"Fossies" - the Fresh Open Source Software Archive

Member "kea-1.6.2/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc" (21 Feb 2020, 169063 Bytes) of package /linux/misc/kea-1.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mysql_cb_dhcp6.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.1_vs_1.6.2.

    1 // Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
    2 //
    3 // This Source Code Form is subject to the terms of the Mozilla Public
    4 // License, v. 2.0. If a copy of the MPL was not distributed with this
    5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
    6 
    7 #include <config.h>
    8 
    9 #include <mysql_cb_dhcp6.h>
   10 #include <mysql_cb_impl.h>
   11 #include <mysql_query_macros_dhcp.h>
   12 #include <asiolink/addr_utilities.h>
   13 #include <cc/data.h>
   14 #include <config_backend/constants.h>
   15 #include <database/db_exceptions.h>
   16 #include <dhcp/classify.h>
   17 #include <dhcp/dhcp6.h>
   18 #include <dhcp/libdhcp++.h>
   19 #include <dhcp/option_data_types.h>
   20 #include <dhcp/option_space.h>
   21 #include <dhcpsrv/config_backend_dhcp6_mgr.h>
   22 #include <dhcpsrv/network.h>
   23 #include <dhcpsrv/pool.h>
   24 #include <dhcpsrv/lease.h>
   25 #include <util/buffer.h>
   26 #include <util/boost_time_utils.h>
   27 #include <mysql/mysql_connection.h>
   28 #include <boost/date_time/posix_time/posix_time.hpp>
   29 #include <boost/lexical_cast.hpp>
   30 #include <boost/pointer_cast.hpp>
   31 #include <boost/scoped_ptr.hpp>
   32 #include <mysql.h>
   33 #include <mysqld_error.h>
   34 #include <array>
   35 #include <sstream>
   36 #include <utility>
   37 #include <vector>
   38 
   39 using namespace isc::cb;
   40 using namespace isc::db;
   41 using namespace isc::data;
   42 using namespace isc::asiolink;
   43 using namespace isc::log;
   44 using namespace isc::util;
   45 
   46 namespace isc {
   47 namespace dhcp {
   48 
   49 /// @brief Implementation of the MySQL Configuration Backend.
   50 class MySqlConfigBackendDHCPv6Impl : public MySqlConfigBackendImpl {
   51 public:
   52 
   53     /// @brief Statement tags.
   54     ///
   55     /// The contents of the enum are indexes into the list of SQL statements.
   56     /// It is assumed that the order is such that the indices of statements
   57     /// reading the database are less than those of statements modifying the
   58     /// database.
   59     enum StatementIndex {
   60         CREATE_AUDIT_REVISION,
   61         GET_GLOBAL_PARAMETER6,
   62         GET_ALL_GLOBAL_PARAMETERS6,
   63         GET_MODIFIED_GLOBAL_PARAMETERS6,
   64         GET_SUBNET6_ID_NO_TAG,
   65         GET_SUBNET6_ID_ANY,
   66         GET_SUBNET6_ID_UNASSIGNED,
   67         GET_SUBNET6_PREFIX_NO_TAG,
   68         GET_SUBNET6_PREFIX_ANY,
   69         GET_SUBNET6_PREFIX_UNASSIGNED,
   70         GET_ALL_SUBNETS6,
   71         GET_ALL_SUBNETS6_UNASSIGNED,
   72         GET_MODIFIED_SUBNETS6,
   73         GET_MODIFIED_SUBNETS6_UNASSIGNED,
   74         GET_SHARED_NETWORK_SUBNETS6,
   75         GET_POOL6_RANGE,
   76         GET_POOL6_RANGE_ANY,
   77         GET_PD_POOL,
   78         GET_PD_POOL_ANY,
   79         GET_SHARED_NETWORK6_NAME_NO_TAG,
   80         GET_SHARED_NETWORK6_NAME_ANY,
   81         GET_SHARED_NETWORK6_NAME_UNASSIGNED,
   82         GET_ALL_SHARED_NETWORKS6,
   83         GET_ALL_SHARED_NETWORKS6_UNASSIGNED,
   84         GET_MODIFIED_SHARED_NETWORKS6,
   85         GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED,
   86         GET_OPTION_DEF6_CODE_SPACE,
   87         GET_ALL_OPTION_DEFS6,
   88         GET_MODIFIED_OPTION_DEFS6,
   89         GET_OPTION6_CODE_SPACE,
   90         GET_ALL_OPTIONS6,
   91         GET_MODIFIED_OPTIONS6,
   92         GET_OPTION6_SUBNET_ID_CODE_SPACE,
   93         GET_OPTION6_POOL_ID_CODE_SPACE,
   94         GET_OPTION6_PD_POOL_ID_CODE_SPACE,
   95         GET_OPTION6_SHARED_NETWORK_CODE_SPACE,
   96         GET_AUDIT_ENTRIES6_TIME,
   97         GET_SERVER6,
   98         GET_ALL_SERVERS6,
   99         INSERT_GLOBAL_PARAMETER6,
  100         INSERT_GLOBAL_PARAMETER6_SERVER,
  101         INSERT_SUBNET6,
  102         INSERT_SUBNET6_SERVER,
  103         INSERT_POOL6,
  104         INSERT_PD_POOL,
  105         INSERT_SHARED_NETWORK6,
  106         INSERT_SHARED_NETWORK6_SERVER,
  107         INSERT_OPTION_DEF6,
  108         INSERT_OPTION_DEF6_SERVER,
  109         INSERT_OPTION6,
  110         INSERT_OPTION6_SERVER,
  111         INSERT_SERVER6,
  112         UPDATE_GLOBAL_PARAMETER6,
  113         UPDATE_SUBNET6,
  114         UPDATE_SHARED_NETWORK6,
  115         UPDATE_OPTION_DEF6,
  116         UPDATE_OPTION6,
  117         UPDATE_OPTION6_SUBNET_ID,
  118         UPDATE_OPTION6_POOL_ID,
  119         UPDATE_OPTION6_PD_POOL_ID,
  120         UPDATE_OPTION6_SHARED_NETWORK,
  121         UPDATE_SERVER6,
  122         DELETE_GLOBAL_PARAMETER6,
  123         DELETE_ALL_GLOBAL_PARAMETERS6,
  124         DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
  125         DELETE_SUBNET6_ID_WITH_TAG,
  126         DELETE_SUBNET6_ID_ANY,
  127         DELETE_SUBNET6_PREFIX_WITH_TAG,
  128         DELETE_SUBNET6_PREFIX_ANY,
  129         DELETE_ALL_SUBNETS6,
  130         DELETE_ALL_SUBNETS6_UNASSIGNED,
  131         DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME,
  132         DELETE_SUBNET6_SERVER,
  133         DELETE_POOLS6,
  134         DELETE_PD_POOLS,
  135         DELETE_SHARED_NETWORK6_NAME_WITH_TAG,
  136         DELETE_SHARED_NETWORK6_NAME_ANY,
  137         DELETE_ALL_SHARED_NETWORKS6,
  138         DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED,
  139         DELETE_SHARED_NETWORK6_SERVER,
  140         DELETE_OPTION_DEF6_CODE_NAME,
  141         DELETE_ALL_OPTION_DEFS6,
  142         DELETE_ALL_OPTION_DEFS6_UNASSIGNED,
  143         DELETE_OPTION6,
  144         DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
  145         DELETE_OPTION6_SUBNET_ID,
  146         DELETE_OPTION6_POOL_RANGE,
  147         DELETE_OPTION6_PD_POOL,
  148         DELETE_OPTION6_SHARED_NETWORK,
  149         DELETE_OPTIONS6_SUBNET_ID,
  150         DELETE_OPTIONS6_SHARED_NETWORK,
  151         DELETE_SERVER6,
  152         DELETE_ALL_SERVERS6,
  153         NUM_STATEMENTS
  154     };
  155 
  156     /// @brief Constructor.
  157     ///
  158     /// @param parameters A data structure relating keywords and values
  159     /// concerned with the database.
  160     explicit MySqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap&
  161                                           parameters);
  162 
  163     /// @brief Sends query to retrieve global parameter.
  164     ///
  165     /// @param server_selector Server selector.
  166     /// @param name Name of the parameter to be retrieved.
  167     ///
  168     /// @return Pointer to the retrieved value or null if such parameter
  169     /// doesn't exist.
  170     StampedValuePtr getGlobalParameter6(const ServerSelector& server_selector,
  171                                         const std::string& name) {
  172         StampedValueCollection parameters;
  173 
  174         auto tags = server_selector.getTags();
  175         for (auto tag : tags) {
  176             MySqlBindingCollection in_bindings = {
  177                 MySqlBinding::createString(tag.get()),
  178                 MySqlBinding::createString(name)
  179             };
  180 
  181             getGlobalParameters(GET_GLOBAL_PARAMETER6, in_bindings, parameters);
  182         }
  183 
  184         return (parameters.empty() ? StampedValuePtr() : *parameters.begin());
  185     }
  186 
  187     /// @brief Sends query to insert or update global parameter.
  188     ///
  189     /// @param server_selector Server selector.
  190     /// @param name Name of the global parameter.
  191     /// @param value Value of the global parameter.
  192     void createUpdateGlobalParameter6(const db::ServerSelector& server_selector,
  193                                       const StampedValuePtr& value) {
  194 
  195         if (server_selector.amUnassigned()) {
  196             isc_throw(NotImplemented, "managing configuration for no particular server"
  197                       " (unassigned) is unsupported at the moment");
  198         }
  199 
  200         auto tag = getServerTag(server_selector, "creating or updating global parameter");
  201 
  202         MySqlBindingCollection in_bindings = {
  203             MySqlBinding::createString(value->getName()),
  204             MySqlBinding::createString(value->getValue()),
  205             MySqlBinding::createInteger<uint8_t>(value->getType()),
  206             MySqlBinding::createTimestamp(value->getModificationTime()),
  207             MySqlBinding::createString(tag),
  208             MySqlBinding::createString(value->getName())
  209         };
  210 
  211         MySqlTransaction transaction(conn_);
  212 
  213         // Create scoped audit revision. As long as this instance exists
  214         // no new audit revisions are created in any subsequent calls.
  215         ScopedAuditRevision
  216             audit_revision(this, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
  217                            server_selector, "global parameter set", false);
  218 
  219         // Try to update the existing row.
  220         if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6,
  221                                     in_bindings) == 0) {
  222 
  223             // No such parameter found, so let's insert it. We have to adjust the
  224             // bindings collection to match the prepared statement for insert.
  225             in_bindings.pop_back();
  226             in_bindings.pop_back();
  227             conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6,
  228                               in_bindings);
  229 
  230             // Successfully inserted global parameter. Now, we have to associate it
  231             // with the server tag.
  232 
  233             // Let's first get the primary key of the global parameter.
  234             uint64_t id = mysql_insert_id(conn_.mysql_);
  235 
  236             // Successfully inserted global parameter. Now, we have to associate it
  237             // with the server tag.
  238             attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER,
  239                                    server_selector,
  240                                    MySqlBinding::createInteger<uint64_t>(id),
  241                                    MySqlBinding::createTimestamp(value->getModificationTime()));
  242         }
  243 
  244         transaction.commit();
  245     }
  246 
  247     /// @brief Sends query to the database to retrieve multiple subnets.
  248     ///
  249     /// Query should order subnets by subnet_id.
  250     ///
  251     /// @param index Index of the query to be used.
  252     /// @param server_selector Server selector.
  253     /// @param in_bindings Input bindings specifying selection criteria. The
  254     /// size of the bindings collection must match the number of placeholders
  255     /// in the prepared statement. The input bindings collection must be empty
  256     /// if the query contains no WHERE clause.
  257     /// @param [out] subnets Reference to the container where fetched subnets
  258     /// will be inserted.
  259     void getSubnets6(const StatementIndex& index,
  260                      const ServerSelector& server_selector,
  261                      const MySqlBindingCollection& in_bindings,
  262                      Subnet6Collection& subnets) {
  263         // Create output bindings. The order must match that in the prepared
  264         // statement.
  265         MySqlBindingCollection out_bindings = {
  266             MySqlBinding::createInteger<uint32_t>(), // subnet_id
  267             MySqlBinding::createString(SUBNET6_PREFIX_BUF_LENGTH), // subnet_prefix
  268             MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // client_class
  269             MySqlBinding::createString(INTERFACE_BUF_LENGTH), // interface
  270             MySqlBinding::createTimestamp(), // modification_ts
  271             MySqlBinding::createInteger<uint32_t>(), // preferred_lifetime
  272             MySqlBinding::createInteger<uint8_t>(), // rapid_commit
  273             MySqlBinding::createInteger<uint32_t>(), // rebind_timer
  274             MySqlBinding::createString(RELAY_BUF_LENGTH), // relay
  275             MySqlBinding::createInteger<uint32_t>(), // renew_timer
  276             MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes
  277             MySqlBinding::createInteger<uint8_t>(), // reservation_mode
  278             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // shared_network_name
  279             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context
  280             MySqlBinding::createInteger<uint32_t>(), // valid_lifetime
  281             MySqlBinding::createInteger<uint64_t>(), // pool: id
  282             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: start_address
  283             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: end_address
  284             MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id
  285             MySqlBinding::createTimestamp(), // pool: modification_ts
  286             MySqlBinding::createInteger<uint64_t>(), // pd pool: id
  287             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: prefix
  288             MySqlBinding::createInteger<uint8_t>(), // pd pool: prefix_length
  289             MySqlBinding::createInteger<uint8_t>(), // pd pool: delegated_prefix_length
  290             MySqlBinding::createInteger<uint32_t>(), // pd pool: subnet_id
  291             MySqlBinding::createTimestamp(), // pd pool: modification_ts
  292             MySqlBinding::createInteger<uint64_t>(), // pool option: option_id
  293             MySqlBinding::createInteger<uint16_t>(), // pool option: code
  294             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pool option: value
  295             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value
  296             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space
  297             MySqlBinding::createInteger<uint8_t>(), // pool option: persistent
  298             MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp6_subnet_id
  299             MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id
  300             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context
  301             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name
  302             MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id
  303             MySqlBinding::createTimestamp(), // pool option: modification_ts
  304             MySqlBinding::createInteger<uint64_t>(), // pool option: pd_pool_id
  305             MySqlBinding::createInteger<uint64_t>(), // pd pool option: option_id
  306             MySqlBinding::createInteger<uint16_t>(), // pd pool option: code
  307             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pd pool option: value
  308             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pd pool option: formatted_value
  309             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pd pool option: space
  310             MySqlBinding::createInteger<uint8_t>(), // pd pool option: persistent
  311             MySqlBinding::createInteger<uint32_t>(), // pd pool option: dhcp6_subnet_id
  312             MySqlBinding::createInteger<uint8_t>(), // pd pool option: scope_id
  313             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool option: user_context
  314             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pd pool option: shared_network_name
  315             MySqlBinding::createInteger<uint64_t>(), // pd pool option: pool_id
  316             MySqlBinding::createTimestamp(), // pd pool option: modification_ts
  317             MySqlBinding::createInteger<uint64_t>(), // pd pool option: pd_pool_id
  318             MySqlBinding::createInteger<uint64_t>(), // option: option_id
  319             MySqlBinding::createInteger<uint16_t>(), // option: code
  320             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value
  321             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
  322             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
  323             MySqlBinding::createInteger<uint8_t>(), // option: persistent
  324             MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id
  325             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
  326             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
  327             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
  328             MySqlBinding::createInteger<uint64_t>(), // option: pool_id
  329             MySqlBinding::createTimestamp(), // option: modification_ts
  330             MySqlBinding::createInteger<uint64_t>(), // option: pd_pool_id
  331             MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times
  332             MySqlBinding::createInteger<float>(), // t1_percent
  333             MySqlBinding::createInteger<float>(), // t2_percent
  334             MySqlBinding::createBlob(INTERFACE_ID_BUF_LENGTH), // interface_id
  335             MySqlBinding::createInteger<uint32_t>(), // min_preferred_lifetime
  336             MySqlBinding::createInteger<uint32_t>(), // max_preferred_lifetime
  337             MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime
  338             MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime
  339             MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class
  340             MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes
  341             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context
  342             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: excluded_prefix
  343             MySqlBinding::createInteger<uint8_t>(), // pd pool: excluded_prefix_length
  344             MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pd pool: client_class
  345             MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pd pool: require_client_classes
  346             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool: user_context
  347             MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag
  348         };
  349 
  350         uint64_t last_pool_id = 0;
  351         uint64_t last_pd_pool_id = 0;
  352         uint64_t last_pool_option_id = 0;
  353         uint64_t last_pd_pool_option_id = 0;
  354         uint64_t last_option_id = 0;
  355         Pool6Ptr last_pool;
  356         Pool6Ptr last_pd_pool;
  357         std::string last_tag;
  358 
  359         // Execute actual query.
  360         conn_.selectQuery(index, in_bindings, out_bindings,
  361                           [this, &subnets, &last_pool,  &last_pd_pool,
  362                            &last_pool_id, &last_pd_pool_id,
  363                            &last_pool_option_id, &last_pd_pool_option_id,
  364                            &last_option_id, &last_tag]
  365                           (MySqlBindingCollection& out_bindings) {
  366             // Get pointer to the last subnet in the collection.
  367             Subnet6Ptr last_subnet;
  368             if (!subnets.empty()) {
  369                 last_subnet = *subnets.rbegin();
  370             }
  371 
  372             // Subnet has been returned. Assuming that subnets are ordered by
  373             // subnet identifier, if the subnet identifier of the current row
  374             // is different than the subnet identifier of the previously returned
  375             // row, it means that we have to construct new subnet object.
  376             if (!last_subnet || (last_subnet->getID() != out_bindings[0]->getInteger<uint32_t>())) {
  377 
  378                 // Reset per subnet component tracking and server tag because
  379                 // we're now starting to process a new subnet.
  380                 last_pool_id = 0;
  381                 last_pd_pool_id = 0;
  382                 last_pool_option_id = 0;
  383                 last_pd_pool_option_id = 0;
  384                 last_option_id = 0;
  385                 last_pool.reset();
  386                 last_pd_pool.reset();
  387                 last_tag.clear();
  388 
  389                 // subnet_id (0)
  390                 SubnetID subnet_id(out_bindings[0]->getInteger<uint32_t>());
  391 
  392                 // subnet_prefix (1)
  393                 std::string subnet_prefix = out_bindings[1]->getString();
  394                 auto prefix_pair = Subnet6::parsePrefix(subnet_prefix);
  395 
  396                 // preferred_lifetime (and {min,max)_preferred_lifetime)
  397                 auto preferred_lifetime = createTriplet(out_bindings[5],
  398                                                         out_bindings[69],
  399                                                         out_bindings[70]);
  400 
  401                 // renew_timer (9)
  402                 auto renew_timer = createTriplet(out_bindings[9]);
  403 
  404                 // rebind_timer (7)
  405                 auto rebind_timer = createTriplet(out_bindings[7]);
  406 
  407                 // valid_lifetime  (and {min,max)_valid_lifetime)
  408                 auto valid_lifetime = createTriplet(out_bindings[14],
  409                                                     out_bindings[71],
  410                                                     out_bindings[72]);
  411 
  412                 // Create subnet with basic settings.
  413                 last_subnet = Subnet6::create(prefix_pair.first, prefix_pair.second,
  414                                               renew_timer, rebind_timer,
  415                                               preferred_lifetime,
  416                                               valid_lifetime, subnet_id);
  417 
  418                 // client_class (2)
  419                 if (!out_bindings[2]->amNull()) {
  420                     last_subnet->allowClientClass(out_bindings[2]->getString());
  421                 }
  422 
  423                 // interface (3)
  424                 if (!out_bindings[3]->amNull()) {
  425                     last_subnet->setIface(out_bindings[3]->getString());
  426                 }
  427 
  428                 // modification_ts (4)
  429                 last_subnet->setModificationTime(out_bindings[4]->getTimestamp());
  430                 // 5 is preferred_lifetime
  431 
  432                 // rapid_commit (6)
  433                 if (!out_bindings[6]->amNull()) {
  434                     last_subnet->setRapidCommit(out_bindings[6]->getBool());
  435                 }
  436 
  437                 // 7 is rebind_timer
  438 
  439                 // relay (8)
  440                 ElementPtr relay_element = out_bindings[8]->getJSON();
  441                 if (relay_element) {
  442                     if (relay_element->getType() != Element::list) {
  443                         isc_throw(BadValue, "invalid relay value "
  444                                   << out_bindings[8]->getString());
  445                     }
  446                     for (auto i = 0; i < relay_element->size(); ++i) {
  447                         auto relay_address_element = relay_element->get(i);
  448                         if (relay_address_element->getType() != Element::string) {
  449                             isc_throw(BadValue, "relay address must be a string");
  450                         }
  451                         last_subnet->addRelayAddress(IOAddress(relay_element->get(i)->stringValue()));
  452                     }
  453                 }
  454 
  455                 // 9 is renew_timer
  456 
  457                 // require_client_classes (10)
  458                 ElementPtr require_element = out_bindings[10]->getJSON();
  459                 if (require_element) {
  460                     if (require_element->getType() != Element::list) {
  461                         isc_throw(BadValue, "invalid require_client_classes value "
  462                                   << out_bindings[10]->getString());
  463                     }
  464                     for (auto i = 0; i < require_element->size(); ++i) {
  465                         auto require_item = require_element->get(i);
  466                         if (require_item->getType() != Element::string) {
  467                             isc_throw(BadValue, "elements of require_client_classes list must"
  468                                       "be valid strings");
  469                         }
  470                         last_subnet->requireClientClass(require_item->stringValue());
  471                     }
  472                 }
  473 
  474                 // reservation_mode (11)
  475                 if (!out_bindings[11]->amNull()) {
  476                     last_subnet->setHostReservationMode(static_cast<Subnet4::HRMode>
  477                         (out_bindings[11]->getInteger<uint8_t>()));
  478                 }
  479 
  480                 // shared_network_name (12)
  481                 if (!out_bindings[12]->amNull()) {
  482                     last_subnet->setSharedNetworkName(out_bindings[12]->getString());
  483                 }
  484 
  485                 // user_context (13)
  486                 ElementPtr user_context = out_bindings[13]->getJSON();
  487                 if (user_context) {
  488                     last_subnet->setContext(user_context);
  489                 }
  490 
  491                 // 14 is valid_lifetime
  492 
  493                 // calculate_tee_times (65)
  494                 if (!out_bindings[65]->amNull()) {
  495                     last_subnet->setCalculateTeeTimes(out_bindings[65]->getBool());
  496                 }
  497 
  498                 // t1_percent (66)
  499                 if (!out_bindings[66]->amNull()) {
  500                     last_subnet->setT1Percent(out_bindings[66]->getFloat());
  501                 }
  502 
  503                 // t2_percent (67)
  504                 if (!out_bindings[67]->amNull()) {
  505                     last_subnet->setT2Percent(out_bindings[67]->getFloat());
  506                 }
  507 
  508                 // interface_id (68)
  509                 if (!out_bindings[68]->amNull()) {
  510                     auto iface_id_data = out_bindings[68]->getBlob();
  511                     if (!iface_id_data.empty()) {
  512                         OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID,
  513                                                           iface_id_data));
  514                         last_subnet->setInterfaceId(opt_iface_id);
  515                     }
  516                 }
  517 
  518                 // 69 and 70 are {min,max}_preferred_lifetime
  519 
  520                 // 71 and 72 are {min,max}_valid_lifetime
  521 
  522                 // 73 is pool client_class
  523                 // 74 is pool require_client_classes
  524                 // 75 is pool user_context
  525                 // 76 is pd pool excluded_prefix
  526                 // 77 is pd pool excluded_prefix_length
  527                 // 78 is pd pool client_class
  528                 // 79 is pd pool require_client_classes
  529                 // 80 is pd pool user_context
  530 
  531                 // server_tag (81 / last)
  532 
  533                 // Subnet ready. Add it to the list.
  534                 auto ret = subnets.push_back(last_subnet);
  535 
  536                 // subnets is a multi index container with unique indexes
  537                 // but these indexes are unique too in the database,
  538                 // so this is for sanity only.
  539                 if (!ret.second) {
  540                     isc_throw(Unexpected, "add subnet failed");
  541                 }
  542             }
  543 
  544             // Check for new server tags.
  545             if (!out_bindings[81]->amNull() &&
  546                 (last_tag != out_bindings[81]->getString())) {
  547                 last_tag = out_bindings[81]->getString();
  548                 if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) {
  549                     last_subnet->setServerTag(last_tag);
  550                 }
  551             }
  552 
  553             // Pool is between 15 and 19 with extra between 73 and 75
  554 
  555             // If the row contains information about the pool and it
  556             // appears to be new pool entry (checked by comparing pool
  557             // id), let's create the new pool and add it to the
  558             // subnet.
  559             if (!out_bindings[15]->amNull() &&
  560                 !out_bindings[16]->getString().empty() &&
  561                 !out_bindings[17]->getString().empty() &&
  562                 (out_bindings[15]->getInteger<uint64_t>() > last_pool_id)) {
  563                 last_pool_id = out_bindings[15]->getInteger<uint64_t>();
  564                 last_pool = Pool6::create(Lease::TYPE_NA,
  565                                           IOAddress(out_bindings[16]->getString()),
  566                                           IOAddress(out_bindings[17]->getString()));
  567                 // pool client_class (73)
  568                 if (!out_bindings[73]->amNull()) {
  569                     last_pool->allowClientClass(out_bindings[73]->getString());
  570                 }
  571 
  572                 // pool require_client_classes (74)
  573                 ElementPtr require_element = out_bindings[74]->getJSON();
  574                 if (require_element) {
  575                     if (require_element->getType() != Element::list) {
  576                         isc_throw(BadValue, "invalid pool require_client_classes value "
  577                                   << out_bindings[74]->getString());
  578                     }
  579                     for (auto i = 0; i < require_element->size(); ++i) {
  580                         auto require_item = require_element->get(i);
  581                         if (require_item->getType() != Element::string) {
  582                             isc_throw(BadValue, "elements of pool require_client_classes list must"
  583                                       "be valid strings");
  584                         }
  585                         last_pool->requireClientClass(require_item->stringValue());
  586                     }
  587                 }
  588 
  589                 // pool user_context (75)
  590                 ElementPtr user_context = out_bindings[75]->getJSON();
  591                 if (user_context) {
  592                     last_pool->setContext(user_context);
  593                 }
  594 
  595                 last_subnet->addPool(last_pool);
  596             }
  597 
  598             // Pd Pool is between 20 and 25 with extra between 76 and 80
  599 
  600             // If the row contains information about the pd pool and
  601             // it appears to be new pd pool entry (checked by
  602             // comparing pd pool id), let's create the new pd pool and
  603             // add it to the subnet.
  604             if (!out_bindings[20]->amNull() &&
  605                 !out_bindings[21]->getString().empty() &&
  606                 (out_bindings[22]->getInteger<uint8_t>() != 0) &&
  607                 (out_bindings[23]->getInteger<uint8_t>() != 0) &&
  608                 (out_bindings[20]->getInteger<uint64_t>() > last_pd_pool_id)) {
  609                 last_pd_pool_id = out_bindings[20]->getInteger<uint64_t>();
  610 
  611                 // excluded_prefix (76) and excluded_prefix_length (77)
  612                 IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
  613                 if (!out_bindings[76]->amNull()) {
  614                     excluded_prefix = IOAddress(out_bindings[76]->getString());
  615                 }
  616                 last_pd_pool = Pool6::create(IOAddress(out_bindings[21]->getString()),
  617                                              out_bindings[22]->getInteger<uint8_t>(),
  618                                              out_bindings[23]->getInteger<uint8_t>(),
  619                                              excluded_prefix,
  620                                              out_bindings[77]->getInteger<uint8_t>());
  621                 // pd pool client_class (78)
  622                 if (!out_bindings[78]->amNull()) {
  623                     last_pd_pool->allowClientClass(out_bindings[78]->getString());
  624                 }
  625 
  626                 // pd pool require_client_classes (79)
  627                 ElementPtr require_element = out_bindings[79]->getJSON();
  628                 if (require_element) {
  629                     if (require_element->getType() != Element::list) {
  630                         isc_throw(BadValue, "invalid pd pool require_client_classes value "
  631                                   << out_bindings[79]->getString());
  632                     }
  633                     for (auto i = 0; i < require_element->size(); ++i) {
  634                         auto require_item = require_element->get(i);
  635                         if (require_item->getType() != Element::string) {
  636                             isc_throw(BadValue, "elements of pd pool require_client_classes list must"
  637                                       "be valid strings");
  638                         }
  639                         last_pd_pool->requireClientClass(require_item->stringValue());
  640                     }
  641                 }
  642 
  643                 // pd pool user_context (80)
  644                 ElementPtr user_context = out_bindings[80]->getJSON();
  645                 if (user_context) {
  646                     last_pd_pool->setContext(user_context);
  647                 }
  648 
  649                 last_subnet->addPool(last_pd_pool);
  650             }
  651 
  652             // Parse pool specific option between 26 and 38
  653             if (last_pool && !out_bindings[26]->amNull() &&
  654                 (last_pool_option_id < out_bindings[26]->getInteger<uint64_t>())) {
  655                 last_pool_option_id = out_bindings[26]->getInteger<uint64_t>();
  656 
  657                 OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 26);
  658                 if (desc) {
  659                     last_pool->getCfgOption()->add(*desc, desc->space_name_);
  660                 }
  661             }
  662 
  663             // Parse pd pool specific option between 39 and 51
  664             if (last_pd_pool && !out_bindings[39]->amNull() &&
  665                 (last_pd_pool_option_id < out_bindings[39]->getInteger<uint64_t>())) {
  666                 last_pd_pool_option_id = out_bindings[39]->getInteger<uint64_t>();
  667 
  668                 OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 39);
  669                 if (desc) {
  670                     last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
  671                 }
  672             }
  673 
  674             // Parse subnet specific option between 52 and 64
  675             if (!out_bindings[52]->amNull() &&
  676                 (last_option_id < out_bindings[52]->getInteger<uint64_t>())) {
  677                 last_option_id = out_bindings[52]->getInteger<uint64_t>();
  678 
  679                 OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 52);
  680                 if (desc) {
  681                     last_subnet->getCfgOption()->add(*desc, desc->space_name_);
  682                 }
  683             }
  684         });
  685 
  686         // Now that we're done fetching the whole subnet, we have to
  687         // check if it has matching server tags and toss it if it
  688         // doesn't. We skip matching the server tags if we're asking
  689         // for ANY subnet.
  690         auto& subnet_index = subnets.get<SubnetRandomAccessIndexTag>();
  691         tossNonMatchingElements(server_selector, subnet_index);
  692     }
  693 
  694     /// @brief Sends query to retrieve single subnet by id.
  695     ///
  696     /// @param server_selector Server selector.
  697     /// @param subnet_id Subnet identifier.
  698     ///
  699     /// @return Pointer to the returned subnet or NULL if such subnet
  700     /// doesn't exist.
  701     Subnet6Ptr getSubnet6(const ServerSelector& server_selector,
  702                           const SubnetID& subnet_id) {
  703         if (server_selector.hasMultipleTags()) {
  704             isc_throw(InvalidOperation, "expected one server tag to be specified"
  705                       " while fetching a subnet. Got: "
  706                       << getServerTagsAsText(server_selector));
  707         }
  708 
  709         MySqlBindingCollection in_bindings = { MySqlBinding::createInteger<uint32_t>(subnet_id) };
  710 
  711         auto index = GET_SUBNET6_ID_NO_TAG;
  712 
  713         if (server_selector.amUnassigned()) {
  714             index = GET_SUBNET6_ID_UNASSIGNED;
  715 
  716         } else if (server_selector.amAny()) {
  717             index = GET_SUBNET6_ID_ANY;
  718         }
  719 
  720         Subnet6Collection subnets;
  721         getSubnets6(index, server_selector, in_bindings, subnets);
  722 
  723         return (subnets.empty() ? Subnet6Ptr() : *subnets.begin());
  724     }
  725 
  726     /// @brief Sends query to retrieve single subnet by prefix.
  727     ///
  728     /// The prefix should be in the following format: "2001:db8:1::/64".
  729     ///
  730     /// @param server_selector Server selector.
  731     /// @param subnet_id Subnet identifier.
  732     ///
  733     /// @return Pointer to the returned subnet or NULL if such subnet
  734     /// doesn't exist.
  735     Subnet6Ptr getSubnet6(const ServerSelector& server_selector,
  736                           const std::string& subnet_prefix) {
  737         if (server_selector.hasMultipleTags()) {
  738             isc_throw(InvalidOperation, "expected one server tag to be specified"
  739                       " while fetching a subnet. Got: "
  740                       << getServerTagsAsText(server_selector));
  741         }
  742 
  743         MySqlBindingCollection in_bindings = { MySqlBinding::createString(subnet_prefix) };
  744 
  745         auto index = GET_SUBNET6_PREFIX_NO_TAG;
  746 
  747         if (server_selector.amUnassigned()) {
  748             index = GET_SUBNET6_PREFIX_UNASSIGNED;
  749 
  750         } else if (server_selector.amAny()) {
  751             index = GET_SUBNET6_PREFIX_ANY;
  752         }
  753 
  754         Subnet6Collection subnets;
  755         getSubnets6(index, server_selector, in_bindings, subnets);
  756 
  757         return (subnets.empty() ? Subnet6Ptr() : *subnets.begin());
  758     }
  759 
  760     /// @brief Sends query to retrieve all subnets.
  761     ///
  762     /// @param server_selector Server selector.
  763     /// @param [out] subnets Reference to the subnet collection structure where
  764     /// subnets should be inserted.
  765     void getAllSubnets6(const ServerSelector& server_selector,
  766                         Subnet6Collection& subnets) {
  767         if (server_selector.amAny()) {
  768             isc_throw(InvalidOperation, "fetching all subnets for ANY "
  769                       "server is not supported");
  770         }
  771         auto index = (server_selector.amUnassigned() ? GET_ALL_SUBNETS6_UNASSIGNED :
  772                       GET_ALL_SUBNETS6);
  773         MySqlBindingCollection in_bindings;
  774         getSubnets6(index, server_selector, in_bindings, subnets);
  775     }
  776 
  777     /// @brief Sends query to retrieve modified subnets.
  778     ///
  779     /// @param server_selector Server selector.
  780     /// @param modification_ts Lower bound modification timestamp.
  781     /// @param [out] subnets Reference to the subnet collection structure where
  782     /// subnets should be inserted.
  783     void getModifiedSubnets6(const ServerSelector& server_selector,
  784                              const boost::posix_time::ptime& modification_ts,
  785                              Subnet6Collection& subnets) {
  786         if (server_selector.amAny()) {
  787             isc_throw(InvalidOperation, "fetching modified subnets for ANY "
  788                       "server is not supported");
  789         }
  790 
  791         MySqlBindingCollection in_bindings = {
  792             MySqlBinding::createTimestamp(modification_ts)
  793         };
  794 
  795         auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SUBNETS6_UNASSIGNED :
  796                       GET_MODIFIED_SUBNETS6);
  797         getSubnets6(index, server_selector, in_bindings, subnets);
  798     }
  799 
  800     /// @brief Sends query to retrieve all subnets belonging to a shared network.
  801     ///
  802     /// @param server_selector Server selector.
  803     /// @param shared_network_name Name of the shared network for which the
  804     /// subnets should be retrieved.
  805     /// @param [out] subnets Reference to the subnet collection structure where
  806     /// subnets should be inserted.
  807     void getSharedNetworkSubnets6(const ServerSelector& server_selector,
  808                                   const std::string& shared_network_name,
  809                                   Subnet6Collection& subnets) {
  810         MySqlBindingCollection in_bindings = { MySqlBinding::createString(shared_network_name) };
  811         getSubnets6(GET_SHARED_NETWORK_SUBNETS6, server_selector, in_bindings, subnets);
  812     }
  813 
  814     /// @brief Sends query to retrieve multiple pools.
  815     ///
  816     /// Query should order pools by id.
  817     ///
  818     /// @param index Index of the query to be used.
  819     /// @param in_bindings Input bindings specifying selection criteria. The
  820     /// size of the bindings collection must match the number of placeholders
  821     /// in the prepared statement. The input bindings collection must be empty
  822     /// if the query contains no WHERE clause.
  823     /// @param [out] pools Reference to the container where fetched pools
  824     /// will be inserted.
  825     /// @param [out] pool_ids Identifiers of the pools returned in @c pools
  826     /// argument.
  827     void getPools(const StatementIndex& index,
  828                   const MySqlBindingCollection& in_bindings,
  829                   PoolCollection& pools,
  830                   std::vector<uint64_t>& pool_ids) {
  831         MySqlBindingCollection out_bindings = {
  832             MySqlBinding::createInteger<uint64_t>(), // pool: id
  833             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: start_address
  834             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: end_address
  835             MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id
  836             MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class
  837             MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes
  838             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context
  839             MySqlBinding::createTimestamp(), // pool: modification_ts
  840             MySqlBinding::createInteger<uint64_t>(), // pool option: option_id
  841             MySqlBinding::createInteger<uint16_t>(), // pool option: code
  842             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pool option: value
  843             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pool option: formatted_value
  844             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pool option: space
  845             MySqlBinding::createInteger<uint8_t>(), // pool option: persistent
  846             MySqlBinding::createInteger<uint32_t>(), // pool option: dhcp6_subnet_id
  847             MySqlBinding::createInteger<uint8_t>(), // pool option: scope_id
  848             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool option: user_context
  849             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pool option: shared_network_name
  850             MySqlBinding::createInteger<uint64_t>(), // pool option: pool_id
  851             MySqlBinding::createTimestamp(), //pool option: modification_ts
  852             MySqlBinding::createInteger<uint64_t>(), // pool option: pd_pool_id
  853         };
  854 
  855         uint64_t last_pool_id = 0;
  856         uint64_t last_pool_option_id = 0;
  857         Pool6Ptr last_pool;
  858 
  859         conn_.selectQuery(index, in_bindings, out_bindings,
  860                           [this, &last_pool_id, &last_pool_option_id, &last_pool,
  861                            &pools, &pool_ids]
  862                           (MySqlBindingCollection& out_bindings) {
  863             if (out_bindings[0]->getInteger<uint64_t>() > last_pool_id) {
  864 
  865                 last_pool_id = out_bindings[0]->getInteger<uint64_t>();
  866 
  867                 last_pool = Pool6::create(Lease::TYPE_NA,
  868                                           IOAddress(out_bindings[1]->getString()),
  869                                           IOAddress(out_bindings[2]->getString()));
  870                 // pool client_class (4)
  871                 if (!out_bindings[4]->amNull()) {
  872                     last_pool->allowClientClass(out_bindings[4]->getString());
  873                 }
  874 
  875                 // pool require_client_classes (5)
  876                 ElementPtr require_element = out_bindings[5]->getJSON();
  877                 if (require_element) {
  878                     if (require_element->getType() != Element::list) {
  879                         isc_throw(BadValue, "invalid pool require_client_classes value "
  880                                   << out_bindings[5]->getString());
  881                     }
  882                     for (auto i = 0; i < require_element->size(); ++i) {
  883                         auto require_item = require_element->get(i);
  884                         if (require_item->getType() != Element::string) {
  885                             isc_throw(BadValue, "elements of pool require_client_classes list must"
  886                                       "be valid strings");
  887                         }
  888                         last_pool->requireClientClass(require_item->stringValue());
  889                     }
  890                 }
  891 
  892                 // pool user_context (6)
  893                 ElementPtr user_context = out_bindings[6]->getJSON();
  894                 if (user_context) {
  895                     last_pool->setContext(user_context);
  896                 }
  897 
  898                 // pool: modification_ts (7)
  899 
  900                 pools.push_back(last_pool);
  901                 pool_ids.push_back(last_pool_id);
  902             }
  903 
  904             // Parse pool specific option (8).
  905             if (last_pool && !out_bindings[8]->amNull() &&
  906                 (last_pool_option_id < out_bindings[8]->getInteger<uint64_t>())) {
  907                 last_pool_option_id = out_bindings[8]->getInteger<uint64_t>();
  908 
  909                 OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 8);
  910                 if (desc) {
  911                     last_pool->getCfgOption()->add(*desc, desc->space_name_);
  912                 }
  913             }
  914         });
  915     }
  916 
  917     /// @brief Sends query to retrieve multiple pd pools.
  918     ///
  919     /// Query should order pd pools by id.
  920     ///
  921     /// @param index Index of the query to be used.
  922     /// @param in_bindings Input bindings specifying selection criteria. The
  923     /// size of the bindings collection must match the number of placeholders
  924     /// in the prepared statement. The input bindings collection must be empty
  925     /// if the query contains no WHERE clause.
  926     /// @param [out] pd_pools Reference to the container where fetched pools
  927     /// will be inserted.
  928     /// @param [out] pd_pool_ids Identifiers of the pd pools returned in
  929     /// @c pd_pools argument.
  930     void getPdPools(const StatementIndex& index,
  931                     const MySqlBindingCollection& in_bindings,
  932                     PoolCollection& pd_pools,
  933                     std::vector<uint64_t>& pd_pool_ids) {
  934         MySqlBindingCollection out_bindings = {
  935             MySqlBinding::createInteger<uint64_t>(), // pd pool: id
  936             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: prefix
  937             MySqlBinding::createInteger<uint8_t>(), // pd pool: prefix_length
  938             MySqlBinding::createInteger<uint8_t>(), // pd pool: delegated_prefix_length
  939             MySqlBinding::createInteger<uint32_t>(), // pd pool: subnet_id
  940             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: excluded_prefix
  941             MySqlBinding::createInteger<uint8_t>(), // pd pool: excluded_prefix_length
  942             MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pd pool: client_class
  943             MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pd pool: require_client_classes
  944             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool: user_context
  945             MySqlBinding::createTimestamp(), // pd pool: modification_ts
  946             MySqlBinding::createInteger<uint64_t>(), // pd pool option: option_id
  947             MySqlBinding::createInteger<uint16_t>(), // pd pool option: code
  948             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // pd pool option: value
  949             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // pd pool option: formatted_value
  950             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // pd pool option: space
  951             MySqlBinding::createInteger<uint8_t>(), // pd pool option: persistent
  952             MySqlBinding::createInteger<uint32_t>(), // pd pool option: dhcp6_subnet_id
  953             MySqlBinding::createInteger<uint8_t>(), // pd pool option: scope_id
  954             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool option: user_context
  955             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // pd pool option: shared_network_name
  956             MySqlBinding::createInteger<uint64_t>(), // pd pool option: pool_id
  957             MySqlBinding::createTimestamp(), // pd pool option: modification_ts
  958             MySqlBinding::createInteger<uint64_t>() // pd pool option: pd_pool_id
  959         };
  960 
  961         uint64_t last_pd_pool_id = 0;
  962         uint64_t last_pd_pool_option_id = 0;
  963         Pool6Ptr last_pd_pool;
  964 
  965         conn_.selectQuery(index, in_bindings, out_bindings,
  966                           [this, &last_pd_pool_id, &last_pd_pool_option_id,
  967                            &last_pd_pool, &pd_pools, &pd_pool_ids]
  968                           (MySqlBindingCollection& out_bindings) {
  969             if (out_bindings[0]->getInteger<uint64_t>() > last_pd_pool_id) {
  970 
  971                 last_pd_pool_id = out_bindings[0]->getInteger<uint64_t>();
  972 
  973                 // excluded_prefix (5) and excluded_prefix_length (6)
  974                 IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
  975                 if (!out_bindings[5]->amNull()) {
  976                     excluded_prefix = IOAddress(out_bindings[5]->getString());
  977                 }
  978 
  979                 last_pd_pool = Pool6::create(IOAddress(out_bindings[1]->getString()),
  980                                              out_bindings[2]->getInteger<uint8_t>(),
  981                                              out_bindings[3]->getInteger<uint8_t>(),
  982                                              excluded_prefix,
  983                                              out_bindings[6]->getInteger<uint8_t>());
  984 
  985                 // pd pool client_class (7)
  986                 if (!out_bindings[7]->amNull()) {
  987                     last_pd_pool->allowClientClass(out_bindings[7]->getString());
  988                 }
  989 
  990                 // pd pool require_client_classes (8)
  991                 ElementPtr require_element = out_bindings[8]->getJSON();
  992                 if (require_element) {
  993                     if (require_element->getType() != Element::list) {
  994                         isc_throw(BadValue, "invalid pd pool require_client_classes value "
  995                                   << out_bindings[8]->getString());
  996                     }
  997                     for (auto i = 0; i < require_element->size(); ++i) {
  998                         auto require_item = require_element->get(i);
  999                         if (require_item->getType() != Element::string) {
 1000                             isc_throw(BadValue, "elements of pd pool require_client_classes list must"
 1001                                       "be valid strings");
 1002                         }
 1003                         last_pd_pool->requireClientClass(require_item->stringValue());
 1004                     }
 1005                 }
 1006 
 1007                 // pd pool user_context (9)
 1008                 ElementPtr user_context = out_bindings[9]->getJSON();
 1009                 if (user_context) {
 1010                     last_pd_pool->setContext(user_context);
 1011                 }
 1012 
 1013                 // pd pool modification_ts (10)
 1014 
 1015                 pd_pools.push_back(last_pd_pool);
 1016                 pd_pool_ids.push_back(last_pd_pool_id);
 1017             }
 1018 
 1019             // Parse pd pool specific option between 11 and 24
 1020             if (last_pd_pool && !out_bindings[11]->amNull() &&
 1021                 (last_pd_pool_option_id < out_bindings[11]->getInteger<uint64_t>())) {
 1022                 last_pd_pool_option_id = out_bindings[11]->getInteger<uint64_t>();
 1023 
 1024                 OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 11);
 1025                 if (desc) {
 1026                     last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
 1027                 }
 1028             }
 1029         });
 1030     }
 1031 
 1032     /// @brief Sends query to retrieve single pool by address range.
 1033     ///
 1034     /// @param server_selector Server selector.
 1035     /// @param pool_start_address Lower bound pool address.
 1036     /// @param pool_end_address Upper bound pool address.
 1037     /// @param pool_id Pool identifier for the returned pool.
 1038     /// @return Pointer to the pool or null if no such pool found.
 1039     Pool6Ptr getPool6(const ServerSelector& server_selector,
 1040                       const IOAddress& pool_start_address,
 1041                       const IOAddress& pool_end_address,
 1042                       uint64_t& pool_id) {
 1043         PoolCollection pools;
 1044         std::vector<uint64_t> pool_ids;
 1045 
 1046         if (server_selector.amAny()) {
 1047             MySqlBindingCollection in_bindings = {
 1048                     MySqlBinding::createString(pool_start_address.toText()),
 1049                     MySqlBinding::createString(pool_end_address.toText())
 1050             };
 1051             getPools(GET_POOL6_RANGE_ANY, in_bindings, pools, pool_ids);
 1052 
 1053         } else {
 1054             auto tags = server_selector.getTags();
 1055             for (auto tag : tags) {
 1056                 MySqlBindingCollection in_bindings = {
 1057                     MySqlBinding::createString(tag.get()),
 1058                     MySqlBinding::createString(pool_start_address.toText()),
 1059                     MySqlBinding::createString(pool_end_address.toText())
 1060                 };
 1061                 getPools(GET_POOL6_RANGE, in_bindings, pools, pool_ids);
 1062 
 1063             }
 1064         }
 1065 
 1066         // Return upon the first pool found.
 1067         if (!pools.empty()) {
 1068             pool_id = pool_ids[0];
 1069             return (boost::dynamic_pointer_cast<Pool6>(*pools.begin()));
 1070         }
 1071 
 1072         pool_id = 0;
 1073         return (Pool6Ptr());
 1074     }
 1075 
 1076     /// @brief Sends query to retrieve single pd pool.
 1077     ///
 1078     /// @param server_selector Server selector.
 1079     /// @param pd_pool_prefix Address part of the pd pool prefix.
 1080     /// @param pd_pool_prefix_length Length of the pd pool prefix.
 1081     /// @param pd_pool_id Pool identifier for the returned pool.
 1082     /// @return Pointer to the pool or null if no such pool found.
 1083     Pool6Ptr getPdPool6(const ServerSelector& server_selector,
 1084                         const asiolink::IOAddress& pd_pool_prefix,
 1085                         const uint8_t pd_pool_prefix_length,
 1086                         uint64_t& pd_pool_id) {
 1087         PoolCollection pd_pools;
 1088         std::vector<uint64_t> pd_pool_ids;
 1089 
 1090         if (server_selector.amAny()) {
 1091             MySqlBindingCollection in_bindings = {
 1092                 MySqlBinding::createString(pd_pool_prefix.toText()),
 1093                 MySqlBinding::createInteger<uint8_t>(pd_pool_prefix_length)
 1094             };
 1095             getPdPools(GET_PD_POOL_ANY, in_bindings, pd_pools, pd_pool_ids);
 1096 
 1097         } else {
 1098             auto tags = server_selector.getTags();
 1099             for (auto tag : tags) {
 1100                 MySqlBindingCollection in_bindings = {
 1101                     MySqlBinding::createString(tag.get()),
 1102                     MySqlBinding::createString(pd_pool_prefix.toText()),
 1103                     MySqlBinding::createInteger<uint8_t>(pd_pool_prefix_length)
 1104                 };
 1105                 getPdPools(GET_PD_POOL, in_bindings, pd_pools, pd_pool_ids);
 1106             }
 1107         }
 1108 
 1109         if (!pd_pools.empty()) {
 1110             pd_pool_id = pd_pool_ids[0];
 1111             return (boost::dynamic_pointer_cast<Pool6>(*pd_pools.begin()));
 1112         }
 1113 
 1114         pd_pool_id = 0;
 1115 
 1116         return (Pool6Ptr());
 1117     }
 1118 
 1119     /// @brief Sends query to insert or update subnet.
 1120     ///
 1121     /// @param server_selector Server selector.
 1122     /// @param subnet Pointer to the subnet to be inserted or updated.
 1123     void createUpdateSubnet6(const ServerSelector& server_selector,
 1124                              const Subnet6Ptr& subnet) {
 1125 
 1126         if (server_selector.amAny()) {
 1127             isc_throw(InvalidOperation, "creating or updating a subnet for ANY"
 1128                       " server is not supported");
 1129 
 1130         } else if (server_selector.amUnassigned()) {
 1131             isc_throw(NotImplemented, "managing configuration for no particular server"
 1132                       " (unassigned) is unsupported at the moment");
 1133         }
 1134 
 1135         // Create JSON list of required classes.
 1136         ElementPtr required_classes_element = Element::createList();
 1137         const auto& required_classes = subnet->getRequiredClasses();
 1138         for (auto required_class = required_classes.cbegin();
 1139              required_class != required_classes.cend();
 1140              ++required_class) {
 1141             required_classes_element->add(Element::create(*required_class));
 1142         }
 1143 
 1144         // Create binding for host reservation mode.
 1145         MySqlBindingPtr hr_mode_binding;
 1146         auto hr_mode = subnet->getHostReservationMode(Network::Inheritance::NONE);
 1147         if (!hr_mode.unspecified()) {
 1148             hr_mode_binding = MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>
 1149                                                                    (hr_mode.get()));
 1150         } else {
 1151             hr_mode_binding = MySqlBinding::createNull();
 1152         }
 1153 
 1154         // Create binding with shared network name if the subnet belongs to a
 1155         // shared network.
 1156         MySqlBindingPtr shared_network_binding;
 1157 
 1158         SharedNetwork6Ptr shared_network;
 1159         subnet->getSharedNetwork(shared_network);
 1160 
 1161         // Check if the subnet is associated with a shared network instance.
 1162         // If it is, create the binding using the name of the shared network.
 1163         if (shared_network) {
 1164             shared_network_binding = MySqlBinding::createString(shared_network->getName());
 1165 
 1166         // If the subnet is associated with a shared network by name (no
 1167         // shared network instance), use this name to create the binding.
 1168         // This may be the case if the subnet is added as a result of
 1169         // receiving a control command that merely specifies shared
 1170         // network name. In that case, it is expected that the shared
 1171         // network data is already stored in the database.
 1172         } else if (!subnet->getSharedNetworkName().empty()) {
 1173             shared_network_binding = MySqlBinding::createString(subnet->getSharedNetworkName());
 1174 
 1175         // If the subnet is not associated with a shared network, create
 1176         // null binding.
 1177         } else {
 1178              shared_network_binding = MySqlBinding::createNull();
 1179         }
 1180 
 1181         // Create the binding holding interface_id.
 1182         MySqlBindingPtr interface_id_binding = MySqlBinding::createNull();
 1183         auto opt_iface_id = subnet->getInterfaceId();
 1184         if (opt_iface_id) {
 1185             auto iface_id_data = opt_iface_id->getData();
 1186             if (!iface_id_data.empty()) {
 1187                 interface_id_binding = MySqlBinding::createBlob(iface_id_data.begin(),
 1188                                                                 iface_id_data.end());
 1189             }
 1190         }
 1191 
 1192         // Create input bindings.
 1193         MySqlBindingCollection in_bindings = {
 1194             MySqlBinding::createInteger<uint32_t>(subnet->getID()),
 1195             MySqlBinding::createString(subnet->toText()),
 1196             MySqlBinding::condCreateString(subnet->getClientClass(Network::Inheritance::NONE)),
 1197             MySqlBinding::condCreateString(subnet->getIface(Network::Inheritance::NONE)),
 1198             MySqlBinding::createTimestamp(subnet->getModificationTime()),
 1199             createBinding(subnet->getPreferred(Network::Inheritance::NONE)),
 1200             createMinBinding(subnet->getPreferred(Network::Inheritance::NONE)),
 1201             createMaxBinding(subnet->getPreferred(Network::Inheritance::NONE)),
 1202             MySqlBinding::condCreateBool(subnet->getRapidCommit(Network::Inheritance::NONE)),
 1203             createBinding(subnet->getT2(Network::Inheritance::NONE)),
 1204             createInputRelayBinding(subnet),
 1205             createBinding(subnet->getT1(Network::Inheritance::NONE)),
 1206             createInputRequiredClassesBinding(subnet),
 1207             hr_mode_binding,
 1208             shared_network_binding,
 1209             createInputContextBinding(subnet),
 1210             createBinding(subnet->getValid(Network::Inheritance::NONE)),
 1211             createMinBinding(subnet->getValid(Network::Inheritance::NONE)),
 1212             createMaxBinding(subnet->getValid(Network::Inheritance::NONE)),
 1213             MySqlBinding::condCreateBool(subnet->getCalculateTeeTimes(Network::Inheritance::NONE)),
 1214             MySqlBinding::condCreateFloat(subnet->getT1Percent(Network::Inheritance::NONE)),
 1215             MySqlBinding::condCreateFloat(subnet->getT2Percent(Network::Inheritance::NONE)),
 1216             interface_id_binding
 1217         };
 1218 
 1219         MySqlTransaction transaction(conn_);
 1220 
 1221         // Create scoped audit revision. As long as this instance exists
 1222         // no new audit revisions are created in any subsequent calls.
 1223         ScopedAuditRevision audit_revision(this,
 1224                                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 1225                                            server_selector, "subnet set", true);
 1226 
 1227         try {
 1228 
 1229             // Try to insert subnet. If this duplicates unique key, i.e. this
 1230             // subnet already exists it will throw DuplicateEntry exception in
 1231             // which case we'll try an update.
 1232             conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6,
 1233                               in_bindings);
 1234 
 1235         } catch (const DuplicateEntry&) {
 1236             deletePools6(subnet);
 1237             deletePdPools6(subnet);
 1238             deleteOptions6(ServerSelector::ANY(), subnet);
 1239 
 1240             // Need to add two more bindings for WHERE clause.
 1241             in_bindings.push_back(MySqlBinding::createInteger<uint32_t>(subnet->getID()));
 1242             in_bindings.push_back(MySqlBinding::createString(subnet->toText()));
 1243             conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6,
 1244                                     in_bindings);
 1245 
 1246             MySqlBindingCollection in_server_bindings = {
 1247                 MySqlBinding::createInteger<uint32_t>(subnet->getID())
 1248             };
 1249             conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER,
 1250                                     in_server_bindings);
 1251         }
 1252 
 1253         // Insert associations with the servers.
 1254         attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER,
 1255                                server_selector,
 1256                                MySqlBinding::createInteger<uint32_t>(subnet->getID()),
 1257                                MySqlBinding::createTimestamp(subnet->getModificationTime()));
 1258 
 1259         // (Re)create pools.
 1260         for (auto pool : subnet->getPools(Lease::TYPE_NA)) {
 1261             createPool6(server_selector, boost::dynamic_pointer_cast<Pool6>(pool),
 1262                         subnet);
 1263         }
 1264 
 1265         // (Re)create pd pools.
 1266         for (auto pd_pool : subnet->getPools(Lease::TYPE_PD)) {
 1267             createPdPool6(server_selector, boost::dynamic_pointer_cast<Pool6>(pd_pool),
 1268                           subnet);
 1269         }
 1270 
 1271         // (Re)create options.
 1272         auto option_spaces = subnet->getCfgOption()->getOptionSpaceNames();
 1273         for (auto option_space : option_spaces) {
 1274             OptionContainerPtr options = subnet->getCfgOption()->getAll(option_space);
 1275             for (auto desc = options->begin(); desc != options->end(); ++desc) {
 1276                 OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
 1277                 desc_copy->space_name_ = option_space;
 1278                 createUpdateOption6(server_selector, subnet->getID(), desc_copy,
 1279                                     true);
 1280             }
 1281         }
 1282 
 1283         transaction.commit();
 1284     }
 1285 
 1286     /// @brief Inserts new IPv6 pool to the database.
 1287     ///
 1288     /// @param server_selector Server selector.
 1289     /// @param pool Pointer to the pool to be inserted.
 1290     /// @param subnet Pointer to the subnet that this pool belongs to.
 1291     void createPool6(const ServerSelector& server_selector, const Pool6Ptr& pool,
 1292                      const Subnet6Ptr& subnet) {
 1293         MySqlBindingCollection in_bindings = {
 1294             MySqlBinding::createString(pool->getFirstAddress().toText()),
 1295             MySqlBinding::createString(pool->getLastAddress().toText()),
 1296             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())),
 1297             MySqlBinding::condCreateString(pool->getClientClass()),
 1298             createInputRequiredClassesBinding(pool),
 1299             createInputContextBinding(pool),
 1300             MySqlBinding::createTimestamp(subnet->getModificationTime())
 1301         };
 1302 
 1303         // Run INSERT.
 1304         conn_.insertQuery(INSERT_POOL6, in_bindings);
 1305 
 1306         uint64_t pool_id = mysql_insert_id(conn_.mysql_);
 1307         auto option_spaces = pool->getCfgOption()->getOptionSpaceNames();
 1308         for (auto option_space : option_spaces) {
 1309             OptionContainerPtr options = pool->getCfgOption()->getAll(option_space);
 1310             for (auto desc = options->begin(); desc != options->end(); ++desc) {
 1311                 OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
 1312                 desc_copy->space_name_ = option_space;
 1313                 createUpdateOption6(server_selector, Lease::TYPE_NA,
 1314                                     pool_id, desc_copy, true);
 1315             }
 1316         }
 1317     }
 1318 
 1319     /// @brief Inserts new IPv6 pd pool to the database.
 1320     ///
 1321     /// @param server_selector Server selector.
 1322     /// @param pd_pool Pointer to the pd pool to be inserted.
 1323     /// @param subnet Pointer to the subnet that this pd pool belongs to.
 1324     void createPdPool6(const ServerSelector& server_selector,
 1325                        const Pool6Ptr& pd_pool,
 1326                        const Subnet6Ptr& subnet) {
 1327         int plen = prefixLengthFromRange(pd_pool->getFirstAddress(),
 1328                                          pd_pool->getLastAddress());
 1329 
 1330         // Extract excluded prefix components.
 1331         Optional<std::string> xprefix_txt;
 1332         uint8_t xlen = 0;
 1333         const Option6PDExcludePtr& xopt = pd_pool->getPrefixExcludeOption();
 1334         if (xopt) {
 1335             const IOAddress& prefix = pd_pool->getFirstAddress();
 1336             const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, pd_pool->getLength());
 1337             xprefix_txt = xprefix.toText();
 1338             xlen = xopt->getExcludedPrefixLength();
 1339         }
 1340 
 1341         MySqlBindingCollection in_bindings = {
 1342             MySqlBinding::createString(pd_pool->getFirstAddress().toText()),
 1343             MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(plen)),
 1344             MySqlBinding::createInteger<uint8_t>(pd_pool->getLength()),
 1345             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())),
 1346             MySqlBinding::condCreateString(xprefix_txt),
 1347             MySqlBinding::createInteger<uint8_t>(xlen),
 1348             MySqlBinding::condCreateString(pd_pool->getClientClass()),
 1349             createInputRequiredClassesBinding(pd_pool),
 1350             createInputContextBinding(pd_pool),
 1351             MySqlBinding::createTimestamp(subnet->getModificationTime())
 1352         };
 1353 
 1354         // Run INSERT.
 1355         conn_.insertQuery(INSERT_PD_POOL, in_bindings);
 1356 
 1357         uint64_t pd_pool_id = mysql_insert_id(conn_.mysql_);
 1358         auto option_spaces = pd_pool->getCfgOption()->getOptionSpaceNames();
 1359         for (auto option_space : option_spaces) {
 1360             OptionContainerPtr options = pd_pool->getCfgOption()->getAll(option_space);
 1361             for (auto desc = options->begin(); desc != options->end(); ++desc) {
 1362                 OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
 1363                 desc_copy->space_name_ = option_space;
 1364                 createUpdateOption6(server_selector, Lease::TYPE_PD,
 1365                                     pd_pool_id, desc_copy, true);
 1366             }
 1367         }
 1368     }
 1369 
 1370     /// @brief Sends a query to delete data from a table.
 1371     ///
 1372     /// If creates a new audit revision for this change if such audit
 1373     /// revision doesn't exist yet (using ScopedAuditRevision mechanism).
 1374     ///
 1375     /// @tparam Args type of the arguments to be passed to one of the existing
 1376     /// @c deleteFromTable methods.
 1377     /// @param server_selector server selector.
 1378     /// @param operation operation which results in calling this function. This is
 1379     /// used for logging purposes.
 1380     /// @param log_message log message to be associated with the audit revision.
 1381     /// @param cascade_delete boolean flag indicating if we're performing
 1382     /// cascade delete. If set to true, the audit entries for the child
 1383     /// objects (e.g. DHCPoptions) won't be created.
 1384     /// @param keys arguments to be passed to one of the existing
 1385     /// @c deleteFromTable methods.
 1386     ///
 1387     /// @return Number of deleted entries.
 1388     template<typename... Args>
 1389     uint64_t deleteTransactional(const int index,
 1390                                  const db::ServerSelector& server_selector,
 1391                                  const std::string& operation,
 1392                                  const std::string& log_message,
 1393                                  const bool cascade_delete,
 1394                                  Args&&... keys) {
 1395 
 1396         MySqlTransaction transaction(conn_);
 1397 
 1398         // Create scoped audit revision. As long as this instance exists
 1399         // no new audit revisions are created in any subsequent calls.
 1400         ScopedAuditRevision
 1401             audit_revision(this,
 1402                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 1403                            server_selector, log_message, cascade_delete);
 1404 
 1405         auto count = deleteFromTable(index, server_selector, operation, keys...);
 1406 
 1407         transaction.commit();
 1408 
 1409         return (count);
 1410     }
 1411 
 1412     /// @brief Sends query to delete subnet by id.
 1413     ///
 1414     /// @param server_selector Server selector.
 1415     /// @param subnet_id Identifier of the subnet to be deleted.
 1416     /// @return Number of deleted subnets.
 1417     uint64_t deleteSubnet6(const ServerSelector& server_selector,
 1418                            const SubnetID& subnet_id) {
 1419         int index = (server_selector.amAny() ?
 1420                      MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY :
 1421                      MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG);
 1422         return (deleteTransactional(index, server_selector,
 1423                                     "deleting a subnet", "subnet deleted",
 1424                                     true, static_cast<uint32_t>(subnet_id)));
 1425     }
 1426 
 1427     /// @brief Sends query to delete subnet by id.
 1428     ///
 1429     /// @param server_selector Server selector.
 1430     /// @param subnet_prefix Prefix of the subnet to be deleted.
 1431     /// @return Number of deleted subnets.
 1432     uint64_t deleteSubnet6(const ServerSelector& server_selector,
 1433                            const std::string& subnet_prefix) {
 1434         int index = (server_selector.amAny() ?
 1435                      MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY :
 1436                      MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG);
 1437         return (deleteTransactional(index, server_selector,
 1438                                     "deleting a subnet", "subnet deleted",
 1439                                     true, subnet_prefix));
 1440     }
 1441 
 1442     /// @brief Deletes pools belonging to a subnet from the database.
 1443     ///
 1444     /// The query deletes all pools associated with the subnet's
 1445     /// identifier or prefix.
 1446     /// @param subnet Pointer to the subnet for which pools should be
 1447     /// deleted.
 1448     uint64_t deletePools6(const Subnet6Ptr& subnet) {
 1449         MySqlBindingCollection in_bindings = {
 1450             MySqlBinding::createInteger<uint32_t>(subnet->getID()),
 1451             MySqlBinding::createString(subnet->toText())
 1452         };
 1453 
 1454         // Run DELETE.
 1455         return (conn_.updateDeleteQuery(DELETE_POOLS6, in_bindings));
 1456     }
 1457 
 1458     /// @brief Deletes prefix delegation pools belonging to a subnet from
 1459     /// the database.
 1460     ///
 1461     /// The query deletes all pd pools associated with the subnet's
 1462     /// identifier or prefix.
 1463     /// @param subnet Pointer to the subnet for which pd pools should be
 1464     /// deleted.
 1465     uint64_t deletePdPools6(const Subnet6Ptr& subnet) {
 1466         MySqlBindingCollection in_bindings = {
 1467             MySqlBinding::createInteger<uint32_t>(subnet->getID()),
 1468             MySqlBinding::createString(subnet->toText())
 1469         };
 1470 
 1471         // Run DELETE.
 1472         return (conn_.updateDeleteQuery(DELETE_PD_POOLS, in_bindings));
 1473     }
 1474 
 1475     /// @brief Sends query to the database to retrieve multiple shared
 1476     /// networks.
 1477     ///
 1478     /// Query should order shared networks by id.
 1479     ///
 1480     /// @param index Index of the query to be used.
 1481     /// @param server_selector Server selector.
 1482     /// @param in_bindings Input bindings specifying selection criteria. The
 1483     /// size of the bindings collection must match the number of placeholders
 1484     /// in the prepared statement. The input bindings collection must be empty
 1485     /// if the query contains no WHERE clause.
 1486     /// @param [out] shared_networks Reference to the container where fetched
 1487     /// shared networks will be inserted.
 1488     void getSharedNetworks6(const StatementIndex& index,
 1489                             const ServerSelector& server_selector,
 1490                             const MySqlBindingCollection& in_bindings,
 1491                             SharedNetwork6Collection& shared_networks) {
 1492         // Create output bindings. The order must match that in the prepared
 1493         // statement.
 1494         MySqlBindingCollection out_bindings = {
 1495             MySqlBinding::createInteger<uint64_t>(), // id
 1496             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // name
 1497             MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // client_class
 1498             MySqlBinding::createString(INTERFACE_BUF_LENGTH), // interface
 1499             MySqlBinding::createTimestamp(), // modification_ts
 1500             MySqlBinding::createInteger<uint32_t>(), // preferred_lifetime
 1501             MySqlBinding::createInteger<uint8_t>(), // rapid_commit
 1502             MySqlBinding::createInteger<uint32_t>(), // rebind_timer
 1503             MySqlBinding::createString(RELAY_BUF_LENGTH), // relay
 1504             MySqlBinding::createInteger<uint32_t>(), // renew_timer
 1505             MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // require_client_classes
 1506             MySqlBinding::createInteger<uint8_t>(), // reservation_mode
 1507             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // user_context
 1508             MySqlBinding::createInteger<uint32_t>(), // valid_lifetime
 1509             MySqlBinding::createInteger<uint64_t>(), // option: option_id
 1510             MySqlBinding::createInteger<uint16_t>(), // option: code
 1511             MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value
 1512             MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
 1513             MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
 1514             MySqlBinding::createInteger<uint8_t>(), // option: persistent
 1515             MySqlBinding::createInteger<uint32_t>(), // option: dhcp6_subnet_id
 1516             MySqlBinding::createInteger<uint8_t>(), // option: scope_id
 1517             MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
 1518             MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
 1519             MySqlBinding::createInteger<uint64_t>(), // option: pool_id
 1520             MySqlBinding::createTimestamp(), // option: modification_ts
 1521             MySqlBinding::createInteger<uint64_t>(), // option: pd_pool_id
 1522             MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times
 1523             MySqlBinding::createInteger<float>(), // t1_percent
 1524             MySqlBinding::createInteger<float>(), // t2_percent
 1525             MySqlBinding::createBlob(INTERFACE_ID_BUF_LENGTH), // interface_id
 1526             MySqlBinding::createInteger<uint32_t>(), // min_preferred_lifetime
 1527             MySqlBinding::createInteger<uint32_t>(), // max_preferred_lifetime
 1528             MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime
 1529             MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime
 1530             MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag
 1531         };
 1532 
 1533         uint64_t last_network_id = 0;
 1534         uint64_t last_option_id = 0;
 1535         std::string last_tag;
 1536 
 1537         conn_.selectQuery(index, in_bindings, out_bindings,
 1538                           [this, &shared_networks, &last_network_id, &last_option_id,
 1539                            &last_tag]
 1540                           (MySqlBindingCollection& out_bindings) {
 1541             SharedNetwork6Ptr last_network;
 1542             if (!shared_networks.empty()) {
 1543                 last_network = *shared_networks.rbegin();
 1544             }
 1545 
 1546             // If this is the first shared network or the shared network id in this
 1547             // row points to the next shared network we use the data in the
 1548             // row to create the new shared network instance.
 1549             if (last_network_id != out_bindings[0]->getInteger<uint64_t>()) {
 1550 
 1551                 // Reset per shared network component tracking and server tag because
 1552                 // we're now starting to process a new shared network.
 1553                 last_option_id = 0;
 1554                 last_tag.clear();
 1555 
 1556                 last_network_id = out_bindings[0]->getInteger<uint64_t>();
 1557                 last_network = SharedNetwork6::create(out_bindings[1]->getString());
 1558                 last_network->setId(last_network_id);
 1559 
 1560                 // client_class
 1561                 if (!out_bindings[2]->amNull()) {
 1562                     last_network->allowClientClass(out_bindings[2]->getString());
 1563                 }
 1564 
 1565                 // interface
 1566                 if (!out_bindings[3]->amNull()) {
 1567                     last_network->setIface(out_bindings[3]->getString());
 1568                 }
 1569 
 1570                 // modification_ts
 1571                 last_network->setModificationTime(out_bindings[4]->getTimestamp());
 1572 
 1573                 // preferred_lifetime (and {min,max)_preferred_lifetime)
 1574                 if (!out_bindings[5]->amNull()) {
 1575                     last_network->setPreferred(createTriplet(out_bindings[5],
 1576                                                          out_bindings[31],
 1577                                                          out_bindings[32]));
 1578                 }
 1579 
 1580                 // rapid_commit
 1581                 if (!out_bindings[6]->amNull()) {
 1582                     last_network->setRapidCommit(out_bindings[6]->getBool());
 1583                 }
 1584 
 1585                 // rebind_timer
 1586                 if (!out_bindings[7]->amNull()) {
 1587                     last_network->setT2(createTriplet(out_bindings[7]));
 1588                 }
 1589 
 1590                 // relay
 1591                 ElementPtr relay_element = out_bindings[8]->getJSON();
 1592                 if (relay_element) {
 1593                     if (relay_element->getType() != Element::list) {
 1594                         isc_throw(BadValue, "invalid relay value "
 1595                                   << out_bindings[8]->getString());
 1596                     }
 1597                     for (auto i = 0; i < relay_element->size(); ++i) {
 1598                         auto relay_address_element = relay_element->get(i);
 1599                         if (relay_address_element->getType() != Element::string) {
 1600                             isc_throw(BadValue, "relay address must be a string");
 1601                         }
 1602                         last_network->addRelayAddress(IOAddress(relay_element->get(i)->stringValue()));
 1603                     }
 1604                 }
 1605 
 1606                 // renew_timer
 1607                 if (!out_bindings[9]->amNull()) {
 1608                     last_network->setT1(createTriplet(out_bindings[9]));
 1609                 }
 1610 
 1611                 // require_client_classes
 1612                 ElementPtr require_element = out_bindings[10]->getJSON();
 1613                 if (require_element) {
 1614                     if (require_element->getType() != Element::list) {
 1615                         isc_throw(BadValue, "invalid require_client_classes value "
 1616                               << out_bindings[10]->getString());
 1617                     }
 1618                     for (auto i = 0; i < require_element->size(); ++i) {
 1619                         auto require_item = require_element->get(i);
 1620                         if (require_item->getType() != Element::string) {
 1621                             isc_throw(BadValue, "elements of require_client_classes list must"
 1622                                       "be valid strings");
 1623                         }
 1624                         last_network->requireClientClass(require_item->stringValue());
 1625                     }
 1626                 }
 1627 
 1628                 // reservation_mode
 1629                 if (!out_bindings[11]->amNull()) {
 1630                     last_network->setHostReservationMode(static_cast<Subnet4::HRMode>
 1631                         (out_bindings[11]->getIntegerOrDefault<uint8_t>(Subnet4::HR_ALL)));
 1632                 }
 1633 
 1634                 // user_context
 1635                 ElementPtr user_context = out_bindings[12]->getJSON();
 1636                 if (user_context) {
 1637                     last_network->setContext(user_context);
 1638                 }
 1639 
 1640                 // valid_lifetime (and {min,max)_valid_lifetime)
 1641                 if (!out_bindings[13]->amNull()) {
 1642                     last_network->setValid(createTriplet(out_bindings[13],
 1643                                                          out_bindings[33],
 1644                                                          out_bindings[34]));
 1645                 }
 1646 
 1647                 // calculate_tee_times
 1648                 if (!out_bindings[27]->amNull()) {
 1649                     last_network->setCalculateTeeTimes(out_bindings[27]->getBool());
 1650                 }
 1651 
 1652                 // t1_percent
 1653                 if (!out_bindings[28]->amNull()) {
 1654                     last_network->setT1Percent(out_bindings[28]->getFloat());
 1655                 }
 1656 
 1657                 // t2_percent
 1658                 if (!out_bindings[29]->amNull()) {
 1659                     last_network->setT2Percent(out_bindings[29]->getFloat());
 1660                 }
 1661 
 1662                 // interface_id
 1663                 if (!out_bindings[30]->amNull()) {
 1664                     auto iface_id_data = out_bindings[30]->getBlob();
 1665                     if (!iface_id_data.empty()) {
 1666                         OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID,
 1667                                                           iface_id_data));
 1668                         last_network->setInterfaceId(opt_iface_id);
 1669                     }
 1670                 }
 1671 
 1672                 // {min,max)_preferred_lifetime
 1673 
 1674                 // {min,max)_valid_lifetime
 1675 
 1676                 // Add the shared network.
 1677                 auto ret = shared_networks.push_back(last_network);
 1678 
 1679                 // shared_networks is a multi index container with an unique
 1680                 // index but this index is unique too in the database,
 1681                 // so this is for sanity only.
 1682                 if (!ret.second) {
 1683                     isc_throw(Unexpected, "add shared network failed");
 1684                 }
 1685             }
 1686 
 1687             // Parse option from 14 to 26.
 1688             if (!out_bindings[14]->amNull() &&
 1689                 (last_option_id < out_bindings[14]->getInteger<uint64_t>())) {
 1690                 last_option_id = out_bindings[14]->getInteger<uint64_t>();
 1691 
 1692                 OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 14);
 1693                 if (desc) {
 1694                     last_network->getCfgOption()->add(*desc, desc->space_name_);
 1695                 }
 1696             }
 1697 
 1698             // Check for new server tags.
 1699             if (!out_bindings[35]->amNull() &&
 1700                 (last_tag != out_bindings[35]->getString())) {
 1701                 last_tag = out_bindings[35]->getString();
 1702                 if (!last_tag.empty() && !last_network->hasServerTag(ServerTag(last_tag))) {
 1703                     last_network->setServerTag(last_tag);
 1704                 }
 1705             }
 1706         });
 1707 
 1708         // Now that we're done fetching the whole network, we have to
 1709         // check if it has matching server tags and toss it if it
 1710         // doesn't. We skip matching the server tags if we're asking
 1711         // for ANY shared network.
 1712         auto& sn_index = shared_networks.get<SharedNetworkRandomAccessIndexTag>();
 1713         tossNonMatchingElements(server_selector, sn_index);
 1714     }
 1715 
 1716     /// @brief Sends query to retrieve single shared network by name.
 1717     ///
 1718     /// @param server_selector Server selector.
 1719     /// @param name Shared network name.
 1720     ///
 1721     /// @return Pointer to the returned shared network or NULL if such shared
 1722     /// network doesn't exist.
 1723     SharedNetwork6Ptr getSharedNetwork6(const ServerSelector& server_selector,
 1724                                         const std::string& name) {
 1725 
 1726         if (server_selector.hasMultipleTags()) {
 1727             isc_throw(InvalidOperation, "expected one server tag to be specified"
 1728                       " while fetching a shared network. Got: "
 1729                       << getServerTagsAsText(server_selector));
 1730         }
 1731 
 1732         MySqlBindingCollection in_bindings = { MySqlBinding::createString(name) };
 1733 
 1734         auto index = GET_SHARED_NETWORK6_NAME_NO_TAG;
 1735 
 1736         if (server_selector.amUnassigned()) {
 1737             index = GET_SHARED_NETWORK6_NAME_UNASSIGNED;
 1738 
 1739         } else if (server_selector.amAny()) {
 1740             index = GET_SHARED_NETWORK6_NAME_ANY;
 1741         }
 1742 
 1743         SharedNetwork6Collection shared_networks;
 1744         getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
 1745 
 1746         return (shared_networks.empty() ? SharedNetwork6Ptr() : *shared_networks.begin());
 1747     }
 1748 
 1749     /// @brief Sends query to retrieve all shared networks.
 1750     ///
 1751     /// @param server_selector Server selector.
 1752     /// @param [out] shared_networks Reference to the shared networks collection
 1753     /// structure where shared networks should be inserted.
 1754     void getAllSharedNetworks6(const ServerSelector& server_selector,
 1755                                SharedNetwork6Collection& shared_networks) {
 1756         if (server_selector.amAny()) {
 1757             isc_throw(InvalidOperation, "fetching all shared networks for ANY "
 1758                       "server is not supported");
 1759         }
 1760 
 1761         auto index = (server_selector.amUnassigned() ? GET_ALL_SHARED_NETWORKS6_UNASSIGNED :
 1762                       GET_ALL_SHARED_NETWORKS6);
 1763         MySqlBindingCollection in_bindings;
 1764         getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
 1765     }
 1766 
 1767     /// @brief Sends query to retrieve modified shared networks.
 1768     ///
 1769     /// @param server_selector Server selector.
 1770     /// @param modification_ts Lower bound modification timestamp.
 1771     /// @param [out] shared_networks Reference to the shared networks collection
 1772     /// structure where shared networks should be inserted.
 1773     void getModifiedSharedNetworks6(const ServerSelector& server_selector,
 1774                                     const boost::posix_time::ptime& modification_ts,
 1775                                     SharedNetwork6Collection& shared_networks) {
 1776         if (server_selector.amAny()) {
 1777             isc_throw(InvalidOperation, "fetching modified shared networks for ANY "
 1778                       "server is not supported");
 1779         }
 1780 
 1781         MySqlBindingCollection in_bindings = {
 1782             MySqlBinding::createTimestamp(modification_ts)
 1783         };
 1784 
 1785         auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED :
 1786                       GET_MODIFIED_SHARED_NETWORKS6);
 1787         getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
 1788     }
 1789 
 1790     /// @brief Sends query to insert or update shared network.
 1791     ///
 1792     /// @param server_selector Server selector.
 1793     /// @param subnet Pointer to the shared network to be inserted or updated.
 1794     void createUpdateSharedNetwork6(const ServerSelector& server_selector,
 1795                                     const SharedNetwork6Ptr& shared_network) {
 1796 
 1797         if (server_selector.amAny()) {
 1798             isc_throw(InvalidOperation, "creating or updating a shared network for ANY"
 1799                       " server is not supported");
 1800 
 1801         } else if (server_selector.amUnassigned()) {
 1802             isc_throw(NotImplemented, "managing configuration for no particular server"
 1803                       " (unassigned) is unsupported at the moment");
 1804         }
 1805 
 1806         // Create binding for host reservation mode.
 1807         MySqlBindingPtr hr_mode_binding;
 1808         auto hr_mode = shared_network->getHostReservationMode(Network::Inheritance::NONE);
 1809         if (!hr_mode.unspecified()) {
 1810             hr_mode_binding = MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>
 1811                                                                    (hr_mode.get()));
 1812         } else {
 1813             hr_mode_binding = MySqlBinding::createNull();
 1814         }
 1815 
 1816         // Create the binding holding interface_id.
 1817         MySqlBindingPtr interface_id_binding = MySqlBinding::createNull();
 1818         auto opt_iface_id = shared_network->getInterfaceId();
 1819         if (opt_iface_id) {
 1820             auto iface_id_data = opt_iface_id->getData();
 1821             if (!iface_id_data.empty()) {
 1822                 interface_id_binding = MySqlBinding::createBlob(iface_id_data.begin(),
 1823                                                                 iface_id_data.end());
 1824             }
 1825         }
 1826 
 1827         MySqlBindingCollection in_bindings = {
 1828             MySqlBinding::createString(shared_network->getName()),
 1829             MySqlBinding::condCreateString(shared_network->getClientClass(Network::Inheritance::NONE)),
 1830             MySqlBinding::condCreateString(shared_network->getIface(Network::Inheritance::NONE)),
 1831             MySqlBinding::createTimestamp(shared_network->getModificationTime()),
 1832             createBinding(shared_network->getPreferred(Network::Inheritance::NONE)),
 1833             createMinBinding(shared_network->getPreferred(Network::Inheritance::NONE)),
 1834             createMaxBinding(shared_network->getPreferred(Network::Inheritance::NONE)),
 1835             MySqlBinding::condCreateBool(shared_network->getRapidCommit(Network::Inheritance::NONE)),
 1836             createBinding(shared_network->getT2(Network::Inheritance::NONE)),
 1837             createInputRelayBinding(shared_network),
 1838             createBinding(shared_network->getT1(Network::Inheritance::NONE)),
 1839             createInputRequiredClassesBinding(shared_network),
 1840             hr_mode_binding,
 1841             createInputContextBinding(shared_network),
 1842             createBinding(shared_network->getValid(Network::Inheritance::NONE)),
 1843             createMinBinding(shared_network->getValid(Network::Inheritance::NONE)),
 1844             createMaxBinding(shared_network->getValid(Network::Inheritance::NONE)),
 1845             MySqlBinding::condCreateBool(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE)),
 1846             MySqlBinding::condCreateFloat(shared_network->getT1Percent(Network::Inheritance::NONE)),
 1847             MySqlBinding::condCreateFloat(shared_network->getT2Percent(Network::Inheritance::NONE)),
 1848             interface_id_binding
 1849         };
 1850 
 1851         MySqlTransaction transaction(conn_);
 1852 
 1853         // Create scoped audit revision. As long as this instance exists
 1854         // no new audit revisions are created in any subsequent calls.
 1855         ScopedAuditRevision
 1856             audit_revision(this,
 1857                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 1858                            server_selector, "shared network set", true);
 1859 
 1860         try {
 1861 
 1862             // Try to insert shared network. The shared network name must be unique,
 1863             // so if inserting fails with DuplicateEntry exception we'll need to
 1864             // update existing shared network entry.
 1865             conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6,
 1866                               in_bindings);
 1867 
 1868         } catch (const DuplicateEntry&) {
 1869             deleteOptions6(ServerSelector::ANY(), shared_network);
 1870 
 1871             // Need to add one more binding for WHERE clause.
 1872             in_bindings.push_back(MySqlBinding::createString(shared_network->getName()));
 1873             conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6,
 1874                                     in_bindings);
 1875 
 1876             MySqlBindingCollection in_server_bindings = {
 1877                 MySqlBinding::createString(shared_network->getName())
 1878             };
 1879             conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER,
 1880                                     in_server_bindings);
 1881 
 1882         }
 1883 
 1884         attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER,
 1885                                server_selector,
 1886                                MySqlBinding::createString(shared_network->getName()),
 1887                                MySqlBinding::createTimestamp(shared_network->getModificationTime()));
 1888 
 1889         // (Re)create options.
 1890         auto option_spaces = shared_network->getCfgOption()->getOptionSpaceNames();
 1891         for (auto option_space : option_spaces) {
 1892             OptionContainerPtr options = shared_network->getCfgOption()->getAll(option_space);
 1893             for (auto desc = options->begin(); desc != options->end(); ++desc) {
 1894                 OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
 1895                 desc_copy->space_name_ = option_space;
 1896                 createUpdateOption6(server_selector, shared_network->getName(),
 1897                                     desc_copy, true);
 1898             }
 1899         }
 1900 
 1901         transaction.commit();
 1902     }
 1903 
 1904 
 1905     /// @brief Sends query to insert DHCP option.
 1906     ///
 1907     /// This method expects that the server selector contains exactly one
 1908     /// server tag.
 1909     ///
 1910     /// @param server_selector Server selector.
 1911     /// @param in_bindings Collection of bindings representing an option.
 1912     void insertOption6(const ServerSelector& server_selector,
 1913                        const MySqlBindingCollection& in_bindings) {
 1914         conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6,
 1915                           in_bindings);
 1916 
 1917         // Fetch primary key value of the inserted option. We will use it in the
 1918         // next INSERT statement to associate this option with the server.
 1919         auto option_id = mysql_insert_id(conn_.mysql_);
 1920 
 1921         // Timestamp is expected to be in this input binding.
 1922         auto timestamp_binding = in_bindings[11];
 1923 
 1924         // Associate the option with the servers.
 1925         attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER,
 1926                                server_selector,
 1927                                MySqlBinding::createInteger<uint64_t>(option_id),
 1928                                timestamp_binding);
 1929     }
 1930 
 1931     /// @brief Sends query to insert or update global DHCP option.
 1932     ///
 1933     /// @param server_selector Server selector.
 1934     /// @param option Pointer to the option descriptor encapsulating the option.
 1935     void createUpdateOption6(const ServerSelector& server_selector,
 1936                              const OptionDescriptorPtr& option) {
 1937 
 1938         if (server_selector.amUnassigned()) {
 1939             isc_throw(NotImplemented, "managing configuration for no particular server"
 1940                       " (unassigned) is unsupported at the moment");
 1941         }
 1942 
 1943         auto tag = getServerTag(server_selector, "creating or updating global option");
 1944 
 1945         MySqlBindingCollection in_bindings = {
 1946             MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
 1947             createOptionValueBinding(option),
 1948             MySqlBinding::condCreateString(option->formatted_value_),
 1949             MySqlBinding::condCreateString(option->space_name_),
 1950             MySqlBinding::createBool(option->persistent_),
 1951             MySqlBinding::createNull(),
 1952             MySqlBinding::createNull(),
 1953             MySqlBinding::createInteger<uint8_t>(0),
 1954             createInputContextBinding(option),
 1955             MySqlBinding::createNull(),
 1956             MySqlBinding::createNull(),
 1957             MySqlBinding::createTimestamp(option->getModificationTime()),
 1958             MySqlBinding::createNull(),
 1959             MySqlBinding::createString(tag),
 1960             MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
 1961             MySqlBinding::condCreateString(option->space_name_)
 1962         };
 1963 
 1964         MySqlTransaction transaction(conn_);
 1965 
 1966         // Create scoped audit revision. As long as this instance exists
 1967         // no new audit revisions are created in any subsequent calls.
 1968         ScopedAuditRevision
 1969             audit_revision(this,
 1970                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 1971                            server_selector, "global option set", false);
 1972 
 1973         if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
 1974                                     in_bindings) == 0) {
 1975             // Remove the 3 bindings used only in case of update.
 1976             in_bindings.resize(in_bindings.size() - 3);
 1977             insertOption6(server_selector, in_bindings);
 1978         }
 1979 
 1980         transaction.commit();
 1981     }
 1982 
 1983     /// @brief Sends query to insert or update DHCP option in a subnet.
 1984     ///
 1985     /// @param server_selector Server selector.
 1986     /// @param subnet_id Identifier of the subnet the option belongs to.
 1987     /// @param option Pointer to the option descriptor encapsulating the option.
 1988     /// @param cascade_update Boolean value indicating whether the update is
 1989     /// performed as part of the ownining element, e.g. subnet.
 1990     void createUpdateOption6(const ServerSelector& server_selector,
 1991                              const SubnetID& subnet_id,
 1992                              const OptionDescriptorPtr& option,
 1993                              const bool cascade_update) {
 1994 
 1995         if (server_selector.amUnassigned()) {
 1996             isc_throw(NotImplemented, "managing configuration for no particular server"
 1997                       " (unassigned) is unsupported at the moment");
 1998         }
 1999 
 2000         MySqlBindingCollection in_bindings = {
 2001             MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
 2002             createOptionValueBinding(option),
 2003             MySqlBinding::condCreateString(option->formatted_value_),
 2004             MySqlBinding::condCreateString(option->space_name_),
 2005             MySqlBinding::createBool(option->persistent_),
 2006             MySqlBinding::createNull(),
 2007             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
 2008             MySqlBinding::createInteger<uint8_t>(1),
 2009             createInputContextBinding(option),
 2010             MySqlBinding::createNull(),
 2011             MySqlBinding::createNull(),
 2012             MySqlBinding::createTimestamp(option->getModificationTime()),
 2013             MySqlBinding::createNull(),
 2014             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
 2015             MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
 2016             MySqlBinding::condCreateString(option->space_name_)
 2017         };
 2018 
 2019         boost::scoped_ptr<MySqlTransaction> transaction;
 2020         // Only start new transaction if specified to do so. This function may
 2021         // be called from within an existing transaction in which case we
 2022         // don't start the new one.
 2023         if (!cascade_update) {
 2024             transaction.reset(new MySqlTransaction(conn_));
 2025         }
 2026 
 2027         // Create scoped audit revision. As long as this instance exists
 2028         // no new audit revisions are created in any subsequent calls.
 2029         ScopedAuditRevision
 2030             audit_revision(this,
 2031                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2032                            server_selector, "subnet specific option set",
 2033                            cascade_update);
 2034 
 2035         if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID,
 2036                                     in_bindings) == 0) {
 2037             // Remove the 3 bindings used only in case of update.
 2038             in_bindings.resize(in_bindings.size() - 3);
 2039             insertOption6(server_selector, in_bindings);
 2040         }
 2041 
 2042         if (transaction) {
 2043             transaction->commit();
 2044         }
 2045     }
 2046 
 2047     /// @brief Sends query to insert or update DHCP option in a pool.
 2048     ///
 2049     /// @param server_selector Server selector.
 2050     /// @param pool_start_address Lower bound address of the pool.
 2051     /// @param pool_end_address Upper bound address of the pool.
 2052     /// @param option Pointer to the option descriptor encapsulating the option.
 2053     void createUpdateOption6(const ServerSelector& server_selector,
 2054                              const IOAddress& pool_start_address,
 2055                              const IOAddress& pool_end_address,
 2056                              const OptionDescriptorPtr& option) {
 2057         uint64_t pool_id = 0;
 2058         Pool6Ptr pool = getPool6(server_selector, pool_start_address, pool_end_address,
 2059                                  pool_id);
 2060         if (!pool) {
 2061             isc_throw(BadValue, "no pool found for range of "
 2062                       << pool_start_address << " : "
 2063                       << pool_end_address);
 2064         }
 2065 
 2066         createUpdateOption6(server_selector, Lease::TYPE_NA,
 2067                             pool_id, option, false);
 2068     }
 2069 
 2070 
 2071     /// @brief Sends query to insert or update DHCP option in a pd pool.
 2072     ///
 2073     /// @param server_selector Server selector.
 2074     /// @param pd_pool_prefix Address part of the pd pool prefix.
 2075     /// @param pd_pool_prefix_length Length of the pd pool prefix.
 2076     /// @param option Pointer to the option descriptor encapsulating the option.
 2077     void createUpdateOption6(const ServerSelector& server_selector,
 2078                              const asiolink::IOAddress& pd_pool_prefix,
 2079                              const uint8_t pd_pool_prefix_length,
 2080                              const OptionDescriptorPtr& option) {
 2081         uint64_t pd_pool_id = 0;
 2082         Pool6Ptr pd_pool = getPdPool6(server_selector,
 2083                                       pd_pool_prefix,
 2084                                       pd_pool_prefix_length,
 2085                                       pd_pool_id);
 2086         if (!pd_pool) {
 2087             isc_throw(BadValue, "no prefix delegation pool found for prefix "
 2088                       << "of " << pd_pool_prefix << "/"
 2089                       << static_cast<unsigned>(pd_pool_prefix_length));
 2090         }
 2091 
 2092         createUpdateOption6(server_selector, Lease::TYPE_PD,
 2093                             pd_pool_id, option, false);
 2094     }
 2095 
 2096 
 2097     /// @brief Sends query to insert or update DHCP option in an address
 2098     /// or prefix delegation pool.
 2099     ///
 2100     /// @param selector Server selector.
 2101     /// @param pool_type Pool type (Lease::TYPE_NA or Lease::TYPE_PD).
 2102     /// @param pool_id Identifier of the address or prefix delegation pool
 2103     /// the option belongs to.
 2104     /// @param option Pointer to the option descriptor encapsulating the option.
 2105     /// @param cascade_update Boolean value indicating whether the update is
 2106     /// performed as part of the ownining element, e.g. subnet.
 2107     void createUpdateOption6(const ServerSelector& server_selector,
 2108                              const Lease::Type& pool_type,
 2109                              const uint64_t pool_id,
 2110                              const OptionDescriptorPtr& option,
 2111                              const bool cascade_update) {
 2112 
 2113         if (server_selector.amUnassigned()) {
 2114             isc_throw(NotImplemented, "managing configuration for no particular server"
 2115                       " (unassigned) is unsupported at the moment");
 2116         }
 2117 
 2118         std::string msg = "creating or updating ";
 2119         if (pool_type == Lease::TYPE_PD) {
 2120             msg += "prefix delegation";
 2121         } else {
 2122             msg += "address";
 2123         }
 2124         msg += " pool level option";
 2125 
 2126         MySqlBindingCollection in_bindings;
 2127         // code
 2128         in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(option->option_->getType()));
 2129         // value
 2130         in_bindings.push_back(createOptionValueBinding(option));
 2131         // formatted_value
 2132         in_bindings.push_back(MySqlBinding::condCreateString(option->formatted_value_));
 2133         // space
 2134         in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
 2135         // persistent
 2136         in_bindings.push_back(MySqlBinding::createBool(option->persistent_));
 2137         // dhcp_client_class
 2138         in_bindings.push_back(MySqlBinding::createNull());
 2139         // dhcp[46]_subnet_id
 2140         in_bindings.push_back(MySqlBinding::createNull());
 2141         // scope_id
 2142         if (pool_type == Lease::TYPE_NA) {
 2143             in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(5));
 2144         } else {
 2145             in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(6));
 2146         }
 2147         // user_context
 2148         in_bindings.push_back(createInputContextBinding(option));
 2149         // shared_network_name
 2150         in_bindings.push_back(MySqlBinding::createNull());
 2151         // pool_id
 2152         if (pool_type == Lease::TYPE_NA) {
 2153             in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id));
 2154         } else {
 2155             in_bindings.push_back(MySqlBinding::createNull());
 2156         }
 2157         // modification_ts
 2158         in_bindings.push_back(MySqlBinding::createTimestamp(option->getModificationTime()));
 2159         // pd_pool_id
 2160         if (pool_type == Lease::TYPE_PD) {
 2161             in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id));
 2162         } else {
 2163             in_bindings.push_back(MySqlBinding::createNull());
 2164         }
 2165 
 2166         // Insert bindings used only during the update.
 2167         in_bindings.push_back(MySqlBinding::createInteger<uint64_t>(pool_id));
 2168         in_bindings.push_back(MySqlBinding::createInteger<uint16_t>(option->option_->getType()));
 2169         in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
 2170 
 2171 
 2172         MySqlTransaction transaction(conn_);
 2173 
 2174         // Create scoped audit revision. As long as this instance exists
 2175         // no new audit revisions are created in any subsequent calls.
 2176         if (pool_type == Lease::TYPE_PD) {
 2177             msg = "prefix delegation";
 2178         } else {
 2179             msg = "address";
 2180         }
 2181         msg += " pool specific option set";
 2182         ScopedAuditRevision
 2183             audit_revision(this,
 2184                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2185                            server_selector, msg, cascade_update);
 2186 
 2187         auto index = (pool_type == Lease::TYPE_NA ?
 2188                       MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID :
 2189                       MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID);
 2190         if (conn_.updateDeleteQuery(index, in_bindings) == 0) {
 2191             // Remove the 3 bindings used only in case of update.
 2192             in_bindings.resize(in_bindings.size() - 3);
 2193             insertOption6(server_selector, in_bindings);
 2194         }
 2195 
 2196         transaction.commit();
 2197     }
 2198 
 2199     /// @brief Sends query to insert or update DHCP option in a shared network.
 2200     ///
 2201     /// @param selector Server selector.
 2202     /// @param shared_network_name Name of the shared network the option
 2203     /// belongs to.
 2204     /// @param option Pointer to the option descriptor encapsulating the option.
 2205     /// @param cascade_update Boolean value indicating whether the update is
 2206     /// performed as part of the ownining element, e.g. shared network.
 2207     void createUpdateOption6(const ServerSelector& server_selector,
 2208                              const std::string& shared_network_name,
 2209                              const OptionDescriptorPtr& option,
 2210                              const bool cascade_update) {
 2211 
 2212         if (server_selector.amUnassigned()) {
 2213             isc_throw(NotImplemented, "managing configuration for no particular server"
 2214                       " (unassigned) is unsupported at the moment");
 2215         }
 2216 
 2217         MySqlBindingCollection in_bindings = {
 2218             MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
 2219             createOptionValueBinding(option),
 2220             MySqlBinding::condCreateString(option->formatted_value_),
 2221             MySqlBinding::condCreateString(option->space_name_),
 2222             MySqlBinding::createBool(option->persistent_),
 2223             MySqlBinding::createNull(),
 2224             MySqlBinding::createNull(),
 2225             MySqlBinding::createInteger<uint8_t>(4),
 2226             createInputContextBinding(option),
 2227             MySqlBinding::createString(shared_network_name),
 2228             MySqlBinding::createNull(),
 2229             MySqlBinding::createTimestamp(option->getModificationTime()),
 2230             MySqlBinding::createNull(),
 2231             MySqlBinding::createString(shared_network_name),
 2232             MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
 2233             MySqlBinding::condCreateString(option->space_name_)
 2234         };
 2235 
 2236         boost::scoped_ptr<MySqlTransaction> transaction;
 2237         // Only start new transaction if specified to do so. This function may
 2238         // be called from within an existing transaction in which case we
 2239         // don't start the new one.
 2240         if (!cascade_update) {
 2241             transaction.reset(new MySqlTransaction(conn_));
 2242         }
 2243 
 2244         // Create scoped audit revision. As long as this instance exists
 2245         // no new audit revisions are created in any subsequent calls.
 2246         ScopedAuditRevision
 2247             audit_revision(this,
 2248                            MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2249                            server_selector, "shared network specific option set",
 2250                            cascade_update);
 2251 
 2252         if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::
 2253                                     UPDATE_OPTION6_SHARED_NETWORK,
 2254                                     in_bindings) == 0) {
 2255             // Remove the 3 bindings used only in case of update.
 2256             in_bindings.resize(in_bindings.size() - 3);
 2257             insertOption6(server_selector, in_bindings);
 2258         }
 2259 
 2260         if (transaction) {
 2261             transaction->commit();
 2262         }
 2263     }
 2264 
 2265     /// @brief Sends query to insert or update option definition.
 2266     ///
 2267     /// @param server_selector Server selector.
 2268     /// @param option_def Pointer to the option definition to be inserted or updated.
 2269     void createUpdateOptionDef6(const ServerSelector& server_selector,
 2270                                 const OptionDefinitionPtr& option_def) {
 2271 
 2272         createUpdateOptionDef(server_selector, option_def, "dhcp6",
 2273                               MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
 2274                               MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6,
 2275                               MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6,
 2276                               MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2277                               MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER);
 2278     }
 2279 
 2280     /// @brief Sends query to delete option definition by code and
 2281     /// option space name.
 2282     ///
 2283     /// @param server_selector Server selector.
 2284     /// @param code Option code.
 2285     /// @param name Option name.
 2286     /// @return Number of deleted option definitions.
 2287     uint64_t deleteOptionDef6(const ServerSelector& server_selector,
 2288                               const uint16_t code,
 2289                               const std::string& space) {
 2290 
 2291         MySqlBindingCollection in_bindings = {
 2292             MySqlBinding::createInteger<uint16_t>(code),
 2293             MySqlBinding::createString(space)
 2294         };
 2295 
 2296         // Run DELETE.
 2297         return (deleteTransactional(DELETE_OPTION_DEF6_CODE_NAME, server_selector,
 2298                                     "deleting option definition",
 2299                                     "option definition deleted",
 2300                                     false,
 2301                                     in_bindings));
 2302     }
 2303 
 2304     /// @brief Deletes global option.
 2305     ///
 2306     /// @param server_selector Server selector.
 2307     /// @param code Code of the deleted option.
 2308     /// @param space Option space of the deleted option.
 2309     /// @return Number of deleted options.
 2310     uint64_t deleteOption6(const ServerSelector& server_selector,
 2311                            const uint16_t code,
 2312                            const std::string& space) {
 2313 
 2314         MySqlBindingCollection in_bindings = {
 2315             MySqlBinding::createInteger<uint16_t>(code),
 2316             MySqlBinding::createString(space)
 2317         };
 2318 
 2319         // Run DELETE.
 2320         return (deleteTransactional(DELETE_OPTION6, server_selector,
 2321                                     "deleting global option",
 2322                                     "global option deleted",
 2323                                     false,
 2324                                     in_bindings));
 2325     }
 2326 
 2327     /// @brief Deletes subnet level option.
 2328     ///
 2329     /// @param server_selector Server selector.
 2330     /// @param subnet_id Identifier of the subnet to which deleted option
 2331     /// belongs.
 2332     /// @param code Code of the deleted option.
 2333     /// @param space Option space of the deleted option.
 2334     /// @return Number of deleted options.
 2335     uint64_t deleteOption6(const ServerSelector& server_selector,
 2336                            const SubnetID& subnet_id,
 2337                            const uint16_t code,
 2338                            const std::string& space) {
 2339 
 2340         MySqlBindingCollection in_bindings = {
 2341             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
 2342             MySqlBinding::createInteger<uint16_t>(code),
 2343             MySqlBinding::createString(space)
 2344         };
 2345 
 2346         // Run DELETE.
 2347         return (deleteTransactional(DELETE_OPTION6_SUBNET_ID, server_selector,
 2348                                     "deleting option for a subnet",
 2349                                     "subnet specific option deleted",
 2350                                     false,
 2351                                     in_bindings));
 2352     }
 2353 
 2354     /// @brief Deletes pool level option.
 2355     ///
 2356     /// @param server_selector Server selector.
 2357     /// @param pool_start_address Lower bound pool address.
 2358     /// @param pool_end_address  Upper bound pool address.
 2359     /// @param code Code of the deleted option.
 2360     /// @param space Option space of the deleted option.
 2361     /// @return Number of deleted options.
 2362     uint64_t deleteOption6(const db::ServerSelector& server_selector,
 2363                            const IOAddress& pool_start_address,
 2364                            const IOAddress& pool_end_address,
 2365                            const uint16_t code,
 2366                            const std::string& space) {
 2367 
 2368         MySqlBindingCollection in_bindings = {
 2369             MySqlBinding::createInteger<uint16_t>(code),
 2370             MySqlBinding::createString(space),
 2371             MySqlBinding::createString(pool_start_address.toText()),
 2372             MySqlBinding::createString(pool_end_address.toText())
 2373         };
 2374 
 2375         // Run DELETE.
 2376         return (deleteTransactional(DELETE_OPTION6_POOL_RANGE, server_selector,
 2377                                     "deleting option for an address pool",
 2378                                     "address pool specific option deleted",
 2379                                     false,
 2380                                     in_bindings));
 2381     }
 2382 
 2383     /// @brief Deletes pd pool level option.
 2384     ///
 2385     /// @param server_selector Server selector.
 2386     /// @param pd_pool_prefix Address part of the pd pool prefix.
 2387     /// @param pd_pool_prefix_length Length of the pd pool prefix.
 2388     /// @param code Code of the deleted option.
 2389     /// @param space Option space of the deleted option.
 2390     /// @return Number of deleted options.
 2391     uint64_t deleteOption6(const db::ServerSelector& server_selector,
 2392                            const asiolink::IOAddress& pd_pool_prefix,
 2393                            const uint8_t pd_pool_prefix_length,
 2394                            const uint16_t code,
 2395                            const std::string& space) {
 2396 
 2397         MySqlBindingCollection in_bindings = {
 2398             MySqlBinding::createInteger<uint16_t>(code),
 2399             MySqlBinding::createString(space),
 2400             MySqlBinding::createString(pd_pool_prefix.toText()),
 2401             MySqlBinding::createInteger<uint8_t>(pd_pool_prefix_length)
 2402         };
 2403 
 2404         // Run DELETE.
 2405         return (deleteTransactional(DELETE_OPTION6_PD_POOL, server_selector,
 2406                                     "deleting option for a prefix delegation pool",
 2407                                     "prefix delegation pool specific option deleted",
 2408                                     false,
 2409                                     in_bindings));
 2410     }
 2411 
 2412     /// @brief Deletes shared network level option.
 2413     ///
 2414     /// @param server_selector Server selector.
 2415     /// @param shared_network_name Name of the shared network which deleted
 2416     /// option belongs to
 2417     /// @param code Code of the deleted option.
 2418     /// @param space Option space of the deleted option.
 2419     /// @return Number of deleted options.
 2420     uint64_t deleteOption6(const db::ServerSelector& server_selector,
 2421                            const std::string& shared_network_name,
 2422                            const uint16_t code,
 2423                            const std::string& space) {
 2424 
 2425         MySqlBindingCollection in_bindings = {
 2426             MySqlBinding::createString(shared_network_name),
 2427             MySqlBinding::createInteger<uint16_t>(code),
 2428             MySqlBinding::createString(space)
 2429         };
 2430 
 2431         // Run DELETE.
 2432         return (deleteTransactional(DELETE_OPTION6_SHARED_NETWORK, server_selector,
 2433                                     "deleting option for a shared network",
 2434                                     "shared network specific option deleted",
 2435                                     false,
 2436                                     in_bindings));
 2437     }
 2438 
 2439     /// @brief Deletes options belonging to a subnet from the database.
 2440     ///
 2441     /// @param server_selector Server selector.
 2442     /// @param subnet Pointer to the subnet for which options should be
 2443     /// deleted.
 2444     /// @return Number of deleted options.
 2445     uint64_t deleteOptions6(const ServerSelector& server_selector,
 2446                             const Subnet6Ptr& subnet) {
 2447 
 2448         MySqlBindingCollection in_bindings = {
 2449             MySqlBinding::createInteger<uint32_t>(subnet->getID())
 2450         };
 2451 
 2452         // Run DELETE.
 2453         return (deleteTransactional(DELETE_OPTIONS6_SUBNET_ID, server_selector,
 2454                                     "deleting options for a subnet",
 2455                                     "subnet specific options deleted",
 2456                                     true,
 2457                                     in_bindings));
 2458     }
 2459 
 2460     /// @brief Deletes options belonging to a shared network from the database.
 2461     ///
 2462     /// @param server_selector Server selector.
 2463     /// @param subnet Pointer to the subnet for which options should be
 2464     /// deleted.
 2465     /// @return Number of deleted options.
 2466     uint64_t deleteOptions6(const ServerSelector& server_selector,
 2467                             const SharedNetwork6Ptr& shared_network) {
 2468 
 2469         MySqlBindingCollection in_bindings = {
 2470             MySqlBinding::createString(shared_network->getName())
 2471         };
 2472 
 2473         // Run DELETE.
 2474         return (deleteTransactional(DELETE_OPTIONS6_SHARED_NETWORK, server_selector,
 2475                                     "deleting options for a shared network",
 2476                                     "shared network specific options deleted",
 2477                                     true,
 2478                                     in_bindings));
 2479     }
 2480 
 2481     /// @brief Removes unassigned global parameters, global options and
 2482     /// option definitions.
 2483     ///
 2484     /// This function is called when one or more servers are deleted and
 2485     /// it is likely that there are some orphaned configuration elements
 2486     /// left in the database. This method removes those elements.
 2487     void purgeUnassignedConfig() {
 2488         multipleUpdateDeleteQueries(DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
 2489                                     DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
 2490                                     DELETE_ALL_OPTION_DEFS6_UNASSIGNED);
 2491     }
 2492 
 2493     /// @brief Attempts to delete a server having a given tag.
 2494     ///
 2495     /// @param server_tag Tag of the server to be deleted.
 2496     /// @return Number of deleted servers.
 2497     /// @throw isc::InvalidOperation when trying to delete the logical
 2498     /// server 'all'.
 2499     uint64_t deleteServer6(const data::ServerTag& server_tag) {
 2500         // It is not allowed to delete 'all' logical server.
 2501         if (server_tag.amAll()) {
 2502             isc_throw(InvalidOperation, "'all' is a name reserved for the server tag which"
 2503                       " associates the configuration elements with all servers connecting"
 2504                       " to the database and may not be deleted");
 2505         }
 2506 
 2507         MySqlTransaction transaction(conn_);
 2508 
 2509         // Create scoped audit revision. As long as this instance exists
 2510         // no new audit revisions are created in any subsequent calls.
 2511         ScopedAuditRevision
 2512             audit_revision(this, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2513                            ServerSelector::ALL(), "deleting a server", false);
 2514 
 2515         // Specify which server should be deleted.
 2516         MySqlBindingCollection in_bindings = {
 2517             MySqlBinding::createString(server_tag.get())
 2518         };
 2519 
 2520         // Attempt to delete the server.
 2521         auto count = conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_SERVER6,
 2522                                              in_bindings);
 2523 
 2524         // If we have deleted any servers we have to remove any dangling global
 2525         // parameters, options and option definitions.
 2526         if (count > 0) {
 2527             purgeUnassignedConfig();
 2528         }
 2529 
 2530         transaction.commit();
 2531 
 2532         return (count);
 2533     }
 2534 
 2535     /// @brief Attempts to delete all servers.
 2536     ///
 2537     /// This method deletes all servers added by the user. It does not
 2538     /// delete the logical server 'all'.
 2539     ///
 2540     /// @return Number of deleted servers.
 2541     uint64_t deleteAllServers6() {
 2542         MySqlTransaction transaction(conn_);
 2543 
 2544         // Create scoped audit revision. As long as this instance exists
 2545         // no new audit revisions are created in any subsequent calls.
 2546         ScopedAuditRevision
 2547             audit_revision(this, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2548                            ServerSelector::ALL(), "deleting all servers",
 2549                            false);
 2550 
 2551         MySqlBindingCollection in_bindings;
 2552 
 2553         // Attempt to delete the servers.
 2554         auto count = conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6,
 2555                                              in_bindings);
 2556 
 2557         // If we have deleted any servers we have to remove any dangling global
 2558         // parameters, options and option definitions.
 2559         if (count > 0) {
 2560             purgeUnassignedConfig();
 2561         }
 2562 
 2563         transaction.commit();
 2564 
 2565         return (count);
 2566     }
 2567 };
 2568 
 2569 namespace {
 2570 
 2571 /// @brief Array of tagged statements.
 2572 typedef std::array<TaggedStatement, MySqlConfigBackendDHCPv6Impl::NUM_STATEMENTS>
 2573 TaggedStatementArray;
 2574 
 2575 /// @brief Prepared MySQL statements used by the backend to insert and
 2576 /// retrieve data from the database.
 2577 TaggedStatementArray tagged_statements = { {
 2578     { MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 2579       "CALL createAuditRevisionDHCP6(?, ?, ?, ?)"
 2580     },
 2581 
 2582     // Select global parameter by name.
 2583     { MySqlConfigBackendDHCPv6Impl::GET_GLOBAL_PARAMETER6,
 2584       MYSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.name = ?)
 2585     },
 2586 
 2587     // Select all global parameters.
 2588     { MySqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6,
 2589       MYSQL_GET_GLOBAL_PARAMETER(dhcp6)
 2590     },
 2591 
 2592     // Select modified global parameters.
 2593     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6,
 2594       MYSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.modification_ts > ?)
 2595     },
 2596 
 2597     // Delete all global parameters which are unassigned to any servers.
 2598     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
 2599       MYSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp6)
 2600     },
 2601 
 2602     // Select subnet by id.
 2603     { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_NO_TAG,
 2604       MYSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_id = ?)
 2605     },
 2606 
 2607     // Select subnet by id without specifying server tags.
 2608     { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_ANY,
 2609       MYSQL_GET_SUBNET6_ANY(WHERE s.subnet_id = ?)
 2610     },
 2611 
 2612     // Select unassigned subnet by id.
 2613     { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_UNASSIGNED,
 2614       MYSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_id = ?)
 2615     },
 2616 
 2617     // Select subnet by prefix.
 2618     { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_NO_TAG,
 2619       MYSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_prefix = ?)
 2620     },
 2621 
 2622     // Select subnet by prefix without specifying server tags.
 2623     { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_ANY,
 2624       MYSQL_GET_SUBNET6_ANY(WHERE s.subnet_prefix = ?)
 2625     },
 2626 
 2627     // Select unassigned subnet by prefix.
 2628     { MySqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_UNASSIGNED,
 2629       MYSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_prefix = ?)
 2630     },
 2631 
 2632     // Select all subnets.
 2633     { MySqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6,
 2634       MYSQL_GET_SUBNET6_NO_TAG()
 2635     },
 2636 
 2637     // Select all unassigned subnets.
 2638     { MySqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6_UNASSIGNED,
 2639       MYSQL_GET_SUBNET6_UNASSIGNED()
 2640     },
 2641 
 2642     // Select subnets having modification time later than X.
 2643     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6,
 2644       MYSQL_GET_SUBNET6_NO_TAG(WHERE s.modification_ts > ?)
 2645     },
 2646 
 2647     // Select modified and unassigned subnets.
 2648     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6_UNASSIGNED,
 2649       MYSQL_GET_SUBNET6_UNASSIGNED(AND s.modification_ts > ?)
 2650     },
 2651 
 2652     // Select subnets belonging to a shared network.
 2653     { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK_SUBNETS6,
 2654       MYSQL_GET_SUBNET6_ANY(WHERE s.shared_network_name = ?)
 2655     },
 2656 
 2657     // Select pool by address range for a server.
 2658     { MySqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE,
 2659       MYSQL_GET_POOL6_RANGE_WITH_TAG(WHERE (srv.tag = ? OR srv.id = 1) AND p.start_address = ? \
 2660                                      AND p.end_address = ?)
 2661     },
 2662 
 2663     // Select pool by address range for any server.
 2664     { MySqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE_ANY,
 2665       MYSQL_GET_POOL6_RANGE_NO_TAG(WHERE p.start_address = ? AND p.end_address = ?)
 2666     },
 2667 
 2668     // Select prefix delegation pool for a server.
 2669     { MySqlConfigBackendDHCPv6Impl::GET_PD_POOL,
 2670       MYSQL_GET_PD_POOL_WITH_TAG(WHERE (srv.tag = ? OR srv.id = 1) \
 2671                                  AND p.prefix = ? AND p.prefix_length = ?)
 2672     },
 2673 
 2674     // Select prefix delegation pool for any server.
 2675     { MySqlConfigBackendDHCPv6Impl::GET_PD_POOL_ANY,
 2676       MYSQL_GET_PD_POOL_NO_TAG(WHERE p.prefix = ? AND p.prefix_length = ?)
 2677     },
 2678 
 2679     // Select shared network by name.
 2680     { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG,
 2681       MYSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.name = ?)
 2682     },
 2683 
 2684     // Select shared network by name without specifying server tags.
 2685     { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY,
 2686       MYSQL_GET_SHARED_NETWORK6_ANY(WHERE n.name = ?)
 2687     },
 2688 
 2689     // Select unassigned shared network by name.
 2690     { MySqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED,
 2691       MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.name = ?)
 2692     },
 2693 
 2694     // Select all shared networks.
 2695     { MySqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6,
 2696       MYSQL_GET_SHARED_NETWORK6_NO_TAG()
 2697     },
 2698 
 2699     // Select all unassigned shared networks.
 2700     { MySqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED,
 2701       MYSQL_GET_SHARED_NETWORK6_UNASSIGNED()
 2702     },
 2703 
 2704     // Select modified shared networks.
 2705     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6,
 2706       MYSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.modification_ts > ?)
 2707     },
 2708 
 2709     // Select modified and unassigned shared networks.
 2710     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED,
 2711       MYSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.modification_ts > ?)
 2712     },
 2713 
 2714     // Retrieves option definition by code and space.
 2715     { MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
 2716       MYSQL_GET_OPTION_DEF(dhcp6, AND d.code = ? AND d.space = ?)
 2717     },
 2718 
 2719     // Retrieves all option definitions.
 2720     { MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6,
 2721       MYSQL_GET_OPTION_DEF(dhcp6)
 2722     },
 2723 
 2724     // Retrieves modified option definitions.
 2725     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6,
 2726       MYSQL_GET_OPTION_DEF(dhcp6, AND d.modification_ts > ?)
 2727     },
 2728 
 2729     // Retrieves global option by code and space.
 2730     { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE,
 2731       MYSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = ? AND o.space = ?)
 2732     },
 2733 
 2734     // Retrieves all global options.
 2735     { MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6,
 2736       MYSQL_GET_OPTION6(AND o.scope_id = 0)
 2737     },
 2738 
 2739     // Retrieves modified options.
 2740     { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6,
 2741       MYSQL_GET_OPTION6(AND o.scope_id = 0 AND o.modification_ts > ?)
 2742     },
 2743 
 2744     // Retrieves an option for a given subnet, option code and space.
 2745     { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_SUBNET_ID_CODE_SPACE,
 2746       MYSQL_GET_OPTION6(AND o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?)
 2747     },
 2748 
 2749     // Retrieves an option for a given pool, option code and space.
 2750     { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_POOL_ID_CODE_SPACE,
 2751       MYSQL_GET_OPTION6(AND o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?)
 2752     },
 2753 
 2754     // Retrieves an option for a given pd pool, option code and space.
 2755     { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_PD_POOL_ID_CODE_SPACE,
 2756       MYSQL_GET_OPTION6(AND o.scope_id = 6 AND o.pd_pool_id = ? AND o.code = ? AND o.space = ?)
 2757     },
 2758 
 2759     // Retrieves an option for a given shared network, option code and space.
 2760     { MySqlConfigBackendDHCPv6Impl::GET_OPTION6_SHARED_NETWORK_CODE_SPACE,
 2761       MYSQL_GET_OPTION6(AND o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?)
 2762     },
 2763 
 2764     // Retrieves the most recent audit entries.
 2765     { MySqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME,
 2766       MYSQL_GET_AUDIT_ENTRIES_TIME(dhcp6)
 2767     },
 2768 
 2769     // Retrieves a server by tag.
 2770     { MySqlConfigBackendDHCPv6Impl::GET_SERVER6,
 2771       MYSQL_GET_SERVER(dhcp6)
 2772     },
 2773 
 2774     // Retrieves all servers.
 2775     { MySqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6,
 2776       MYSQL_GET_ALL_SERVERS(dhcp6)
 2777     },
 2778 
 2779     // Insert global parameter.
 2780     { MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6,
 2781       MYSQL_INSERT_GLOBAL_PARAMETER(dhcp6)
 2782     },
 2783 
 2784     // Insert association of the global parameter with a server.
 2785     { MySqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER,
 2786       MYSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp6)
 2787     },
 2788 
 2789     // Insert a subnet.
 2790     { MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6,
 2791       "INSERT INTO dhcp6_subnet("
 2792       "  subnet_id,"
 2793       "  subnet_prefix,"
 2794       "  client_class,"
 2795       "  interface,"
 2796       "  modification_ts,"
 2797       "  preferred_lifetime,"
 2798       "  min_preferred_lifetime,"
 2799       "  max_preferred_lifetime,"
 2800       "  rapid_commit,"
 2801       "  rebind_timer,"
 2802       "  relay,"
 2803       "  renew_timer,"
 2804       "  require_client_classes,"
 2805       "  reservation_mode,"
 2806       "  shared_network_name,"
 2807       "  user_context,"
 2808       "  valid_lifetime,"
 2809       "  min_valid_lifetime,"
 2810       "  max_valid_lifetime,"
 2811       "  calculate_tee_times,"
 2812       "  t1_percent,"
 2813       "  t2_percent,"
 2814       "  interface_id"
 2815       ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,"
 2816       " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" },
 2817 
 2818     // Insert association of the subnet with a server.
 2819     { MySqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER,
 2820       MYSQL_INSERT_SUBNET_SERVER(dhcp6)
 2821     },
 2822 
 2823     // Insert pool for a subnet.
 2824     { MySqlConfigBackendDHCPv6Impl::INSERT_POOL6,
 2825       MYSQL_INSERT_POOL(dhcp6)
 2826     },
 2827 
 2828     // Insert pd pool for a subnet.
 2829     { MySqlConfigBackendDHCPv6Impl::INSERT_PD_POOL,
 2830       MYSQL_INSERT_PD_POOL()
 2831     },
 2832 
 2833     // Insert a shared network.
 2834     { MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6,
 2835       "INSERT INTO dhcp6_shared_network("
 2836       "  name,"
 2837       "  client_class,"
 2838       "  interface,"
 2839       "  modification_ts,"
 2840       "  preferred_lifetime,"
 2841       "  min_preferred_lifetime,"
 2842       "  max_preferred_lifetime,"
 2843       "  rapid_commit,"
 2844       "  rebind_timer,"
 2845       "  relay,"
 2846       "  renew_timer,"
 2847       "  require_client_classes,"
 2848       "  reservation_mode,"
 2849       "  user_context,"
 2850       "  valid_lifetime,"
 2851       "  min_valid_lifetime,"
 2852       "  max_valid_lifetime,"
 2853       "  calculate_tee_times,"
 2854       "  t1_percent,"
 2855       "  t2_percent,"
 2856       "  interface_id"
 2857       ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,"
 2858       " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" },
 2859 
 2860     // Insert association of the shared network with a server.
 2861     { MySqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER,
 2862       MYSQL_INSERT_SHARED_NETWORK_SERVER(dhcp6)
 2863     },
 2864 
 2865     // Insert option definition.
 2866     { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6,
 2867       MYSQL_INSERT_OPTION_DEF(dhcp6)
 2868     },
 2869 
 2870     // Insert association of the option definition with a server.
 2871     { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER,
 2872       MYSQL_INSERT_OPTION_DEF_SERVER(dhcp6)
 2873     },
 2874 
 2875     // Insert subnet specific option.
 2876     { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6,
 2877       MYSQL_INSERT_OPTION6()
 2878     },
 2879 
 2880     // Insert association of the DHCP option with a server.
 2881     { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER,
 2882       MYSQL_INSERT_OPTION_SERVER(dhcp6)
 2883     },
 2884 
 2885     // Insert server with server tag and description.
 2886     { MySqlConfigBackendDHCPv6Impl::INSERT_SERVER6,
 2887       MYSQL_INSERT_SERVER(dhcp6)
 2888     },
 2889 
 2890     // Update existing global parameter.
 2891     { MySqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6,
 2892       MYSQL_UPDATE_GLOBAL_PARAMETER(dhcp6)
 2893     },
 2894 
 2895     // Update existing subnet.
 2896     { MySqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6,
 2897       "UPDATE dhcp6_subnet SET"
 2898       "  subnet_id = ?,"
 2899       "  subnet_prefix = ?,"
 2900       "  client_class = ?,"
 2901       "  interface = ?,"
 2902       "  modification_ts = ?,"
 2903       "  preferred_lifetime = ?,"
 2904       "  min_preferred_lifetime = ?,"
 2905       "  max_preferred_lifetime = ?,"
 2906       "  rapid_commit = ?,"
 2907       "  rebind_timer = ?,"
 2908       "  relay = ?,"
 2909       "  renew_timer = ?,"
 2910       "  require_client_classes = ?,"
 2911       "  reservation_mode = ?,"
 2912       "  shared_network_name = ?,"
 2913       "  user_context = ?,"
 2914       "  valid_lifetime = ?,"
 2915       "  min_valid_lifetime = ?,"
 2916       "  max_valid_lifetime = ?,"
 2917       "  calculate_tee_times = ?,"
 2918       "  t1_percent = ?,"
 2919       "  t2_percent = ?,"
 2920       "  interface_id = ? "
 2921       "WHERE subnet_id = ? OR subnet_prefix = ?" },
 2922 
 2923     // Update existing shared network.
 2924     { MySqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6,
 2925       "UPDATE dhcp6_shared_network SET"
 2926       "  name = ?,"
 2927       "  client_class = ?,"
 2928       "  interface = ?,"
 2929       "  modification_ts = ?,"
 2930       "  preferred_lifetime = ?,"
 2931       "  min_preferred_lifetime = ?,"
 2932       "  max_preferred_lifetime = ?,"
 2933       "  rapid_commit = ?,"
 2934       "  rebind_timer = ?,"
 2935       "  relay = ?,"
 2936       "  renew_timer = ?,"
 2937       "  require_client_classes = ?,"
 2938       "  reservation_mode = ?,"
 2939       "  user_context = ?,"
 2940       "  valid_lifetime = ?,"
 2941       "  min_valid_lifetime = ?,"
 2942       "  max_valid_lifetime = ?,"
 2943       "  calculate_tee_times = ?,"
 2944       "  t1_percent = ?,"
 2945       "  t2_percent = ?,"
 2946       "  interface_id = ? "
 2947       "WHERE name = ?" },
 2948 
 2949     // Update existing option definition.
 2950     { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6,
 2951       MYSQL_UPDATE_OPTION_DEF(dhcp6)
 2952     },
 2953 
 2954     // Update existing global option.
 2955     { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
 2956       MYSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = ? AND o.space = ?)
 2957     },
 2958 
 2959     // Update existing subnet level option.
 2960     { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID,
 2961       MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?)
 2962     },
 2963 
 2964     // Update existing pool level option.
 2965     { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID,
 2966       MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = ? AND o.code = ? AND o.space = ?)
 2967     },
 2968 
 2969     // Update existing pd pool level option.
 2970     { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID,
 2971       MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = ? AND o.code = ? AND o.space = ?)
 2972     },
 2973 
 2974     // Update existing shared network level option.
 2975     { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK,
 2976       MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?)
 2977     },
 2978 
 2979     // Update existing server, e.g. server description.
 2980     { MySqlConfigBackendDHCPv6Impl::UPDATE_SERVER6,
 2981       MYSQL_UPDATE_SERVER(dhcp6)
 2982     },
 2983 
 2984     // Delete global parameter by name.
 2985     { MySqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6,
 2986       MYSQL_DELETE_GLOBAL_PARAMETER(dhcp6, AND g.name = ?)
 2987     },
 2988 
 2989     // Delete all global parameters.
 2990     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6,
 2991       MYSQL_DELETE_GLOBAL_PARAMETER(dhcp6)
 2992     },
 2993 
 2994     // Delete subnet by id with specifying server tag.
 2995     { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG,
 2996       MYSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_id = ?)
 2997     },
 2998 
 2999     // Delete subnet by id without specifying server tag.
 3000     { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY,
 3001       MYSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_id = ?)
 3002     },
 3003 
 3004     // Delete subnet by prefix with specifying server tag.
 3005     { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG,
 3006       MYSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_prefix = ?)
 3007     },
 3008 
 3009     // Delete subnet by prefix without specifying server tag.
 3010     { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY,
 3011       MYSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_prefix = ?)
 3012     },
 3013 
 3014     // Delete all subnets.
 3015     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6,
 3016       MYSQL_DELETE_SUBNET_WITH_TAG(dhcp6)
 3017     },
 3018 
 3019     // Delete all unassigned subnets.
 3020     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED,
 3021       MYSQL_DELETE_SUBNET_UNASSIGNED(dhcp6)
 3022     },
 3023 
 3024     // Delete all subnets for a shared network.
 3025     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME,
 3026       MYSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.shared_network_name = ?)
 3027     },
 3028 
 3029     // Delete associations of a subnet with server.
 3030     { MySqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER,
 3031       MYSQL_DELETE_SUBNET_SERVER(dhcp6),
 3032     },
 3033 
 3034     // Delete pools for a subnet.
 3035     { MySqlConfigBackendDHCPv6Impl::DELETE_POOLS6,
 3036       MYSQL_DELETE_POOLS(dhcp6)
 3037     },
 3038 
 3039     // Delete pd pools for a subnet.
 3040     { MySqlConfigBackendDHCPv6Impl::DELETE_PD_POOLS,
 3041       MYSQL_DELETE_PD_POOLS()
 3042     },
 3043 
 3044     // Delete shared network by name with specifying server tag.
 3045     { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG,
 3046       MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6, AND n.name = ?)
 3047     },
 3048 
 3049     // Delete shared network by name without specifying server tag.
 3050     { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY,
 3051       MYSQL_DELETE_SHARED_NETWORK_ANY(dhcp6, WHERE n.name = ?)
 3052     },
 3053 
 3054     // Delete all shared networks.
 3055     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6,
 3056       MYSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6)
 3057     },
 3058 
 3059     // Delete all unassigned shared networks.
 3060     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED,
 3061       MYSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp6)
 3062     },
 3063 
 3064     // Delete associations of a shared network with server.
 3065     { MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER,
 3066       MYSQL_DELETE_SHARED_NETWORK_SERVER(dhcp6)
 3067     },
 3068 
 3069     // Delete option definition.
 3070     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEF6_CODE_NAME,
 3071       MYSQL_DELETE_OPTION_DEF(dhcp6, AND code = ? AND space = ?)
 3072     },
 3073 
 3074     // Delete all option definitions.
 3075     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6,
 3076       MYSQL_DELETE_OPTION_DEF(dhcp6)
 3077     },
 3078 
 3079     // Delete all option definitions which are assigned to no servers.
 3080     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6_UNASSIGNED,
 3081       MYSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp6)
 3082     },
 3083 
 3084     // Delete single global option.
 3085     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6,
 3086       MYSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0  AND o.code = ? AND o.space = ?)
 3087     },
 3088 
 3089     // Delete all global options which are unassigned to any servers.
 3090     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
 3091       MYSQL_DELETE_OPTION_UNASSIGNED(dhcp6, AND o.scope_id = 0)
 3092     },
 3093 
 3094     // Delete single option from a subnet.
 3095     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID,
 3096       MYSQL_DELETE_OPTION_NO_TAG(dhcp6,
 3097                           WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = ? AND o.code = ? AND o.space = ?)
 3098     },
 3099 
 3100     // Delete single option from a pool.
 3101     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE,
 3102       MYSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = ? AND o.space = ?)
 3103     },
 3104 
 3105     // Delete single option from a pd pool.
 3106     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL,
 3107       MYSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = ? AND o.space = ?)
 3108     },
 3109 
 3110     // Delete single option from a shared network.
 3111     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK,
 3112       MYSQL_DELETE_OPTION_NO_TAG(dhcp6,
 3113                           WHERE o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?)
 3114     },
 3115 
 3116     // Delete options belonging to a subnet.
 3117     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SUBNET_ID,
 3118       MYSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = ?)
 3119     },
 3120 
 3121     // Delete options belonging to a shared_network.
 3122     { MySqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SHARED_NETWORK,
 3123       MYSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 4 AND o.shared_network_name = ?)
 3124     },
 3125 
 3126     // Delete a server by tag.
 3127     { MySqlConfigBackendDHCPv6Impl::DELETE_SERVER6,
 3128       MYSQL_DELETE_SERVER(dhcp6)
 3129     },
 3130 
 3131     // Deletes all servers except logical server 'all'.
 3132     { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6,
 3133       MYSQL_DELETE_ALL_SERVERS(dhcp6)
 3134     }
 3135 }
 3136 };
 3137 
 3138 }; // end anonymous namespace
 3139 
 3140 MySqlConfigBackendDHCPv6Impl::MySqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap& parameters)
 3141     : MySqlConfigBackendImpl(parameters) {
 3142     // Prepare query statements. Those are will be only used to retrieve
 3143     // information from the database, so they can be used even if the
 3144     // database is read only for the current user.
 3145     conn_.prepareStatements(tagged_statements.begin(),
 3146                             tagged_statements.end());
 3147 //                            tagged_statements.begin() + WRITE_STMTS_BEGIN);
 3148 }
 3149 
 3150 MySqlConfigBackendDHCPv6::MySqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters)
 3151     : base_impl_(new MySqlConfigBackendDHCPv6Impl(parameters)), impl_() {
 3152     impl_ = boost::dynamic_pointer_cast<MySqlConfigBackendDHCPv6Impl>(base_impl_);
 3153 }
 3154 
 3155 Subnet6Ptr
 3156 MySqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector,
 3157                                      const std::string& subnet_prefix) const {
 3158     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SUBNET6_BY_PREFIX)
 3159         .arg(subnet_prefix);
 3160     return (impl_->getSubnet6(server_selector, subnet_prefix));
 3161 }
 3162 
 3163 Subnet6Ptr
 3164 MySqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector,
 3165                                      const SubnetID& subnet_id) const {
 3166     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SUBNET6_BY_SUBNET_ID)
 3167         .arg(subnet_id);
 3168     return (impl_->getSubnet6(server_selector, subnet_id));
 3169 }
 3170 
 3171 Subnet6Collection
 3172 MySqlConfigBackendDHCPv6::getAllSubnets6(const ServerSelector& server_selector) const {
 3173     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SUBNETS6);
 3174     Subnet6Collection subnets;
 3175     impl_->getAllSubnets6(server_selector, subnets);
 3176     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SUBNETS6_RESULT)
 3177         .arg(subnets.size());
 3178     return (subnets);
 3179 }
 3180 
 3181 Subnet6Collection
 3182 MySqlConfigBackendDHCPv6::getModifiedSubnets6(const ServerSelector& server_selector,
 3183                                               const boost::posix_time::ptime& modification_time) const {
 3184     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SUBNETS6)
 3185         .arg(util::ptimeToText(modification_time));
 3186     Subnet6Collection subnets;
 3187     impl_->getModifiedSubnets6(server_selector, modification_time, subnets);
 3188     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SUBNETS6_RESULT)
 3189         .arg(subnets.size());
 3190     return (subnets);
 3191 }
 3192 
 3193 Subnet6Collection
 3194 MySqlConfigBackendDHCPv6::getSharedNetworkSubnets6(const ServerSelector& /* server_selector */,
 3195                                                    const std::string& shared_network_name) const {
 3196     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6)
 3197         .arg(shared_network_name);
 3198     Subnet6Collection subnets;
 3199     impl_->getSharedNetworkSubnets6(ServerSelector::ANY(), shared_network_name, subnets);
 3200     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT)
 3201         .arg(subnets.size());
 3202     return (subnets);
 3203 }
 3204 
 3205 SharedNetwork6Ptr
 3206 MySqlConfigBackendDHCPv6::getSharedNetwork6(const ServerSelector& server_selector,
 3207                                             const std::string& name) const {
 3208     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SHARED_NETWORK6)
 3209         .arg(name);
 3210     return (impl_->getSharedNetwork6(server_selector, name));
 3211 }
 3212 
 3213 SharedNetwork6Collection
 3214 MySqlConfigBackendDHCPv6::getAllSharedNetworks6(const ServerSelector& server_selector) const {
 3215     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SHARED_NETWORKS6);
 3216     SharedNetwork6Collection shared_networks;
 3217     impl_->getAllSharedNetworks6(server_selector, shared_networks);
 3218     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT)
 3219         .arg(shared_networks.size());
 3220     return (shared_networks);
 3221 }
 3222 
 3223 SharedNetwork6Collection
 3224 MySqlConfigBackendDHCPv6::getModifiedSharedNetworks6(const ServerSelector& server_selector,
 3225         const boost::posix_time::ptime& modification_time) const {
 3226     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6)
 3227         .arg(util::ptimeToText(modification_time));
 3228     SharedNetwork6Collection shared_networks;
 3229     impl_->getModifiedSharedNetworks6(server_selector, modification_time, shared_networks);
 3230     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT)
 3231         .arg(shared_networks.size());
 3232     return (shared_networks);
 3233 }
 3234 
 3235 OptionDefinitionPtr
 3236 MySqlConfigBackendDHCPv6::getOptionDef6(const ServerSelector& server_selector,
 3237                                         const uint16_t code,
 3238                                         const std::string& space) const {
 3239     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION_DEF6)
 3240         .arg(code).arg(space);
 3241     return (impl_->getOptionDef(MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
 3242                                 server_selector, code, space));
 3243 }
 3244 
 3245 OptionDefContainer
 3246 MySqlConfigBackendDHCPv6::getAllOptionDefs6(const ServerSelector& server_selector) const {
 3247     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTION_DEFS6);
 3248     OptionDefContainer option_defs;
 3249     impl_->getAllOptionDefs(MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6,
 3250                             server_selector, option_defs);
 3251     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTION_DEFS6_RESULT)
 3252         .arg(option_defs.size());
 3253     return (option_defs);
 3254 }
 3255 
 3256 OptionDefContainer
 3257 MySqlConfigBackendDHCPv6::getModifiedOptionDefs6(const ServerSelector& server_selector,
 3258         const boost::posix_time::ptime& modification_time) const {
 3259     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTION_DEFS6)
 3260         .arg(util::ptimeToText(modification_time));
 3261     OptionDefContainer option_defs;
 3262     impl_->getModifiedOptionDefs(MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6,
 3263                                  server_selector, modification_time, option_defs);
 3264     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT)
 3265         .arg(option_defs.size());
 3266     return (option_defs);
 3267 }
 3268 
 3269 OptionDescriptorPtr
 3270 MySqlConfigBackendDHCPv6::getOption6(const ServerSelector& server_selector,
 3271                                      const uint16_t code,
 3272                                      const std::string& space) const {
 3273     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_OPTION6)
 3274         .arg(code).arg(space);
 3275     return (impl_->getOption(MySqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE,
 3276                              Option::V6, server_selector, code, space));
 3277 }
 3278 
 3279 OptionContainer
 3280 MySqlConfigBackendDHCPv6::getAllOptions6(const ServerSelector& server_selector) const {
 3281     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTIONS6);
 3282     OptionContainer options = impl_->getAllOptions(MySqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6,
 3283             Option::V6, server_selector);
 3284     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_OPTIONS6_RESULT)
 3285         .arg(options.size());
 3286     return (options);
 3287 }
 3288 
 3289 OptionContainer
 3290 MySqlConfigBackendDHCPv6::getModifiedOptions6(const ServerSelector& server_selector,
 3291         const boost::posix_time::ptime& modification_time) const {
 3292     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTIONS6)
 3293         .arg(util::ptimeToText(modification_time));
 3294     OptionContainer options = impl_->getModifiedOptions(MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6,
 3295             Option::V6, server_selector, modification_time);
 3296     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_OPTIONS6_RESULT)
 3297         .arg(options.size());
 3298     return (options);
 3299 }
 3300 
 3301 StampedValuePtr
 3302 MySqlConfigBackendDHCPv6::getGlobalParameter6(const ServerSelector& server_selector,
 3303                                               const std::string& name) const {
 3304     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_GLOBAL_PARAMETER6)
 3305         .arg(name);
 3306     return (impl_->getGlobalParameter6(server_selector, name));
 3307 }
 3308 
 3309 StampedValueCollection
 3310 MySqlConfigBackendDHCPv6::getAllGlobalParameters6(const ServerSelector& server_selector) const {
 3311     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6);
 3312     StampedValueCollection parameters;
 3313     auto tags = server_selector.getTags();
 3314     for (auto tag : tags) {
 3315         MySqlBindingCollection in_bindings = { MySqlBinding::createString(tag.get()) };
 3316         impl_->getGlobalParameters(MySqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6,
 3317                                    in_bindings, parameters);
 3318     }
 3319     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT)
 3320         .arg(parameters.size());
 3321     return (parameters);
 3322 }
 3323 
 3324 StampedValueCollection
 3325 MySqlConfigBackendDHCPv6::getModifiedGlobalParameters6(const db::ServerSelector& server_selector,
 3326         const boost::posix_time::ptime& modification_time) const {
 3327     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6)
 3328         .arg(util::ptimeToText(modification_time));
 3329     StampedValueCollection parameters;
 3330     auto tags = server_selector.getTags();
 3331     for (auto tag : tags) {
 3332         MySqlBindingCollection in_bindings = {
 3333             MySqlBinding::createString(tag.get()),
 3334             MySqlBinding::createTimestamp(modification_time)
 3335         };
 3336         impl_->getGlobalParameters(MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6,
 3337                                    in_bindings, parameters);
 3338     }
 3339     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT)
 3340         .arg(parameters.size());
 3341     return (parameters);
 3342 }
 3343 
 3344 AuditEntryCollection
 3345 MySqlConfigBackendDHCPv6::getRecentAuditEntries(const db::ServerSelector& server_selector,
 3346         const boost::posix_time::ptime& modification_time) const {
 3347     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6)
 3348         .arg(util::ptimeToText(modification_time));
 3349     AuditEntryCollection audit_entries;
 3350     impl_->getRecentAuditEntries(MySqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME,
 3351                                  server_selector, modification_time, audit_entries);
 3352     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT)
 3353         .arg(audit_entries.size());
 3354     return (audit_entries);
 3355 }
 3356 
 3357 ServerCollection
 3358 MySqlConfigBackendDHCPv6::getAllServers6() const {
 3359     ServerCollection servers;
 3360 
 3361     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SERVERS6);
 3362     impl_->getAllServers(MySqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6,
 3363                          servers);
 3364 
 3365     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_SERVERS6_RESULT)
 3366         .arg(servers.size());
 3367     return (servers);
 3368 }
 3369 
 3370 ServerPtr
 3371 MySqlConfigBackendDHCPv6::getServer6(const data::ServerTag& server_tag) const {
 3372     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_SERVER6)
 3373         .arg(server_tag.get());
 3374     return (impl_->getServer(MySqlConfigBackendDHCPv6Impl::GET_SERVER6, server_tag));
 3375 }
 3376 
 3377 void
 3378 MySqlConfigBackendDHCPv6::createUpdateSubnet6(const ServerSelector& server_selector,
 3379                                               const Subnet6Ptr& subnet) {
 3380     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SUBNET6)
 3381         .arg(subnet);
 3382     impl_->createUpdateSubnet6(server_selector, subnet);
 3383 }
 3384 
 3385 void
 3386 MySqlConfigBackendDHCPv6::createUpdateSharedNetwork6(const ServerSelector& server_selector,
 3387                                                      const SharedNetwork6Ptr& shared_network) {
 3388     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK6)
 3389         .arg(shared_network->getName());
 3390     impl_->createUpdateSharedNetwork6(server_selector, shared_network);
 3391 }
 3392 
 3393 void
 3394 MySqlConfigBackendDHCPv6::createUpdateOptionDef6(const ServerSelector& server_selector,
 3395                                                  const OptionDefinitionPtr& option_def) {
 3396     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_OPTION_DEF6)
 3397         .arg(option_def->getName()).arg(option_def->getCode());
 3398     impl_->createUpdateOptionDef6(server_selector, option_def);
 3399 }
 3400 
 3401 void
 3402 MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
 3403                                               const OptionDescriptorPtr& option) {
 3404     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_OPTION6);
 3405     impl_->createUpdateOption6(server_selector, option);
 3406 }
 3407 
 3408 void
 3409 MySqlConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_selector,
 3410                                               const std::string& shared_network_name,
 3411                                               const OptionDescriptorPtr& option) {
 3412     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6)
 3413         .arg(shared_network_name);
 3414     impl_->createUpdateOption6(server_selector, shared_network_name, option, false);
 3415 }
 3416 
 3417 void
 3418 MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
 3419                                               const SubnetID& subnet_id,
 3420                                               const OptionDescriptorPtr& option) {
 3421     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6)
 3422         .arg(subnet_id);
 3423     impl_->createUpdateOption6(server_selector, subnet_id, option, false);
 3424 }
 3425 
 3426 void
 3427 MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
 3428                                               const asiolink::IOAddress& pool_start_address,
 3429                                               const asiolink::IOAddress& pool_end_address,
 3430                                               const OptionDescriptorPtr& option) {
 3431     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6)
 3432         .arg(pool_start_address.toText()).arg(pool_end_address.toText());
 3433     impl_->createUpdateOption6(server_selector, pool_start_address, pool_end_address,
 3434                                option);
 3435 }
 3436 
 3437 void
 3438 MySqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
 3439                                               const asiolink::IOAddress& pd_pool_prefix,
 3440                                               const uint8_t pd_pool_prefix_length,
 3441                                               const OptionDescriptorPtr& option) {
 3442     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6)
 3443         .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length);
 3444     impl_->createUpdateOption6(server_selector, pd_pool_prefix,
 3445                                pd_pool_prefix_length, option);
 3446 }
 3447 
 3448 void
 3449 MySqlConfigBackendDHCPv6::createUpdateGlobalParameter6(const ServerSelector& server_selector,
 3450                                                        const StampedValuePtr& value) {
 3451     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6)
 3452         .arg(value->getName());
 3453     impl_->createUpdateGlobalParameter6(server_selector, value);
 3454 }
 3455 
 3456 void
 3457 MySqlConfigBackendDHCPv6::createUpdateServer6(const ServerPtr& server) {
 3458     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SERVER6)
 3459         .arg(server->getServerTagAsText());
 3460     impl_->createUpdateServer(MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
 3461                               MySqlConfigBackendDHCPv6Impl::INSERT_SERVER6,
 3462                               MySqlConfigBackendDHCPv6Impl::UPDATE_SERVER6,
 3463                               server);
 3464 }
 3465 
 3466 uint64_t
 3467 MySqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector,
 3468                                         const std::string& subnet_prefix) {
 3469     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_PREFIX_SUBNET6)
 3470         .arg(subnet_prefix);
 3471     uint64_t result = impl_->deleteSubnet6(server_selector, subnet_prefix);
 3472     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT)
 3473         .arg(result);
 3474     return (result);
 3475 }
 3476 
 3477 uint64_t
 3478 MySqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector,
 3479                                         const SubnetID& subnet_id) {
 3480     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6)
 3481         .arg(subnet_id);
 3482     uint64_t result = impl_->deleteSubnet6(server_selector, subnet_id);
 3483     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT)
 3484         .arg(result);
 3485     return (result);
 3486 }
 3487 
 3488 uint64_t
 3489 MySqlConfigBackendDHCPv6::deleteAllSubnets6(const ServerSelector& server_selector) {
 3490     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SUBNETS6);
 3491 
 3492     int index = (server_selector.amUnassigned() ?
 3493                  MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED :
 3494                  MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6);
 3495     uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets",
 3496                                                  "deleted all subnets", true);
 3497     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SUBNETS6_RESULT)
 3498         .arg(result);
 3499     return (result);
 3500 }
 3501 
 3502 uint64_t
 3503 MySqlConfigBackendDHCPv6::deleteSharedNetworkSubnets6(const db::ServerSelector& server_selector,
 3504                                                       const std::string& shared_network_name) {
 3505     if (!server_selector.amAny()) {
 3506         isc_throw(InvalidOperation, "deleting all subnets from a shared "
 3507                   "network requires using ANY server selector");
 3508     }
 3509     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6)
 3510         .arg(shared_network_name);
 3511     uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME,
 3512                                                  server_selector,
 3513                                                  "deleting all subnets for a shared network",
 3514                                                  "deleted all subnets for a shared network",
 3515                                                  true, shared_network_name);
 3516     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT)
 3517         .arg(result);
 3518     return (result);
 3519 }
 3520 
 3521 uint64_t
 3522 MySqlConfigBackendDHCPv6::deleteSharedNetwork6(const ServerSelector& server_selector,
 3523                                                const std::string& name) {
 3524     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK6)
 3525         .arg(name);
 3526     int index = (server_selector.amAny() ?
 3527                  MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY :
 3528                  MySqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG);
 3529     uint64_t result = impl_->deleteTransactional(index, server_selector,
 3530                                                  "deleting a shared network",
 3531                                                  "shared network deleted", true, name);
 3532     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK6_RESULT)
 3533         .arg(result);
 3534     return (result);
 3535 }
 3536 
 3537 uint64_t
 3538 MySqlConfigBackendDHCPv6::deleteAllSharedNetworks6(const ServerSelector& server_selector) {
 3539     if (server_selector.amAny()) {
 3540         isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not"
 3541                   " supported");
 3542     }
 3543 
 3544     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6);
 3545 
 3546     int index = (server_selector.amUnassigned() ?
 3547                  MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED :
 3548                  MySqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6);
 3549     uint64_t result = impl_->deleteTransactional(index,
 3550                                                  server_selector, "deleting all shared networks",
 3551                                                  "deleted all shared networks", true);
 3552     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT)
 3553         .arg(result);
 3554     return (result);
 3555 }
 3556 
 3557 uint64_t
 3558 MySqlConfigBackendDHCPv6::deleteOptionDef6(const ServerSelector& server_selector,
 3559                                            const uint16_t code,
 3560                                            const std::string& space) {
 3561     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION_DEF6)
 3562         .arg(code).arg(space);
 3563     uint64_t result = impl_->deleteOptionDef6(server_selector, code, space);
 3564     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION_DEF6_RESULT)
 3565         .arg(result);
 3566     return (result);
 3567 }
 3568 
 3569 uint64_t
 3570 MySqlConfigBackendDHCPv6::deleteAllOptionDefs6(const ServerSelector& server_selector) {
 3571     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_OPTION_DEFS6);
 3572     uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6,
 3573                                                  server_selector, "deleting all option definitions",
 3574                                                  "deleted all option definitions", true);
 3575     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT)
 3576         .arg(result);
 3577     return (result);
 3578 }
 3579 
 3580 uint64_t
 3581 MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& server_selector,
 3582                                         const uint16_t code,
 3583                                         const std::string& space) {
 3584     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION6)
 3585         .arg(code).arg(space);
 3586     uint64_t result = impl_->deleteOption6(server_selector, code, space);
 3587     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_OPTION6_RESULT)
 3588         .arg(result);
 3589     return (result);
 3590 }
 3591 
 3592 uint64_t
 3593 MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
 3594                                         const std::string& shared_network_name,
 3595                                         const uint16_t code,
 3596                                         const std::string& space) {
 3597     /// @todo In the future we might use the server selector to make sure that the
 3598     /// option is only deleted if the pool belongs to a given server. For now, we
 3599     /// just delete it when there is a match with the parent object.
 3600     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6)
 3601         .arg(shared_network_name).arg(code).arg(space);
 3602     uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), shared_network_name,
 3603                                            code, space);
 3604     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT)
 3605         .arg(result);
 3606     return (result);
 3607 }
 3608 
 3609 uint64_t
 3610 MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
 3611                                         const SubnetID& subnet_id,
 3612                                         const uint16_t code,
 3613                                         const std::string& space) {
 3614     /// @todo In the future we might use the server selector to make sure that the
 3615     /// option is only deleted if the pool belongs to a given server. For now, we
 3616     /// just delete it when there is a match with the parent object.
 3617     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6)
 3618         .arg(subnet_id).arg(code).arg(space);
 3619     uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space);
 3620     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT)
 3621         .arg(result);
 3622     return (result);
 3623 }
 3624 
 3625 uint64_t
 3626 MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
 3627                                         const asiolink::IOAddress& pool_start_address,
 3628                                         const asiolink::IOAddress& pool_end_address,
 3629                                         const uint16_t code,
 3630                                         const std::string& space) {
 3631     /// @todo In the future we might use the server selector to make sure that the
 3632     /// option is only deleted if the pool belongs to a given server. For now, we
 3633     /// just delete it when there is a match with the parent object.
 3634     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_OPTION6)
 3635         .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space);
 3636     uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pool_start_address, pool_end_address,
 3637                                            code, space);
 3638     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_OPTION6_RESULT)
 3639         .arg(result);
 3640     return (result);
 3641 }
 3642 
 3643 uint64_t
 3644 MySqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
 3645                                         const asiolink::IOAddress& pd_pool_prefix,
 3646                                         const uint8_t pd_pool_prefix_length,
 3647                                         const uint16_t code,
 3648                                         const std::string& space) {
 3649     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6)
 3650         .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length).arg(code).arg(space);
 3651     uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pd_pool_prefix,
 3652                                            pd_pool_prefix_length, code, space);
 3653     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT)
 3654         .arg(result);
 3655     return (result);
 3656 }
 3657 
 3658 uint64_t
 3659 MySqlConfigBackendDHCPv6::deleteGlobalParameter6(const ServerSelector& server_selector,
 3660                                                  const std::string& name) {
 3661     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_GLOBAL_PARAMETER6)
 3662         .arg(name);
 3663     uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6,
 3664                                                  server_selector, "deleting global parameter",
 3665                                                  "global parameter deleted", false, name);
 3666     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT)
 3667         .arg(result);
 3668     return (result);
 3669 }
 3670 
 3671 uint64_t
 3672 MySqlConfigBackendDHCPv6::deleteAllGlobalParameters6(const ServerSelector& server_selector) {
 3673     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6);
 3674     uint64_t result = impl_->deleteTransactional(MySqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6,
 3675                                                  server_selector, "deleting all global parameters",
 3676                                                  "all global parameters deleted", true);
 3677     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT)
 3678         .arg(result);
 3679     return (result);
 3680 }
 3681 
 3682 uint64_t
 3683 MySqlConfigBackendDHCPv6::deleteServer6(const ServerTag& server_tag) {
 3684     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER6)
 3685         .arg(server_tag.get());
 3686     uint64_t result = impl_->deleteServer6(server_tag);
 3687     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER6_RESULT)
 3688         .arg(result);
 3689     return (result);
 3690 }
 3691 
 3692 uint64_t
 3693 MySqlConfigBackendDHCPv6::deleteAllServers6() {
 3694     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SERVERS6);
 3695     uint64_t result = impl_->deleteAllServers6();
 3696     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_SERVERS6_RESULT)
 3697         .arg(result);
 3698     return (result);
 3699 }
 3700 
 3701 std::string
 3702 MySqlConfigBackendDHCPv6::getType() const {
 3703     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_TYPE6);
 3704     return (impl_->getType());
 3705 }
 3706 
 3707 std::string
 3708 MySqlConfigBackendDHCPv6::getHost() const {
 3709     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_HOST6);
 3710     return (impl_->getHost());
 3711 }
 3712 
 3713 uint16_t
 3714 MySqlConfigBackendDHCPv6::getPort() const {
 3715     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_PORT6);
 3716     return (impl_->getPort());
 3717 }
 3718 
 3719 bool
 3720 MySqlConfigBackendDHCPv6::registerBackendType() {
 3721     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_REGISTER_BACKEND_TYPE6);
 3722     return (
 3723         dhcp::ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("mysql",
 3724             [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv6Ptr {
 3725             return (dhcp::MySqlConfigBackendDHCPv6Ptr(new dhcp::MySqlConfigBackendDHCPv6(params)));
 3726         })
 3727     );
 3728 }
 3729 
 3730 void
 3731 MySqlConfigBackendDHCPv6::unregisterBackendType() {
 3732     LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_UNREGISTER_BACKEND_TYPE6);
 3733     dhcp::ConfigBackendDHCPv6Mgr::instance().unregisterBackendFactory("mysql");
 3734 }
 3735 
 3736 } // end of namespace isc::dhcp
 3737 } // end of namespace isc