diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index 96a7fb12f9..dbac205fe2 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -34,6 +34,7 @@ using namespace isc; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::util; +using namespace isc::data; using namespace std; namespace { @@ -63,6 +64,9 @@ const size_t OPTION_FORMATTED_VALUE_MAX_LEN = 8192; /// @brief Maximum length of option space name. const size_t OPTION_SPACE_MAX_LEN = 128; +/// @brief Maximum length of user context. +const size_t USER_CONTEXT_MAX_LEN = 8192; + /// @brief Maximum length of the server hostname. const size_t SERVER_HOSTNAME_MAX_LEN = 64; @@ -758,7 +762,7 @@ class MySqlHostWithOptionsExchange : public MySqlHostExchange { private: /// @brief Number of columns holding DHCPv4 or DHCPv6 option information. - static const size_t OPTION_COLUMNS = 6; + static const size_t OPTION_COLUMNS = 7; /// @brief Receives DHCPv4 or DHCPv6 options information from the /// dhcp4_options or dhcp6_options tables respectively. @@ -787,19 +791,22 @@ private: const size_t start_column) : universe_(universe), start_column_(start_column), option_id_(0), code_(0), value_length_(0), formatted_value_length_(0), - space_length_(0), persistent_(false), option_id_null_(MLM_FALSE), - code_null_(MLM_FALSE), value_null_(MLM_FALSE), - formatted_value_null_(MLM_FALSE), space_null_(MLM_FALSE), + space_length_(0), persistent_(false), user_context_length_(0), + option_id_null_(MLM_FALSE), code_null_(MLM_FALSE), + value_null_(MLM_FALSE), formatted_value_null_(MLM_FALSE), + space_null_(MLM_FALSE), user_context_null_(MLM_FALSE), option_id_index_(start_column), code_index_(start_column_ + 1), value_index_(start_column_ + 2), formatted_value_index_(start_column_ + 3), space_index_(start_column_ + 4), persistent_index_(start_column_ + 5), + user_context_index_(start_column_ + 6), most_recent_option_id_(0) { memset(value_, 0, sizeof(value_)); memset(formatted_value_, 0, sizeof(formatted_value_)); memset(space_, 0, sizeof(space_)); + memset(user_context_, 0, sizeof(user_context_)); } /// @brief Returns identifier of the currently processed option. @@ -858,6 +865,13 @@ private: formatted_value.assign(formatted_value_); } + // Convert user_context to string as well. + std::string user_context; + if (user_context_null_ == MLM_FALSE) { + user_context_[user_context_length_] = '\0'; + user_context.assign(user_context_); + } + // Options are held in a binary or textual format in the database. // This is similar to having an option specified in a server // configuration file. Such option is converted to appropriate C++ @@ -909,6 +923,22 @@ private: } OptionDescriptor desc(option, persistent_, formatted_value); + + // Set the user context if there is one into the option descriptor. + if (!user_context.empty()) { + try { + ConstElementPtr ctx = Element::fromJSON(user_context); + if (!ctx || (ctx->getType() != Element::map)) { + isc_throw(BadValue, "user context '" << user_context + << "' is no a JSON map"); + } + desc.setContext(ctx); + } catch (const isc::data::JSONError& ex) { + isc_throw(BadValue, "user context '" << user_context + << "' is invalid JSON: " << ex.what()); + } + } + cfg->add(desc, space); } @@ -923,6 +953,7 @@ private: columns[formatted_value_index_] = "formatted_value"; columns[space_index_] = "space"; columns[persistent_index_] = "persistent"; + columns[user_context_index_] = "user_context"; } /// @brief Initialize binding table fields for options. @@ -975,6 +1006,14 @@ private: bind[persistent_index_].buffer_type = MYSQL_TYPE_TINY; bind[persistent_index_].buffer = reinterpret_cast(&persistent_); bind[persistent_index_].is_unsigned = MLM_TRUE; + + // user_context : TEXT NULL + user_context_length_ = sizeof(user_context_); + bind[user_context_index_].buffer_type = MYSQL_TYPE_STRING; + bind[user_context_index_].buffer = reinterpret_cast(user_context_); + bind[user_context_index_].buffer_length = user_context_length_; + bind[user_context_index_].length = &user_context_length_; + bind[user_context_index_].is_null = &user_context_null_; } private: @@ -1013,6 +1052,12 @@ private: /// requested. bool persistent_; + /// @brief Buffer holding textual user context of an option. + char user_context_[USER_CONTEXT_MAX_LEN]; + + /// @brief User context length. + unsigned long user_context_length_; + /// @name Boolean values indicating if values of specific columns in /// the database are NULL. //@{ @@ -1032,6 +1077,8 @@ private: /// @brief Boolean flag indicating if the DHCPv4 option space is NULL. my_bool space_null_; + /// @brief Boolean flag indicating if the DHCPv4 option user context is NULL. + my_bool user_context_null_; //@} /// @name Indexes of the specific columns @@ -1055,6 +1102,9 @@ private: size_t persistent_index_; //@} + /// @brief User context; + size_t user_context_index_; + /// @brief Option id for last processed row. uint32_t most_recent_option_id_; }; @@ -1591,17 +1641,19 @@ class MySqlOptionExchange { private: /// @brief Number of columns in the tables holding options. - static const size_t OPTION_COLUMNS = 9; + static const size_t OPTION_COLUMNS = 10; public: /// @brief Constructor. MySqlOptionExchange() - : type_(0), value_len_(0), formatted_value_len_(0), space_(), space_len_(0), - persistent_(false), client_class_(), client_class_len_(0), + + : type_(0), value_len_(0), formatted_value_len_(0), space_(), + space_len_(0), persistent_(false), user_context_(), + user_context_len_(0), client_class_(), client_class_len_(0), subnet_id_(0), host_id_(0), option_() { - BOOST_STATIC_ASSERT(8 < OPTION_COLUMNS); + BOOST_STATIC_ASSERT(9 < OPTION_COLUMNS); } /// @brief Creates binding array to insert option data into database. @@ -1681,30 +1733,43 @@ public: bind_[5].buffer = reinterpret_cast(&persistent_); bind_[5].is_unsigned = MLM_TRUE; + // user_context: TEST NULL, + ConstElementPtr ctx = opt_desc.getContext(); + if (ctx) { + user_context_ = ctx->str(); + user_context_len_ = user_context_.size(); + bind_[6].buffer_type = MYSQL_TYPE_STRING; + bind_[6].buffer = const_cast(user_context_.c_str()); + bind_[6].buffer_length = user_context_len_; + bind_[6].length = &user_context_len_; + } else { + bind_[6].buffer_type = MYSQL_TYPE_NULL; + } + // dhcp_client_class: VARCHAR(128) NULL /// @todo Assign actual value to client class string. client_class_len_ = client_class_.size(); - bind_[6].buffer_type = MYSQL_TYPE_STRING; - bind_[6].buffer = const_cast(client_class_.c_str()); - bind_[6].buffer_length = client_class_len_; - bind_[6].length = &client_class_len_; + bind_[7].buffer_type = MYSQL_TYPE_STRING; + bind_[7].buffer = const_cast(client_class_.c_str()); + bind_[7].buffer_length = client_class_len_; + bind_[7].length = &client_class_len_; // dhcp4_subnet_id: INT UNSIGNED NULL if (subnet_id.isSpecified()) { subnet_id_ = subnet_id; - bind_[7].buffer_type = MYSQL_TYPE_LONG; - bind_[7].buffer = reinterpret_cast(subnet_id_); - bind_[7].is_unsigned = MLM_TRUE; + bind_[8].buffer_type = MYSQL_TYPE_LONG; + bind_[8].buffer = reinterpret_cast(subnet_id_); + bind_[8].is_unsigned = MLM_TRUE; } else { - bind_[7].buffer_type = MYSQL_TYPE_NULL; + bind_[8].buffer_type = MYSQL_TYPE_NULL; } // host_id: INT UNSIGNED NOT NULL host_id_ = host_id; - bind_[8].buffer_type = MYSQL_TYPE_LONG; - bind_[8].buffer = reinterpret_cast(&host_id_); - bind_[8].is_unsigned = MLM_TRUE; + bind_[9].buffer_type = MYSQL_TYPE_LONG; + bind_[9].buffer = reinterpret_cast(&host_id_); + bind_[9].is_unsigned = MLM_TRUE; } catch (const std::exception& ex) { isc_throw(DbOperationError, @@ -1740,6 +1805,12 @@ private: /// a client or only when requested. bool persistent_; + /// @brief User context. + std::string user_context_; + + /// @brief User context length. + unsigned long user_context_len_; + /// @brief Client classes for the option. std::string client_class_; @@ -1970,9 +2041,9 @@ TaggedStatementArray tagged_statements = { { "h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " - "o4.persistent, " + "o4.persistent, o4.user_context, " "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " - "o6.persistent, " + "o6.persistent, o6.user_context, " "r.reservation_id, r.address, r.prefix_len, r.type, " "r.dhcp6_iaid " "FROM hosts AS h " @@ -1994,7 +2065,7 @@ TaggedStatementArray tagged_statements = { { "h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent " + "o.persistent, o.user_context " "FROM hosts AS h " "LEFT JOIN dhcp4_options AS o " "ON h.host_id = o.host_id " @@ -2010,7 +2081,7 @@ TaggedStatementArray tagged_statements = { { "h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent " + "o.persistent, o.user_context " "FROM hosts AS h " "LEFT JOIN dhcp4_options AS o " "ON h.host_id = o.host_id " @@ -2028,7 +2099,7 @@ TaggedStatementArray tagged_statements = { { "h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent, " + "o.persistent, o.user_context, " "r.reservation_id, r.address, r.prefix_len, r.type, " "r.dhcp6_iaid " "FROM hosts AS h " @@ -2050,7 +2121,7 @@ TaggedStatementArray tagged_statements = { { "h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent " + "o.persistent, o.user_context " "FROM hosts AS h " "LEFT JOIN dhcp4_options AS o " "ON h.host_id = o.host_id " @@ -2070,7 +2141,7 @@ TaggedStatementArray tagged_statements = { { "h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent, " + "o.persistent, o.user_context," "r.reservation_id, r.address, r.prefix_len, r.type, " "r.dhcp6_iaid " "FROM hosts AS h " @@ -2096,7 +2167,7 @@ TaggedStatementArray tagged_statements = { { "h.dhcp4_client_classes, h.dhcp6_client_classes, " "h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent, " + "o.persistent, o.user_context, " "r.reservation_id, r.address, r.prefix_len, r.type, " "r.dhcp6_iaid " "FROM hosts AS h " @@ -2129,15 +2200,15 @@ TaggedStatementArray tagged_statements = { { // Using fixed scope_id = 3, which associates an option with host. {MySqlHostDataSourceImpl::INSERT_V4_OPTION, "INSERT INTO dhcp4_options(option_id, code, value, formatted_value, space, " - "persistent, dhcp_client_class, dhcp4_subnet_id, host_id, scope_id) " - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"}, + "persistent, user_context, dhcp_client_class, dhcp4_subnet_id, host_id, scope_id) " + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"}, // Inserts a single DHCPv6 option into 'dhcp6_options' table. // Using fixed scope_id = 3, which associates an option with host. {MySqlHostDataSourceImpl::INSERT_V6_OPTION, "INSERT INTO dhcp6_options(option_id, code, value, formatted_value, space, " - "persistent, dhcp_client_class, dhcp6_subnet_id, host_id, scope_id) " - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"}, + "persistent, user_context, dhcp_client_class, dhcp6_subnet_id, host_id, scope_id) " + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"}, {MySqlHostDataSourceImpl::DEL_HOST_ADDR4, "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"}, diff --git a/src/lib/dhcpsrv/pgsql_exchange.h b/src/lib/dhcpsrv/pgsql_exchange.h index ea21627913..381b4b1891 100644 --- a/src/lib/dhcpsrv/pgsql_exchange.h +++ b/src/lib/dhcpsrv/pgsql_exchange.h @@ -160,7 +160,7 @@ struct PsqlBindArray { /// @brief Binds a the given string to the bind array. /// - /// Prior to added the The given string the vector of exchange values, + /// Prior to add the given string the vector of exchange values, /// it duplicated as a ConstStringPtr and saved internally. This guarantees /// the string remains in scope until the PsqlBindArray is destroyed, /// without the caller maintaining the string values. diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index ead3b672ce..580f03dd2a 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -31,6 +31,7 @@ using namespace isc; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::util; +using namespace isc::data; using namespace std; namespace { @@ -399,7 +400,7 @@ class PgSqlHostWithOptionsExchange : public PgSqlHostExchange { private: /// @brief Number of columns holding DHCPv4 or DHCPv6 option information. - static const size_t OPTION_COLUMNS = 6; + static const size_t OPTION_COLUMNS = 7; /// @brief Receives DHCPv4 or DHCPv6 options information from the /// dhcp4_options or dhcp6_options tables respectively. @@ -432,6 +433,7 @@ private: formatted_value_index_(start_column_ + 3), space_index_(start_column_ + 4), persistent_index_(start_column_ + 5), + user_context_index_(start_column_ + 6), most_recent_option_id_(0) { } @@ -533,6 +535,13 @@ private: PgSqlExchange::getColumnValue(r, row, persistent_index_, persistent); + // user_context: TEXT + std::string user_context; + if (!isColumnNull(r, row, user_context_index_)) { + PgSqlExchange::getColumnValue(r, row, user_context_index_, + user_context); + } + // Options are held in a binary or textual format in the database. // This is similar to having an option specified in a server // configuration file. Such option is converted to appropriate C++ @@ -588,6 +597,22 @@ private: } OptionDescriptor desc(option, persistent, formatted_value); + + // Set the user context if there is one into the option descriptor. + if (!user_context.empty()) { + try { + ConstElementPtr ctx = Element::fromJSON(user_context); + if (!ctx || (ctx->getType() != Element::map)) { + isc_throw(BadValue, "user context '" << user_context + << "' is no a JSON map"); + } + desc.setContext(ctx); + } catch (const isc::data::JSONError& ex) { + isc_throw(BadValue, "user context '" << user_context + << "' is invalid JSON: " << ex.what()); + } + } + cfg->add(desc, space); } @@ -602,6 +627,7 @@ private: columns[formatted_value_index_] = "formatted_value"; columns[space_index_] = "space"; columns[persistent_index_] = "persistent"; + columns[user_context_index_] = "user_context"; } private: @@ -634,6 +660,9 @@ private: size_t persistent_index_; //@} + /// @brief User context + size_t user_context_index_; + /// @brief Option id for last processed row. uint64_t most_recent_option_id_; }; @@ -1049,13 +1078,14 @@ private: static const int FORMATTED_VALUE_COL = 3; static const int SPACE_COL = 4; static const int PERSISTENT_COL = 5; - static const int DHCP_CLIENT_CLASS_COL = 6; - static const int DHCP_SUBNET_ID_COL = 7; - static const int HOST_ID_COL = 8; - static const int SCOPE_ID_COL = 9; + static const int USER_CONTEXT_COL = 6; + static const int DHCP_CLIENT_CLASS_COL = 7; + static const int DHCP_SUBNET_ID_COL = 8; + static const int HOST_ID_COL = 9; + static const int SCOPE_ID_COL = 10; /// @brief Number of columns in the tables holding options. - static const size_t OPTION_COLUMNS = 10; + static const size_t OPTION_COLUMNS = 11; public: @@ -1069,12 +1099,13 @@ public: columns_[FORMATTED_VALUE_COL] = "formatted_value"; columns_[SPACE_COL] = "space"; columns_[PERSISTENT_COL] = "persistent"; + columns_[USER_CONTEXT_COL] = "user_context"; columns_[DHCP_CLIENT_CLASS_COL] = "dhcp_client_class"; columns_[DHCP_SUBNET_ID_COL] = "dhcp_subnet_id"; columns_[HOST_ID_COL] = "host_id"; columns_[SCOPE_ID_COL] = "scope_id"; - BOOST_STATIC_ASSERT(9 < OPTION_COLUMNS); + BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS); } /// @brief Creates binding array to insert option data into database. @@ -1138,6 +1169,15 @@ public: // persistent: BOOLEAN DEFAULT false bind_array->add(opt_desc.persistent_); + // user_context: TEXT NULL, + ConstElementPtr ctx = opt_desc.getContext(); + if (ctx) { + std::string user_context_ = ctx->str(); + bind_array->addTempString(user_context_); + } else { + bind_array->addNull(); + } + // host_id: INT NULL if (!host_id) { isc_throw(BadValue, "host_id cannot be null"); @@ -1389,9 +1429,9 @@ TaggedStatementArray tagged_statements = { { " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " - " o4.persistent, " + " o4.persistent, o4.user_context, " " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " - " o6.persistent, " + " o6.persistent, o6.user_context, " " 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 " @@ -1411,7 +1451,8 @@ TaggedStatementArray tagged_statements = { { " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " " h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " - " o.option_id, o.code, o.value, o.formatted_value, o.space, o.persistent " + " o.option_id, o.code, o.value, o.formatted_value, o.space, " + " o.persistent, o.user_context " "FROM hosts AS h " "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " "WHERE ipv4_address = $1 " @@ -1429,7 +1470,8 @@ TaggedStatementArray tagged_statements = { { " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " " h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " - " o.option_id, o.code, o.value, o.formatted_value, o.space, o.persistent " + " o.option_id, o.code, o.value, o.formatted_value, o.space, " + " o.persistent, o.user_context " "FROM hosts AS h " "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 " @@ -1450,7 +1492,7 @@ TaggedStatementArray tagged_statements = { { " h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " " o.option_id, o.code, o.value, o.formatted_value, o.space, " - " o.persistent, " + " o.persistent, o.user_context, " " 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 " @@ -1472,7 +1514,8 @@ TaggedStatementArray tagged_statements = { { " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " " h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " - " o.option_id, o.code, o.value, o.formatted_value, o.space, o.persistent " + " o.option_id, o.code, o.value, o.formatted_value, o.space, " + " o.persistent, o.user_context " "FROM hosts AS h " "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 " @@ -1495,7 +1538,7 @@ TaggedStatementArray tagged_statements = { { " h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " " o.option_id, o.code, o.value, o.formatted_value, o.space, " - " o.persistent, " + " o.persistent, o.user_context, " " r.reservation_id, r.address, r.prefix_len, r.type, " " r.dhcp6_iaid " "FROM hosts AS h " @@ -1523,7 +1566,7 @@ TaggedStatementArray tagged_statements = { { " h.dhcp4_client_classes, h.dhcp6_client_classes, " " h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, " " o.option_id, o.code, o.value, o.formatted_value, o.space, " - " o.persistent, " + " o.persistent, o.user_context, " " r.reservation_id, r.address, r.prefix_len, r.type, " " r.dhcp6_iaid " "FROM hosts AS h " @@ -1568,25 +1611,25 @@ TaggedStatementArray tagged_statements = { { // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION // Inserts a single DHCPv4 option into 'dhcp4_options' table. // Using fixed scope_id = 3, which associates an option with host. - {6, + {7, { OID_INT2, OID_BYTEA, OID_TEXT, - OID_VARCHAR, OID_BOOL, OID_INT8}, + OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8}, "insert_v4_host_option", "INSERT INTO dhcp4_options(code, value, formatted_value, space, " - " persistent, host_id, scope_id) " - "VALUES ($1, $2, $3, $4, $5, $6, 3)" + " persistent, user_context, host_id, scope_id) " + "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)" }, // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION // Inserts a single DHCPv6 option into 'dhcp6_options' table. // Using fixed scope_id = 3, which associates an option with host. - {6, + {7, { OID_INT2, OID_BYTEA, OID_TEXT, - OID_VARCHAR, OID_BOOL, OID_INT8}, + OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8}, "insert_v6_host_option", "INSERT INTO dhcp6_options(code, value, formatted_value, space, " - " persistent, host_id, scope_id) " - "VALUES ($1, $2, $3, $4, $5, $6, 3)" + " persistent, user_context, host_id, scope_id) " + "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)" }, // PgSqlHostDataSourceImpl::DEL_HOST_ADDR4 diff --git a/src/share/database/scripts/mysql/dhcpdb_create.mysql b/src/share/database/scripts/mysql/dhcpdb_create.mysql index bb82fc33dd..3259648ea7 100644 --- a/src/share/database/scripts/mysql/dhcpdb_create.mysql +++ b/src/share/database/scripts/mysql/dhcpdb_create.mysql @@ -498,6 +498,9 @@ END $$ DELIMITER ; +# Add user contexts into tables holding DHCP options +ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT NULL; +ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT NULL; # Update the schema version number UPDATE schema_version diff --git a/src/share/database/scripts/mysql/upgrade_5.0_to_5.1.sh.in b/src/share/database/scripts/mysql/upgrade_5.0_to_5.1.sh.in index 14d0ef0139..54f8109250 100644 --- a/src/share/database/scripts/mysql/upgrade_5.0_to_5.1.sh.in +++ b/src/share/database/scripts/mysql/upgrade_5.0_to_5.1.sh.in @@ -35,6 +35,10 @@ END $$ DELIMITER ; +# Add user contexts into tables holding DHCP options +ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT NULL; +ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT NULL; + # Update the schema version number UPDATE schema_version SET version = '5', minor = '1'; diff --git a/src/share/database/scripts/pgsql/dhcpdb_create.pgsql b/src/share/database/scripts/pgsql/dhcpdb_create.pgsql index 3597b73340..51a50616f9 100644 --- a/src/share/database/scripts/pgsql/dhcpdb_create.pgsql +++ b/src/share/database/scripts/pgsql/dhcpdb_create.pgsql @@ -524,6 +524,10 @@ CREATE UNIQUE INDEX key_dhcp6_identifier_subnet_id ON hosts (dhcp_identifier ASC, dhcp_identifier_type ASC, dhcp6_subnet_id ASC) WHERE (dhcp6_subnet_id IS NOT NULL AND dhcp6_subnet_id <> 0); +-- Add a column holding DHCP options for user context. +ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT; +ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT; + -- Set 3.2 schema version. UPDATE schema_version SET version = '3', minor = '2'; diff --git a/src/share/database/scripts/pgsql/upgrade_3.1_to_3.2.sh.in b/src/share/database/scripts/pgsql/upgrade_3.1_to_3.2.sh.in index 3e4c44c66a..78e212ce5c 100644 --- a/src/share/database/scripts/pgsql/upgrade_3.1_to_3.2.sh.in +++ b/src/share/database/scripts/pgsql/upgrade_3.1_to_3.2.sh.in @@ -48,6 +48,10 @@ CREATE UNIQUE INDEX hosts_dhcp6_identifier_subnet_id ON hosts (dhcp_identifier ASC, dhcp_identifier_type ASC, dhcp6_subnet_id ASC) WHERE (dhcp6_subnet_id IS NOT NULL AND dhcp6_subnet_id <> 0); +-- Add a column holding DHCP options for user context. +ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT; +ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT; + -- Set 3.2 schema version. UPDATE schema_version SET version = '3', minor = '2';