summaryrefslogtreecommitdiffstats
path: root/src/hooks/dhcp/pgsql_cb
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
commitf5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch)
tree49e44c6f87febed37efb953ab5485aa49f6481a7 /src/hooks/dhcp/pgsql_cb
parentInitial commit. (diff)
downloadisc-kea-upstream.tar.xz
isc-kea-upstream.zip
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/hooks/dhcp/pgsql_cb')
-rw-r--r--src/hooks/dhcp/pgsql_cb/Makefile.am92
-rw-r--r--src/hooks/dhcp/pgsql_cb/Makefile.in1089
-rw-r--r--src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am56
-rw-r--r--src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in1032
-rw-r--r--src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc64
-rw-r--r--src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc20
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc122
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc5238
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h631
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc5725
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h664
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc1148
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h902
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc17
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h22
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc405
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h206
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes595
-rw-r--r--src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h1391
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/Makefile.am64
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/Makefile.in1124
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc88
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc513
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc88
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc517
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc80
-rw-r--r--src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc20
-rw-r--r--src/hooks/dhcp/pgsql_cb/version.cc18
28 files changed, 21931 insertions, 0 deletions
diff --git a/src/hooks/dhcp/pgsql_cb/Makefile.am b/src/hooks/dhcp/pgsql_cb/Makefile.am
new file mode 100644
index 0000000..2bb8eae
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/Makefile.am
@@ -0,0 +1,92 @@
+SUBDIRS = . tests libloadtests
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(PGSQL_CPPFLAGS)
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+# Ensure that the message file is included in the distribution
+EXTRA_DIST = pgsql_cb_messages.mes
+
+CLEANFILES = *.gcno *.gcda
+
+# convenience archive
+
+noinst_LTLIBRARIES = libpgsqlcb.la
+
+libpgsqlcb_la_SOURCES = pgsql_cb_callouts.cc
+
+# Commented out for now - see kea#95
+libpgsqlcb_la_SOURCES += pgsql_cb_dhcp4.cc pgsql_cb_dhcp4.h
+
+# Commented out for now - to be added back in #96
+libpgsqlcb_la_SOURCES += pgsql_cb_dhcp6.cc pgsql_cb_dhcp6.h
+
+libpgsqlcb_la_SOURCES += pgsql_cb_impl.cc pgsql_cb_impl.h
+libpgsqlcb_la_SOURCES += pgsql_cb_messages.cc pgsql_cb_messages.h
+libpgsqlcb_la_SOURCES += pgsql_cb_log.cc pgsql_cb_log.h
+libpgsqlcb_la_SOURCES += pgsql_query_macros_dhcp.h
+libpgsqlcb_la_SOURCES += version.cc
+
+libpgsqlcb_la_CXXFLAGS = $(AM_CXXFLAGS)
+libpgsqlcb_la_CPPFLAGS = $(AM_CPPFLAGS)
+
+# install the shared object into $(libdir)/kea/hooks
+lib_hooksdir = $(libdir)/kea/hooks
+lib_hooks_LTLIBRARIES = libdhcp_pgsql_cb.la
+
+libdhcp_pgsql_cb_la_SOURCES =
+libdhcp_pgsql_cb_la_LDFLAGS = $(AM_LDFLAGS) $(pgsql_LIBS)
+libdhcp_pgsql_cb_la_LDFLAGS += -avoid-version -export-dynamic -module
+
+libdhcp_pgsql_cb_la_LIBADD = libpgsqlcb.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/eval/libkea-eval.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/pgsql/libkea-pgsql.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
+libdhcp_pgsql_cb_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+
+# If we want to get rid of all generated messages files, we need to use
+# make maintainer-clean. The proper way to introduce custom commands for
+# that operation is to define maintainer-clean-local target. However,
+# make maintainer-clean also removes Makefile, so running configure script
+# is required. To make it easy to rebuild messages without going through
+# reconfigure, a new target messages-clean has been added.
+maintainer-clean-local:
+ rm -f pgsql_cb_messages.h pgsql_cb_messages.cc
+
+# To regenerate messages files, one can do:
+#
+# make messages-clean
+# make messages
+#
+# This is needed only when a .mes file is modified.
+messages-clean: maintainer-clean-local
+
+if GENERATE_MESSAGES
+
+# Define rule to build logging source files from message file
+messages: pgsql_cb_messages.h pgsql_cb_messages.cc
+ @echo Message files regenerated
+
+pgsql_cb_messages.h pgsql_cb_messages.cc: pgsql_cb_messages.mes
+ $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
+
+else
+
+messages pgsql_cb_messages.h pgsql_cb_messages.cc:
+ @echo Messages generation disabled. Configure with --enable-generate-messages to enable it.
+
+endif
diff --git a/src/hooks/dhcp/pgsql_cb/Makefile.in b/src/hooks/dhcp/pgsql_cb/Makefile.in
new file mode 100644
index 0000000..50c0c9d
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/Makefile.in
@@ -0,0 +1,1089 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/hooks/dhcp/pgsql_cb
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_cpp20.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_netconf.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(lib_hooksdir)"
+LTLIBRARIES = $(lib_hooks_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libdhcp_pgsql_cb_la_DEPENDENCIES = libpgsqlcb.la \
+ $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \
+ $(top_builddir)/src/lib/process/libkea-process.la \
+ $(top_builddir)/src/lib/eval/libkea-eval.la \
+ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \
+ $(top_builddir)/src/lib/stats/libkea-stats.la \
+ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+ $(top_builddir)/src/lib/http/libkea-http.la \
+ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \
+ $(top_builddir)/src/lib/database/libkea-database.la \
+ $(top_builddir)/src/lib/cc/libkea-cc.la \
+ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+ $(top_builddir)/src/lib/dns/libkea-dns++.la \
+ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \
+ $(top_builddir)/src/lib/log/libkea-log.la \
+ $(top_builddir)/src/lib/util/libkea-util.la \
+ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+am_libdhcp_pgsql_cb_la_OBJECTS =
+libdhcp_pgsql_cb_la_OBJECTS = $(am_libdhcp_pgsql_cb_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libdhcp_pgsql_cb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libdhcp_pgsql_cb_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+libpgsqlcb_la_LIBADD =
+am_libpgsqlcb_la_OBJECTS = libpgsqlcb_la-pgsql_cb_callouts.lo \
+ libpgsqlcb_la-pgsql_cb_dhcp4.lo \
+ libpgsqlcb_la-pgsql_cb_dhcp6.lo libpgsqlcb_la-pgsql_cb_impl.lo \
+ libpgsqlcb_la-pgsql_cb_messages.lo \
+ libpgsqlcb_la-pgsql_cb_log.lo libpgsqlcb_la-version.lo
+libpgsqlcb_la_OBJECTS = $(am_libpgsqlcb_la_OBJECTS)
+libpgsqlcb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo \
+ ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo \
+ ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo \
+ ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo \
+ ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo \
+ ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo \
+ ./$(DEPDIR)/libpgsqlcb_la-version.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libdhcp_pgsql_cb_la_SOURCES) $(libpgsqlcb_la_SOURCES)
+DIST_SOURCES = $(libdhcp_pgsql_cb_la_SOURCES) $(libpgsqlcb_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@
+DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@
+DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_NETCONF = @HAVE_NETCONF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@
+LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@
+LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@
+LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@
+LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@
+LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@
+LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@
+LIBYANG_LIBS = @LIBYANG_LIBS@
+LIBYANG_PREFIX = @LIBYANG_PREFIX@
+LIBYANG_VERSION = @LIBYANG_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_PLUGINS_PATH = @SR_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@
+SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@
+SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@
+SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_PREFIX = @SYSREPO_PREFIX@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = . tests libloadtests
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \
+ $(BOOST_INCLUDES) $(PGSQL_CPPFLAGS)
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+# Ensure that the message file is included in the distribution
+EXTRA_DIST = pgsql_cb_messages.mes
+CLEANFILES = *.gcno *.gcda
+
+# convenience archive
+noinst_LTLIBRARIES = libpgsqlcb.la
+
+# Commented out for now - see kea#95
+
+# Commented out for now - to be added back in #96
+libpgsqlcb_la_SOURCES = pgsql_cb_callouts.cc pgsql_cb_dhcp4.cc \
+ pgsql_cb_dhcp4.h pgsql_cb_dhcp6.cc pgsql_cb_dhcp6.h \
+ pgsql_cb_impl.cc pgsql_cb_impl.h pgsql_cb_messages.cc \
+ pgsql_cb_messages.h pgsql_cb_log.cc pgsql_cb_log.h \
+ pgsql_query_macros_dhcp.h version.cc
+libpgsqlcb_la_CXXFLAGS = $(AM_CXXFLAGS)
+libpgsqlcb_la_CPPFLAGS = $(AM_CPPFLAGS)
+
+# install the shared object into $(libdir)/kea/hooks
+lib_hooksdir = $(libdir)/kea/hooks
+lib_hooks_LTLIBRARIES = libdhcp_pgsql_cb.la
+libdhcp_pgsql_cb_la_SOURCES =
+libdhcp_pgsql_cb_la_LDFLAGS = $(AM_LDFLAGS) $(pgsql_LIBS) \
+ -avoid-version -export-dynamic -module
+libdhcp_pgsql_cb_la_LIBADD = libpgsqlcb.la \
+ $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \
+ $(top_builddir)/src/lib/process/libkea-process.la \
+ $(top_builddir)/src/lib/eval/libkea-eval.la \
+ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \
+ $(top_builddir)/src/lib/stats/libkea-stats.la \
+ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+ $(top_builddir)/src/lib/http/libkea-http.la \
+ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \
+ $(top_builddir)/src/lib/database/libkea-database.la \
+ $(top_builddir)/src/lib/cc/libkea-cc.la \
+ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+ $(top_builddir)/src/lib/dns/libkea-dns++.la \
+ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \
+ $(top_builddir)/src/lib/log/libkea-log.la \
+ $(top_builddir)/src/lib/util/libkea-util.la \
+ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-lib_hooksLTLIBRARIES: $(lib_hooks_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_hooks_LTLIBRARIES)'; test -n "$(lib_hooksdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(lib_hooksdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(lib_hooksdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(lib_hooksdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(lib_hooksdir)"; \
+ }
+
+uninstall-lib_hooksLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_hooks_LTLIBRARIES)'; test -n "$(lib_hooksdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(lib_hooksdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(lib_hooksdir)/$$f"; \
+ done
+
+clean-lib_hooksLTLIBRARIES:
+ -test -z "$(lib_hooks_LTLIBRARIES)" || rm -f $(lib_hooks_LTLIBRARIES)
+ @list='$(lib_hooks_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libdhcp_pgsql_cb.la: $(libdhcp_pgsql_cb_la_OBJECTS) $(libdhcp_pgsql_cb_la_DEPENDENCIES) $(EXTRA_libdhcp_pgsql_cb_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libdhcp_pgsql_cb_la_LINK) -rpath $(lib_hooksdir) $(libdhcp_pgsql_cb_la_OBJECTS) $(libdhcp_pgsql_cb_la_LIBADD) $(LIBS)
+
+libpgsqlcb.la: $(libpgsqlcb_la_OBJECTS) $(libpgsqlcb_la_DEPENDENCIES) $(EXTRA_libpgsqlcb_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libpgsqlcb_la_LINK) $(libpgsqlcb_la_OBJECTS) $(libpgsqlcb_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpgsqlcb_la-version.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+libpgsqlcb_la-pgsql_cb_callouts.lo: pgsql_cb_callouts.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_callouts.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Tpo -c -o libpgsqlcb_la-pgsql_cb_callouts.lo `test -f 'pgsql_cb_callouts.cc' || echo '$(srcdir)/'`pgsql_cb_callouts.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_callouts.cc' object='libpgsqlcb_la-pgsql_cb_callouts.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_callouts.lo `test -f 'pgsql_cb_callouts.cc' || echo '$(srcdir)/'`pgsql_cb_callouts.cc
+
+libpgsqlcb_la-pgsql_cb_dhcp4.lo: pgsql_cb_dhcp4.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_dhcp4.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Tpo -c -o libpgsqlcb_la-pgsql_cb_dhcp4.lo `test -f 'pgsql_cb_dhcp4.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4.cc' object='libpgsqlcb_la-pgsql_cb_dhcp4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_dhcp4.lo `test -f 'pgsql_cb_dhcp4.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4.cc
+
+libpgsqlcb_la-pgsql_cb_dhcp6.lo: pgsql_cb_dhcp6.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_dhcp6.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Tpo -c -o libpgsqlcb_la-pgsql_cb_dhcp6.lo `test -f 'pgsql_cb_dhcp6.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6.cc' object='libpgsqlcb_la-pgsql_cb_dhcp6.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_dhcp6.lo `test -f 'pgsql_cb_dhcp6.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6.cc
+
+libpgsqlcb_la-pgsql_cb_impl.lo: pgsql_cb_impl.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_impl.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Tpo -c -o libpgsqlcb_la-pgsql_cb_impl.lo `test -f 'pgsql_cb_impl.cc' || echo '$(srcdir)/'`pgsql_cb_impl.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_impl.cc' object='libpgsqlcb_la-pgsql_cb_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_impl.lo `test -f 'pgsql_cb_impl.cc' || echo '$(srcdir)/'`pgsql_cb_impl.cc
+
+libpgsqlcb_la-pgsql_cb_messages.lo: pgsql_cb_messages.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_messages.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Tpo -c -o libpgsqlcb_la-pgsql_cb_messages.lo `test -f 'pgsql_cb_messages.cc' || echo '$(srcdir)/'`pgsql_cb_messages.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_messages.cc' object='libpgsqlcb_la-pgsql_cb_messages.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_messages.lo `test -f 'pgsql_cb_messages.cc' || echo '$(srcdir)/'`pgsql_cb_messages.cc
+
+libpgsqlcb_la-pgsql_cb_log.lo: pgsql_cb_log.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-pgsql_cb_log.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Tpo -c -o libpgsqlcb_la-pgsql_cb_log.lo `test -f 'pgsql_cb_log.cc' || echo '$(srcdir)/'`pgsql_cb_log.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Tpo $(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_log.cc' object='libpgsqlcb_la-pgsql_cb_log.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-pgsql_cb_log.lo `test -f 'pgsql_cb_log.cc' || echo '$(srcdir)/'`pgsql_cb_log.cc
+
+libpgsqlcb_la-version.lo: version.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -MT libpgsqlcb_la-version.lo -MD -MP -MF $(DEPDIR)/libpgsqlcb_la-version.Tpo -c -o libpgsqlcb_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpgsqlcb_la-version.Tpo $(DEPDIR)/libpgsqlcb_la-version.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='version.cc' object='libpgsqlcb_la-version.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpgsqlcb_la_CPPFLAGS) $(CPPFLAGS) $(libpgsqlcb_la_CXXFLAGS) $(CXXFLAGS) -c -o libpgsqlcb_la-version.lo `test -f 'version.cc' || echo '$(srcdir)/'`version.cc
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(lib_hooksdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-lib_hooksLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-version.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-lib_hooksLTLIBRARIES
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_callouts.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp4.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_dhcp6.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_impl.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_log.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-pgsql_cb_messages.Plo
+ -rm -f ./$(DEPDIR)/libpgsqlcb_la-version.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic \
+ maintainer-clean-local
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-lib_hooksLTLIBRARIES
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-am clean clean-generic \
+ clean-lib_hooksLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-lib_hooksLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic \
+ maintainer-clean-local mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-lib_hooksLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# If we want to get rid of all generated messages files, we need to use
+# make maintainer-clean. The proper way to introduce custom commands for
+# that operation is to define maintainer-clean-local target. However,
+# make maintainer-clean also removes Makefile, so running configure script
+# is required. To make it easy to rebuild messages without going through
+# reconfigure, a new target messages-clean has been added.
+maintainer-clean-local:
+ rm -f pgsql_cb_messages.h pgsql_cb_messages.cc
+
+# To regenerate messages files, one can do:
+#
+# make messages-clean
+# make messages
+#
+# This is needed only when a .mes file is modified.
+messages-clean: maintainer-clean-local
+
+# Define rule to build logging source files from message file
+@GENERATE_MESSAGES_TRUE@messages: pgsql_cb_messages.h pgsql_cb_messages.cc
+@GENERATE_MESSAGES_TRUE@ @echo Message files regenerated
+
+@GENERATE_MESSAGES_TRUE@pgsql_cb_messages.h pgsql_cb_messages.cc: pgsql_cb_messages.mes
+@GENERATE_MESSAGES_TRUE@ $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
+
+@GENERATE_MESSAGES_FALSE@messages pgsql_cb_messages.h pgsql_cb_messages.cc:
+@GENERATE_MESSAGES_FALSE@ @echo Messages generation disabled. Configure with --enable-generate-messages to enable it.
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am
new file mode 100644
index 0000000..1d6f178
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.am
@@ -0,0 +1,56 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/pgsql_cb -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DLIBDHCP_PGSQL_CB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/pgsql_cb/.libs/libdhcp_pgsql_cb.so\"
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+EXTRA_DIST =
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+if HAVE_GTEST
+
+TESTS = hook_load_unittests
+
+hook_load_unittests_SOURCES =
+hook_load_unittests_SOURCES += load_unload_unittests.cc
+hook_load_unittests_SOURCES += run_unittests.cc
+hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/pgsql/libkea-pgsql.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
+hook_load_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+hook_load_unittests_LDADD += $(LOG4CPLUS_LIBS)
+hook_load_unittests_LDADD += $(CRYPTO_LIBS)
+hook_load_unittests_LDADD += $(BOOST_LIBS)
+hook_load_unittests_LDADD += $(GTEST_LDADD)
+
+noinst_PROGRAMS = $(TESTS)
+
+endif
diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in
new file mode 100644
index 0000000..8bf1824
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/libloadtests/Makefile.in
@@ -0,0 +1,1032 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_GTEST_TRUE@TESTS = hook_load_unittests$(EXEEXT)
+@HAVE_GTEST_TRUE@noinst_PROGRAMS = $(am__EXEEXT_1)
+subdir = src/hooks/dhcp/pgsql_cb/libloadtests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_cpp20.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_netconf.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_GTEST_TRUE@am__EXEEXT_1 = hook_load_unittests$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+am__hook_load_unittests_SOURCES_DIST = load_unload_unittests.cc \
+ run_unittests.cc
+@HAVE_GTEST_TRUE@am_hook_load_unittests_OBJECTS = hook_load_unittests-load_unload_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ hook_load_unittests-run_unittests.$(OBJEXT)
+hook_load_unittests_OBJECTS = $(am_hook_load_unittests_OBJECTS)
+am__DEPENDENCIES_1 =
+@HAVE_GTEST_TRUE@hook_load_unittests_DEPENDENCIES = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+hook_load_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) \
+ $(hook_load_unittests_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = \
+ ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po \
+ ./$(DEPDIR)/hook_load_unittests-run_unittests.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(hook_load_unittests_SOURCES)
+DIST_SOURCES = $(am__hook_load_unittests_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@
+DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@
+DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_NETCONF = @HAVE_NETCONF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@
+LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@
+LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@
+LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@
+LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@
+LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@
+LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@
+LIBYANG_LIBS = @LIBYANG_LIBS@
+LIBYANG_PREFIX = @LIBYANG_PREFIX@
+LIBYANG_VERSION = @LIBYANG_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_PLUGINS_PATH = @SR_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@
+SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@
+SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@
+SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_PREFIX = @SYSREPO_PREFIX@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = .
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \
+ -I$(top_builddir)/src/hooks/dhcp/pgsql_cb \
+ -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb $(BOOST_INCLUDES) \
+ -DLIBDHCP_PGSQL_CB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/pgsql_cb/.libs/libdhcp_pgsql_cb.so\"
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static
+EXTRA_DIST =
+CLEANFILES = *.gcno *.gcda
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+@HAVE_GTEST_TRUE@hook_load_unittests_SOURCES = \
+@HAVE_GTEST_TRUE@ load_unload_unittests.cc run_unittests.cc
+@HAVE_GTEST_TRUE@hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+@HAVE_GTEST_TRUE@hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+@HAVE_GTEST_TRUE@hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \
+@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/libloadtests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/libloadtests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+hook_load_unittests$(EXEEXT): $(hook_load_unittests_OBJECTS) $(hook_load_unittests_DEPENDENCIES) $(EXTRA_hook_load_unittests_DEPENDENCIES)
+ @rm -f hook_load_unittests$(EXEEXT)
+ $(AM_V_CXXLD)$(hook_load_unittests_LINK) $(hook_load_unittests_OBJECTS) $(hook_load_unittests_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook_load_unittests-run_unittests.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+hook_load_unittests-load_unload_unittests.o: load_unload_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-load_unload_unittests.o -MD -MP -MF $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo -c -o hook_load_unittests-load_unload_unittests.o `test -f 'load_unload_unittests.cc' || echo '$(srcdir)/'`load_unload_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo $(DEPDIR)/hook_load_unittests-load_unload_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_unload_unittests.cc' object='hook_load_unittests-load_unload_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-load_unload_unittests.o `test -f 'load_unload_unittests.cc' || echo '$(srcdir)/'`load_unload_unittests.cc
+
+hook_load_unittests-load_unload_unittests.obj: load_unload_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-load_unload_unittests.obj -MD -MP -MF $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo -c -o hook_load_unittests-load_unload_unittests.obj `if test -f 'load_unload_unittests.cc'; then $(CYGPATH_W) 'load_unload_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/load_unload_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-load_unload_unittests.Tpo $(DEPDIR)/hook_load_unittests-load_unload_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_unload_unittests.cc' object='hook_load_unittests-load_unload_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-load_unload_unittests.obj `if test -f 'load_unload_unittests.cc'; then $(CYGPATH_W) 'load_unload_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/load_unload_unittests.cc'; fi`
+
+hook_load_unittests-run_unittests.o: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/hook_load_unittests-run_unittests.Tpo -c -o hook_load_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-run_unittests.Tpo $(DEPDIR)/hook_load_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='hook_load_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+
+hook_load_unittests-run_unittests.obj: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -MT hook_load_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/hook_load_unittests-run_unittests.Tpo -c -o hook_load_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/hook_load_unittests-run_unittests.Tpo $(DEPDIR)/hook_load_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='hook_load_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hook_load_unittests_CPPFLAGS) $(CPPFLAGS) $(hook_load_unittests_CXXFLAGS) $(CXXFLAGS) -c -o hook_load_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po
+ -rm -f ./$(DEPDIR)/hook_load_unittests-run_unittests.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/hook_load_unittests-load_unload_unittests.Po
+ -rm -f ./$(DEPDIR)/hook_load_unittests-run_unittests.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-TESTS check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc
new file mode 100644
index 0000000..2791c3d
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/// @file This file contains tests which exercise the load and unload
+/// functions in the ddns tuning hook library. In order to test the load
+/// function, one must be able to pass it hook library parameters. The
+/// the only way to populate these parameters is by actually loading the
+/// library via HooksManager::loadLibraries().
+
+#include <config.h>
+
+#include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <hooks/hooks_manager.h>
+#include <process/daemon.h>
+#include <testutils/gtest_utils.h>
+#include <testutils/lib_load_test_fixture.h>
+
+#include <gtest/gtest.h>
+#include <errno.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::hooks;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::process;
+
+namespace {
+
+/// @brief Test fixture for testing loading and unloading the PgSQL cb library
+class PgSqlCbLibLoadTest : public isc::test::LibLoadTest {
+public:
+ /// @brief Constructor
+ PgSqlCbLibLoadTest() : LibLoadTest(LIBDHCP_PGSQL_CB_SO) {
+ }
+
+ /// @brief Destructor
+ virtual ~PgSqlCbLibLoadTest() {
+ unloadLibraries();
+ }
+};
+
+// Simple V4 test that checks the library can be loaded and unloaded several times.
+TEST_F(PgSqlCbLibLoadTest, validLoad4) {
+ validDaemonTest("kea-dhcp4");
+}
+
+// Simple V6 test that checks the library can be loaded and unloaded several times.
+TEST_F(PgSqlCbLibLoadTest, validLoad6) {
+ validDaemonTest("kea-dhcp6", AF_INET6);
+}
+
+// Simple V6 test that checks the library cannot by loaded by invalid daemons.
+TEST_F(PgSqlCbLibLoadTest, invalidDaemonLoad) {
+ invalidDaemonTest("kea-ctrl-agent");
+ invalidDaemonTest("kea-dhcp-ddns");
+ invalidDaemonTest("bogus");
+}
+
+} // end of anonymous namespace
diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc b/src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc
new file mode 100644
index 0000000..d9e195d
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/libloadtests/run_unittests.cc
@@ -0,0 +1,20 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the End User License
+// Agreement. See COPYING file in the premium/ directory.
+
+#include <config.h>
+
+#include <log/logger_support.h>
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+
+ int result = RUN_ALL_TESTS();
+
+ return (result);
+}
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc
new file mode 100644
index 0000000..06727e1
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc
@@ -0,0 +1,122 @@
+// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Functions accessed by the hooks framework use C linkage to avoid the name
+// mangling that accompanies use of the C++ compiler as well as to avoid
+// issues related to namespaces.
+
+#include <config.h>
+
+#include <dhcpsrv/cfgmgr.h>
+#include <hooks/hooks.h>
+#include <process/daemon.h>
+#include <pgsql_cb_impl.h>
+
+#include <pgsql_cb_dhcp4.h>
+#include <pgsql_cb_dhcp6.h>
+#include <pgsql_cb_log.h>
+
+#include <sstream>
+#include <string>
+
+using namespace isc::cb;
+using namespace isc::dhcp;
+using namespace isc::hooks;
+using namespace isc::log;
+using namespace isc::process;
+using namespace std;
+
+extern "C" {
+
+/// @brief This function is called when the library is loaded.
+///
+/// @param handle library handle
+/// @return 0 when initialization is successful, 1 otherwise
+
+int load(LibraryHandle& /* handle */) {
+ // Make the hook library not loadable by d2 or ca.
+ uint16_t family = CfgMgr::instance().getFamily();
+ const std::string& proc_name = Daemon::getProcName();
+ if (family == AF_INET) {
+ if (proc_name != "kea-dhcp4") {
+ isc_throw(isc::Unexpected, "Bad process name: " << proc_name
+ << ", expected kea-dhcp4");
+ }
+ } else {
+ if (proc_name != "kea-dhcp6") {
+ isc_throw(isc::Unexpected, "Bad process name: " << proc_name
+ << ", expected kea-dhcp6");
+ }
+ }
+
+ LOG_INFO(pgsql_cb_logger, PGSQL_CB_INIT_OK);
+ // Register PostgreSQL CB factories with CB Managers
+ isc::dhcp::PgSqlConfigBackendDHCPv4::registerBackendType();
+ isc::dhcp::PgSqlConfigBackendDHCPv6::registerBackendType();
+
+ return (0);
+}
+
+/// @brief This function is called by the DHCPv4 server when it is configured.
+///
+/// The only purpose of this callout is to retrieve io_service_ reference.
+///
+/// @param handle callout handle passed to the callout.
+/// @return 0 on success, 1 otherwise.
+int dhcp4_srv_configured(CalloutHandle& handle) {
+ isc::asiolink::IOServicePtr io_service;
+ handle.getArgument("io_context", io_service);
+ if (!io_service) {
+ const string error("Error: io_context is null");
+ handle.setArgument("error", error);
+ handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
+ return (1);
+ }
+ isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service);
+ return (0);
+}
+
+/// @brief This function is called by the DHCPv6 server when it is configured.
+///
+/// The only purpose of this callout is to retrieve io_service_ reference.
+///
+/// @param handle callout handle passed to the callout.
+/// @return 0 on success, 1 otherwise.
+int dhcp6_srv_configured(CalloutHandle& handle) {
+ isc::asiolink::IOServicePtr io_service;
+ handle.getArgument("io_context", io_service);
+ if (!io_service) {
+ const string error("Error: io_context is null");
+ handle.setArgument("error", error);
+ handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
+ return (1);
+ }
+ isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service);
+ return (0);
+}
+
+/// @brief This function is called when the library is unloaded.
+///
+/// @return 0 if deregistration was successful, 1 otherwise
+int unload() {
+ LOG_INFO(pgsql_cb_logger, PGSQL_CB_DEINIT_OK);
+ // Unregister the factories and remove PostgreSQL backends
+ isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType();
+ isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType();
+ return (0);
+}
+
+/// @brief This function is called to retrieve the multi-threading compatibility.
+///
+/// @note: the compatibility is based on the assumption this hook library
+/// is always called from the main thread.
+///
+/// @return 1 which means compatible with multi-threading.
+int multi_threading_compatible() {
+ return (1);
+}
+
+} // end extern "C"
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc
new file mode 100644
index 0000000..9dcac75
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.cc
@@ -0,0 +1,5238 @@
+// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <pgsql_cb_dhcp4.h>
+#include <pgsql_cb_impl.h>
+#include <pgsql_query_macros_dhcp.h>
+#include <cc/data.h>
+#include <config_backend/constants.h>
+#include <database/database_connection.h>
+#include <database/db_exceptions.h>
+#include <dhcp/classify.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option_data_types.h>
+#include <dhcp/option_space.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/config_backend_dhcp4_mgr.h>
+#include <dhcpsrv/network.h>
+#include <dhcpsrv/pool.h>
+#include <dhcpsrv/lease.h>
+#include <dhcpsrv/timer_mgr.h>
+#include <dhcpsrv/parsers/client_class_def_parser.h>
+#include <util/buffer.h>
+#include <util/boost_time_utils.h>
+#include <util/multi_threading_mgr.h>
+#include <pgsql/pgsql_connection.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/pointer_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+
+using namespace isc::cb;
+using namespace isc::db;
+using namespace isc::data;
+using namespace isc::asiolink;
+using namespace isc::log;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Implementation of the PostgreSQL Configuration Backend.
+class PgSqlConfigBackendDHCPv4Impl : public PgSqlConfigBackendImpl {
+public:
+
+ /// @brief Statement tags.
+ ///
+ /// The contents of the enum are indexes into the list of SQL statements.
+ /// It is assumed that the order is such that the indices of statements
+ /// reading the database are less than those of statements modifying the
+ /// database.
+ enum StatementIndex {
+ CREATE_AUDIT_REVISION,
+ CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ GET_GLOBAL_PARAMETER4,
+ GET_ALL_GLOBAL_PARAMETERS4,
+ GET_MODIFIED_GLOBAL_PARAMETERS4,
+ GET_SUBNET4_ID_NO_TAG,
+ GET_SUBNET4_ID_ANY,
+ GET_SUBNET4_ID_UNASSIGNED,
+ GET_SUBNET4_PREFIX_NO_TAG,
+ GET_SUBNET4_PREFIX_ANY,
+ GET_SUBNET4_PREFIX_UNASSIGNED,
+ GET_ALL_SUBNETS4,
+ GET_ALL_SUBNETS4_UNASSIGNED,
+ GET_MODIFIED_SUBNETS4,
+ GET_MODIFIED_SUBNETS4_UNASSIGNED,
+ GET_SHARED_NETWORK_SUBNETS4,
+ GET_POOL4_RANGE,
+ GET_POOL4_RANGE_ANY,
+ GET_SHARED_NETWORK4_NAME_NO_TAG,
+ GET_SHARED_NETWORK4_NAME_ANY,
+ GET_SHARED_NETWORK4_NAME_UNASSIGNED,
+ GET_ALL_SHARED_NETWORKS4,
+ GET_ALL_SHARED_NETWORKS4_UNASSIGNED,
+ GET_MODIFIED_SHARED_NETWORKS4,
+ GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED,
+ GET_OPTION_DEF4_CODE_SPACE,
+ GET_ALL_OPTION_DEFS4,
+ GET_MODIFIED_OPTION_DEFS4,
+ GET_OPTION4_CODE_SPACE,
+ GET_ALL_OPTIONS4,
+ GET_MODIFIED_OPTIONS4,
+ GET_OPTION4_SUBNET_ID_CODE_SPACE,
+ GET_OPTION4_POOL_ID_CODE_SPACE,
+ GET_OPTION4_SHARED_NETWORK_CODE_SPACE,
+ GET_CLIENT_CLASS4_NAME,
+ GET_ALL_CLIENT_CLASSES4,
+ GET_ALL_CLIENT_CLASSES4_UNASSIGNED,
+ GET_MODIFIED_CLIENT_CLASSES4,
+ GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED,
+ GET_AUDIT_ENTRIES4_TIME,
+ GET_SERVER4,
+ GET_ALL_SERVERS4,
+ INSERT_GLOBAL_PARAMETER4,
+ INSERT_GLOBAL_PARAMETER4_SERVER,
+ INSERT_SUBNET4,
+ INSERT_SUBNET4_SERVER,
+ INSERT_POOL4,
+ INSERT_SHARED_NETWORK4,
+ INSERT_SHARED_NETWORK4_SERVER,
+ INSERT_OPTION_DEF4,
+ INSERT_OPTION_DEF4_CLIENT_CLASS,
+ INSERT_OPTION_DEF4_SERVER,
+ INSERT_OPTION4,
+ INSERT_OPTION4_SERVER,
+ INSERT_CLIENT_CLASS4,
+ INSERT_CLIENT_CLASS4_SERVER,
+ INSERT_CLIENT_CLASS4_DEPENDENCY,
+ INSERT_SERVER4,
+ UPDATE_GLOBAL_PARAMETER4,
+ UPDATE_SUBNET4,
+ UPDATE_SHARED_NETWORK4,
+ UPDATE_OPTION_DEF4,
+ UPDATE_OPTION_DEF4_CLIENT_CLASS,
+ UPDATE_OPTION4,
+ UPDATE_OPTION4_SUBNET_ID,
+ UPDATE_OPTION4_POOL_ID,
+ UPDATE_OPTION4_SHARED_NETWORK,
+ UPDATE_OPTION4_CLIENT_CLASS,
+ UPDATE_CLIENT_CLASS4,
+ UPDATE_CLIENT_CLASS4_SAME_POSITION,
+ UPDATE_SERVER4,
+ DELETE_GLOBAL_PARAMETER4,
+ DELETE_ALL_GLOBAL_PARAMETERS4,
+ DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED,
+ DELETE_SUBNET4_ID_WITH_TAG,
+ DELETE_SUBNET4_ID_ANY,
+ DELETE_SUBNET4_PREFIX_WITH_TAG,
+ DELETE_SUBNET4_PREFIX_ANY,
+ DELETE_ALL_SUBNETS4,
+ DELETE_ALL_SUBNETS4_UNASSIGNED,
+ DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME,
+ DELETE_SUBNET4_SERVER,
+ DELETE_POOLS4,
+ DELETE_SHARED_NETWORK4_NAME_WITH_TAG,
+ DELETE_SHARED_NETWORK4_NAME_ANY,
+ DELETE_ALL_SHARED_NETWORKS4,
+ DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED,
+ DELETE_SHARED_NETWORK4_SERVER,
+ DELETE_OPTION_DEF4_CODE_NAME,
+ DELETE_ALL_OPTION_DEFS4,
+ DELETE_ALL_OPTION_DEFS4_UNASSIGNED,
+ DELETE_OPTION_DEFS4_CLIENT_CLASS,
+ DELETE_OPTION4,
+ DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED,
+ DELETE_OPTION4_SUBNET_ID,
+ DELETE_OPTION4_POOL_RANGE,
+ DELETE_OPTION4_SHARED_NETWORK,
+ DELETE_OPTIONS4_SUBNET_ID_PREFIX,
+ DELETE_OPTIONS4_SHARED_NETWORK,
+ DELETE_OPTIONS4_CLIENT_CLASS,
+ DELETE_CLIENT_CLASS4_DEPENDENCY,
+ DELETE_CLIENT_CLASS4_SERVER,
+ DELETE_ALL_CLIENT_CLASSES4,
+ DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED,
+ DELETE_CLIENT_CLASS4,
+ DELETE_CLIENT_CLASS4_ANY,
+ DELETE_SERVER4,
+ DELETE_ALL_SERVERS4,
+ GET_LAST_INSERT_ID4,
+ NUM_STATEMENTS
+ };
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ explicit PgSqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap&
+ parameters);
+
+ /// @brief Destructor.
+ ~PgSqlConfigBackendDHCPv4Impl();
+
+ /// @brief Fetches the SQL statement for a given statement index.
+ ///
+ /// @param index index of the desired statement.
+ /// @throw BadValue if there is no statement corresponding to
+ /// the index.
+ virtual PgSqlTaggedStatement& getStatement(size_t index) const;
+
+ /// @brief Sends query to retrieve global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the parameter to be retrieved.
+ ///
+ /// @return Pointer to the retrieved value or null if such parameter
+ /// doesn't exist.
+ StampedValuePtr getGlobalParameter4(const ServerSelector& server_selector,
+ const std::string& name) {
+ StampedValueCollection parameters;
+
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.add(name);
+
+ getGlobalParameters(GET_GLOBAL_PARAMETER4, in_bindings, parameters);
+ }
+
+ return (parameters.empty() ? StampedValuePtr() : *parameters.begin());
+ }
+
+ /// @brief Sends query to insert or update global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param value StampedValue describing the parameter to create/update.
+ void createUpdateGlobalParameter4(const db::ServerSelector& server_selector,
+ const StampedValuePtr& value) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "creating or updating global parameter");
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(value->getName());
+ in_bindings.addTempString(value->getValue());
+ in_bindings.add(value->getType()),
+ in_bindings.addTimestamp(value->getModificationTime()),
+ in_bindings.addTempString(tag);
+ in_bindings.addTempString(value->getName());
+
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "global parameter set",
+ false);
+
+ // Try to update the existing row.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4,
+ in_bindings) == 0) {
+ // No such parameter found, so let's insert it. We have to adjust the
+ // bindings collection to match the prepared statement for insert.
+ in_bindings.popBack();
+ in_bindings.popBack();
+
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4,
+ in_bindings);
+
+ // Successfully inserted global parameter. Now, we have to associate it
+ // with the server tag.
+ PsqlBindArray attach_bindings;
+ uint64_t pid = getLastInsertId("dhcp4_global_parameter", "id");
+ attach_bindings.add(pid); // id of newly inserted global.
+ attach_bindings.addTimestamp(value->getModificationTime());
+ attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER,
+ server_selector, attach_bindings);
+ }
+
+ transaction.commit();
+ }
+
+ /// @brief Sends query to the database to retrieve multiple subnets.
+ ///
+ /// Query should order subnets by subnet_id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] subnets Reference to the container where fetched subnets
+ /// will be inserted.
+ void getSubnets4(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ Subnet4Collection& subnets) {
+ uint64_t last_pool_id = 0;
+ uint64_t last_pool_option_id = 0;
+ uint64_t last_option_id = 0;
+ Pool4Ptr last_pool;
+ std::string last_tag;
+
+ // Execute actual query.
+ selectQuery(index, in_bindings,
+ [this, &subnets, &last_pool, &last_pool_id,
+ &last_pool_option_id, &last_option_id, &last_tag](PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get pointer to the last subnet in the collection.
+ Subnet4Ptr last_subnet;
+ if (!subnets.empty()) {
+ last_subnet = *subnets.rbegin();
+ }
+ // Subnet_id is column 0.
+ SubnetID subnet_id = worker.getInt(0) ;
+
+ // Subnet has been returned. Assuming that subnets are ordered by
+ // subnet identifier, if the subnet identifier of the current row
+ // is different than the subnet identifier of the previously returned
+ // row, it means that we have to construct new subnet object.
+ if (!last_subnet || (last_subnet->getID() != subnet_id)) {
+ // Reset per subnet component tracking and server tag because
+ // we're now starting to process a new subnet.
+ last_pool_id = 0;
+ last_pool_option_id = 0;
+ last_option_id = 0;
+ last_pool.reset();
+ last_tag.clear();
+
+ // Get subnet parameters required by the constructor first.
+
+ // subnet_prefix at 1.
+ std::string subnet_prefix = worker.getString(1);
+ auto prefix_pair = Subnet4::parsePrefix(subnet_prefix);
+
+ // renew_timer at 13.
+ auto renew_timer = worker.getTriplet(13);
+
+ // rebind_timer at 11.
+ auto rebind_timer = worker.getTriplet(11);
+
+ // valid_lifetime at 19.
+ // min_valid_lifetime at 55.
+ // max_valid_lifetime at 56.
+ auto valid_lifetime = worker.getTriplet(19, 55, 56);
+
+ // Create subnet with basic settings.
+ last_subnet = Subnet4::create(prefix_pair.first, prefix_pair.second,
+ renew_timer, rebind_timer,
+ valid_lifetime, subnet_id);
+
+ // Get other subnet parameters.
+ // 4o6_interface at 2.
+ if (!worker.isColumnNull(2)) {
+ last_subnet->get4o6().setIface4o6(worker.getString(2));
+ }
+
+ // 4o6_interface_id at 3.
+ if (!worker.isColumnNull(3)) {
+ std::string dhcp4o6_interface_id = worker.getString(3);
+ OptionBuffer dhcp4o6_interface_id_buf(dhcp4o6_interface_id.begin(),
+ dhcp4o6_interface_id.end());
+ OptionPtr option_dhcp4o6_interface_id =
+ Option::create(Option::V6, D6O_INTERFACE_ID, dhcp4o6_interface_id_buf);
+ last_subnet->get4o6().setInterfaceId(option_dhcp4o6_interface_id);
+ }
+
+ // 4o6_subnet at 4.
+ if (!worker.isColumnNull(4)) {
+ std::pair<IOAddress, uint8_t> dhcp4o6_subnet_prefix_pair =
+ Subnet6::parsePrefix(worker.getString(4));
+ last_subnet->get4o6().setSubnet4o6(dhcp4o6_subnet_prefix_pair.first,
+ dhcp4o6_subnet_prefix_pair.second);
+ }
+
+ // boot_file_name at 5.
+ if (!worker.isColumnNull(5)) {
+ last_subnet->setFilename(worker.getString(5));
+ }
+
+ // client_class at 6.
+ if (!worker.isColumnNull(6)) {
+ last_subnet->allowClientClass(worker.getString(6));
+ }
+
+ // interface at 7.
+ if (!worker.isColumnNull(7)) {
+ last_subnet->setIface(worker.getString(7));
+ }
+
+ // match_client_id at 8.
+ if (!worker.isColumnNull(8)) {
+ last_subnet->setMatchClientId(worker.getBool(8));
+ }
+
+ // modification_ts at 9.
+ last_subnet->setModificationTime(worker.getTimestamp(9));
+
+ // next_server at 10.
+ if (!worker.isColumnNull(10)) {
+ last_subnet->setSiaddr(worker.getInet4(10));
+ }
+
+ // rebind_timer at 11 (fetched before subnet create).
+
+ // Relay addresses at 12.
+ setRelays(worker, 12, *last_subnet);
+
+ // renew_timer at 13 (fetched before subnet create).
+
+ // require_client_classes at 14.
+ setRequiredClasses(worker, 14, [&last_subnet](const std::string& class_name) {
+ last_subnet->requireClientClass(class_name);
+ });
+
+ // reservations_global at 15.
+ if (!worker.isColumnNull(15)) {
+ last_subnet->setReservationsGlobal(worker.getBool(15));
+ }
+
+ // server_hostname at 16.
+ if (!worker.isColumnNull(16)) {
+ last_subnet->setSname(worker.getString(16));
+ }
+
+ // shared_network_name at 17.
+ if (!worker.isColumnNull(17)) {
+ last_subnet->setSharedNetworkName(worker.getString(17));
+ }
+
+ // user_context at 18.
+ if (!worker.isColumnNull(18)) {
+ ElementPtr user_context = worker.getJSON(18);
+ if (user_context) {
+ last_subnet->setContext(user_context);
+ }
+ }
+
+ // valid_lifetime at 19 (fetched before subnet create).
+
+ // pool and options from 20 to 50.
+
+ // calculate_tee_times at 51.
+ if (!worker.isColumnNull(51)) {
+ last_subnet->setCalculateTeeTimes(worker.getBool(51));
+ }
+
+ // t1_percent at 52.
+ if (!worker.isColumnNull(52)) {
+ last_subnet->setT1Percent(worker.getDouble(52));
+ }
+
+ // t2_percent at 53.
+ if (!worker.isColumnNull(53)) {
+ last_subnet->setT2Percent(worker.getDouble(53));
+ }
+
+ // authoritative at 54.
+ if (!worker.isColumnNull(54)) {
+ last_subnet->setAuthoritative(worker.getBool(54));
+ }
+
+ // min_valid_lifetime at 55 (fetched as part of triplet).
+ // max_valid_lifetime at 56 (fetched as part of triplet).
+
+ // pool client_class, require_client_classes and user_context
+ // from 57 to 59.
+
+ // ddns_send_updates at 60.
+ if (!worker.isColumnNull(60)) {
+ last_subnet->setDdnsSendUpdates(worker.getBool(60));
+ }
+
+ // ddns_override_no_update at 61.
+ if (!worker.isColumnNull(61)) {
+ last_subnet->setDdnsOverrideNoUpdate(worker.getBool(61));
+ }
+
+ // ddns_override_client_update at 62.
+ if (!worker.isColumnNull(62)) {
+ last_subnet->setDdnsOverrideClientUpdate(worker.getBool(62));
+ }
+
+ // ddns_replace_client_name at 63.
+ if (!worker.isColumnNull(63)) {
+ last_subnet->setDdnsReplaceClientNameMode(
+ static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(63)));
+ }
+
+ // ddns_generated_prefix at 64.
+ if (!worker.isColumnNull(64)) {
+ last_subnet->setDdnsGeneratedPrefix(worker.getString(64));
+ }
+
+ // ddns_qualifying_suffix at 65.
+ if (!worker.isColumnNull(65)) {
+ last_subnet->setDdnsQualifyingSuffix(worker.getString(65));
+ }
+
+ // reservations_in_subnet at 66.
+ if (!worker.isColumnNull(66)) {
+ last_subnet->setReservationsInSubnet(worker.getBool(66));
+ }
+
+ // reservations_out_of_pool at 67.
+ if (!worker.isColumnNull(67)) {
+ last_subnet->setReservationsOutOfPool(worker.getBool(67));
+ }
+
+ // cache_threshold at 68.
+ if (!worker.isColumnNull(68)) {
+ last_subnet->setCacheThreshold(worker.getDouble(68));
+ }
+
+ // cache_max_age at 69.
+ if (!worker.isColumnNull(69)) {
+ last_subnet->setCacheMaxAge(worker.getInt(69));
+ }
+
+ // offer_lifetime at 70.
+ if (!worker.isColumnNull(70)) {
+ last_subnet->setOfferLft(worker.getInt(70));
+ }
+
+ // allocator at 71.
+ if (!worker.isColumnNull(71)) {
+ last_subnet->setAllocatorType(worker.getString(71));
+ }
+
+ // server_tag at 72.
+
+ // Subnet ready. Add it to the list.
+ auto ret = subnets.insert(last_subnet);
+
+ // subnets is a multi index container with unique indexes
+ // but these indexes are unique too in the database,
+ // so this is for sanity only.
+ if (!ret.second) {
+ isc_throw(Unexpected, "add subnet failed");
+ }
+ }
+
+ // Check for new server tags at 71.
+ if (!worker.isColumnNull(72)) {
+ std::string new_tag = worker.getString(72);
+ if (last_tag != new_tag) {
+ if (!new_tag.empty() && !last_subnet->hasServerTag(ServerTag(new_tag))) {
+ last_subnet->setServerTag(new_tag);
+ }
+
+ last_tag = new_tag;
+ }
+ }
+
+ // If the row contains information about the pool and it appears to be
+ // new pool entry (checked by comparing pool id), let's create the new
+ // pool and add it to the subnet.
+ // pool id at 20.
+ // pool start_address at 21.
+ // pool end_address at 22.
+ // pool subnet_id at 23 (ignored)
+ // pool modification_ts at 24 (ignored)
+ if (!worker.isColumnNull(20) &&
+ (worker.getInet4(21) != 0) &&
+ (worker.getInet4(22) != 0) &&
+ (worker.getBigInt(20) > last_pool_id)) {
+ last_pool_id = worker.getBigInt(20);
+ last_pool = Pool4::create(IOAddress(worker.getInet4(21)),
+ IOAddress(worker.getInet4(22)));
+
+ // pool client_class at 57.
+ if (!worker.isColumnNull(57)) {
+ last_pool->allowClientClass(worker.getString(57));
+ }
+
+ // pool require_client_classes at 58.
+ setRequiredClasses(worker, 58, [&last_pool](const std::string& class_name) {
+ last_pool->requireClientClass(class_name);
+ });
+
+ // pool user_context at 59.
+ if (!worker.isColumnNull(59)) {
+ ElementPtr user_context = worker.getJSON(59);
+ if (user_context) {
+ last_pool->setContext(user_context);
+ }
+ }
+
+ last_subnet->addPool(last_pool);
+ }
+
+ // Parse pool-specific option from 25 to 37.
+ if (last_pool && !worker.isColumnNull(25) &&
+ (last_pool_option_id < worker.getBigInt(25))) {
+ last_pool_option_id = worker.getBigInt(25);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 25);
+ if (desc) {
+ last_pool->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+
+ // Parse subnet-specific option from 38 to 50.
+ if (!worker.isColumnNull(38) &&
+ (last_option_id < worker.getBigInt(38))) {
+ last_option_id = worker.getBigInt(38);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 38);
+ if (desc) {
+ last_subnet->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ // Now that we're done fetching the whole subnet, we have to
+ // check if it has matching server tags and toss it if it
+ // doesn't. We skip matching the server tags if we're asking
+ // for ANY subnet.
+ auto& subnet_index = subnets.get<SubnetSubnetIdIndexTag>();
+ tossNonMatchingElements(server_selector, subnet_index);
+ }
+
+ /// @brief Sends query to retrieve single subnet by id.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Subnet identifier.
+ ///
+ /// @return Pointer to the returned subnet or NULL if such subnet
+ /// doesn't exist.
+ Subnet4Ptr getSubnet4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) {
+ if (server_selector.hasMultipleTags()) {
+ isc_throw(InvalidOperation, "expected one server tag to be specified"
+ " while fetching a subnet. Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet_id);
+
+ auto index = GET_SUBNET4_ID_NO_TAG;
+ if (server_selector.amUnassigned()) {
+ index = GET_SUBNET4_ID_UNASSIGNED;
+ } else if (server_selector.amAny()) {
+ index = GET_SUBNET4_ID_ANY;
+ }
+
+ Subnet4Collection subnets;
+ getSubnets4(index, server_selector, in_bindings, subnets);
+
+ return (subnets.empty() ? Subnet4Ptr() : *subnets.begin());
+ }
+
+ /// @brief Sends query to retrieve single subnet by prefix.
+ ///
+ /// The prefix should be in the following format: "192.0.2.0/24".
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Subnet identifier.
+ ///
+ /// @return Pointer to the returned subnet or NULL if such subnet
+ /// doesn't exist.
+ Subnet4Ptr getSubnet4(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) {
+ if (server_selector.hasMultipleTags()) {
+ isc_throw(InvalidOperation, "expected one server tag to be specified"
+ " while fetching a subnet. Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet_prefix);
+
+ auto index = GET_SUBNET4_PREFIX_NO_TAG;
+ if (server_selector.amUnassigned()) {
+ index = GET_SUBNET4_PREFIX_UNASSIGNED;
+ } else if (server_selector.amAny()) {
+ index = GET_SUBNET4_PREFIX_ANY;
+ }
+
+ Subnet4Collection subnets;
+ getSubnets4(index, server_selector, in_bindings, subnets);
+
+ return (subnets.empty() ? Subnet4Ptr() : *subnets.begin());
+ }
+
+ /// @brief Sends query to retrieve all subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] subnets Reference to the subnet collection structure where
+ /// subnets should be inserted.
+ void getAllSubnets4(const ServerSelector& server_selector,
+ Subnet4Collection& subnets) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching all subnets for ANY "
+ "server is not supported");
+ }
+
+ auto index = (server_selector.amUnassigned() ? GET_ALL_SUBNETS4_UNASSIGNED :
+ GET_ALL_SUBNETS4);
+ PsqlBindArray in_bindings;
+ getSubnets4(index, server_selector, in_bindings, subnets);
+ }
+
+ /// @brief Sends query to retrieve modified subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] subnets Reference to the subnet collection structure where
+ /// subnets should be inserted.
+ void getModifiedSubnets4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ Subnet4Collection& subnets) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified subnets for ANY "
+ "server is not supported");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(modification_ts);
+
+ auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SUBNETS4_UNASSIGNED :
+ GET_MODIFIED_SUBNETS4);
+ getSubnets4(index, server_selector, in_bindings, subnets);
+ }
+
+ /// @brief Sends query to retrieve all subnets belonging to a shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network for which the
+ /// subnets should be retrieved.
+ /// @param [out] subnets Reference to the subnet collection structure where
+ /// subnets should be inserted.
+ void getSharedNetworkSubnets4(const ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ Subnet4Collection& subnets) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(shared_network_name);
+ getSubnets4(GET_SHARED_NETWORK_SUBNETS4, server_selector, in_bindings, subnets);
+ }
+
+ /// @brief Sends query to retrieve multiple pools.
+ ///
+ /// Query should order pools by id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] pools Reference to the container where fetched pools
+ /// will be inserted.
+ /// @param [out] pool_ids Identifiers of the pools returned in @c pools
+ /// argument.
+ void getPools(const StatementIndex& index,
+ const PsqlBindArray& in_bindings,
+ PoolCollection& pools,
+ std::vector<uint64_t>& pool_ids) {
+ uint64_t last_pool_id = 0;
+ uint64_t last_pool_option_id = 0;
+ Pool4Ptr last_pool;
+
+ selectQuery(index, in_bindings,
+ [this, &last_pool_id, &last_pool_option_id, &last_pool, &pools, &pool_ids]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Pool id is column 0.
+ auto id = worker.getBigInt(0) ;
+ if (id > last_pool_id) {
+ // pool start_address (1)
+ // pool end_address (2)
+ last_pool_id = id;
+
+ last_pool = Pool4::create(worker.getInet4(1), worker.getInet4(2));
+
+ // pool subnet_id (3) (ignored)
+
+ // pool client_class (4)
+ if (!worker.isColumnNull(4)) {
+ last_pool->allowClientClass(worker.getString(4));
+ }
+
+ // pool require_client_classes (5)
+ setRequiredClasses(worker, 5, [&last_pool](const std::string& class_name) {
+ last_pool->requireClientClass(class_name);
+ });
+
+ // pool user_context (6)
+ if (!worker.isColumnNull(6)) {
+ ElementPtr user_context = worker.getJSON(6);
+ if (user_context) {
+ last_pool->setContext(user_context);
+ }
+ }
+
+ // pool: modification_ts (7) (ignored)
+
+ pools.push_back(last_pool);
+ pool_ids.push_back(last_pool_id);
+ }
+
+ // Parse pool specific option (8).
+ if (last_pool && !worker.isColumnNull(8) &&
+ (last_pool_option_id < worker.getBigInt(8))) {
+ last_pool_option_id = worker.getBigInt(8);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 8);
+ if (desc) {
+ last_pool->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+ }
+
+ /// @brief Sends query to retrieve single pool by address range.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound pool address.
+ /// @param pool_end_address Upper bound pool address.
+ /// @param pool_id Pool identifier for the returned pool.
+ /// @return Pointer to the pool or null if no such pool found.
+ Pool4Ptr getPool4(const ServerSelector& server_selector,
+ const IOAddress& pool_start_address,
+ const IOAddress& pool_end_address,
+ uint64_t& pool_id) {
+ PoolCollection pools;
+ std::vector<uint64_t> pool_ids;
+
+ if (server_selector.amAny()) {
+ PsqlBindArray in_bindings;
+ in_bindings.addInet4(pool_start_address);
+ in_bindings.addInet4(pool_end_address);
+ getPools(GET_POOL4_RANGE_ANY, in_bindings, pools, pool_ids);
+ } else {
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addInet4(pool_start_address);
+ in_bindings.addInet4(pool_end_address);
+
+ getPools(GET_POOL4_RANGE, in_bindings, pools, pool_ids);
+ // Break if something is found?
+ }
+ }
+
+ // Return upon the first pool found.
+ if (!pools.empty()) {
+ pool_id = pool_ids[0];
+ return (boost::dynamic_pointer_cast<Pool4>(*pools.begin()));
+ }
+
+ pool_id = 0;
+
+ return (Pool4Ptr());
+ }
+
+ /// @brief Sends query to insert or update subnet.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the subnet to be inserted or updated.
+ void createUpdateSubnet4(const ServerSelector& server_selector,
+ const Subnet4Ptr& subnet) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "creating or updating a subnet for ANY"
+ " server is not supported");
+
+ } else if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+ in_bindings.addOptional(subnet->get4o6().getIface4o6());
+
+ // Convert DHCPv4o6 interface id to text.
+ OptionPtr dhcp4o6_interface_id = subnet->get4o6().getInterfaceId();
+ if (dhcp4o6_interface_id) {
+ in_bindings.addTempString(std::string(dhcp4o6_interface_id->getData().begin(),
+ dhcp4o6_interface_id->getData().end()));
+
+ } else {
+ in_bindings.addNull();
+ }
+
+ // Convert DHCPv4o6 subnet to text.
+ Optional<std::string> dhcp4o6_subnet;
+ if (!subnet->get4o6().getSubnet4o6().unspecified() &&
+ (!subnet->get4o6().getSubnet4o6().get().first.isV6Zero() ||
+ (subnet->get4o6().getSubnet4o6().get().second != 128u))) {
+ std::ostringstream s;
+ s << subnet->get4o6().getSubnet4o6().get().first << "/"
+ << static_cast<int>(subnet->get4o6().getSubnet4o6().get().second);
+ dhcp4o6_subnet = s.str();
+ }
+
+ in_bindings.addOptional(dhcp4o6_subnet);
+
+ in_bindings.addOptional(subnet->getFilename(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getClientClass(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getIface(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getMatchClientId(Network::Inheritance::NONE));
+ in_bindings.addTimestamp(subnet->getModificationTime());
+ in_bindings.addOptionalInet4(subnet->getSiaddr(Network::Inheritance::NONE));
+ in_bindings.add(subnet->getT2(Network::Inheritance::NONE));
+ addRelayBinding(in_bindings, subnet);
+ in_bindings.add(subnet->getT1(Network::Inheritance::NONE));
+ addRequiredClassesBinding(in_bindings, subnet);
+ in_bindings.addOptional(subnet->getReservationsGlobal(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getSname(Network::Inheritance::NONE));
+
+ // Add shared network.
+ SharedNetwork4Ptr shared_network;
+ subnet->getSharedNetwork(shared_network);
+
+ // Check if the subnet is associated with a shared network instance.
+ // If it is, create the binding using the name of the shared network.
+ if (shared_network) {
+ in_bindings.addTempString(shared_network->getName());
+
+ // If the subnet is associated with a shared network by name (no
+ // shared network instance), use this name to create the binding.
+ // This may be the case if the subnet is added as a result of
+ // receiving a control command that merely specifies shared
+ // network name. In that case, it is expected that the shared
+ // network data is already stored in the database.
+ } else if (!subnet->getSharedNetworkName().empty()) {
+ in_bindings.addTempString(subnet->getSharedNetworkName());
+
+ // If the subnet is not associated with a shared network, create
+ // null binding.
+ } else {
+ in_bindings.addNull();
+ }
+
+ in_bindings.add(subnet->getContext());
+ in_bindings.add(subnet->getValid(Network::Inheritance::NONE));
+ in_bindings.addMin(subnet->getValid(Network::Inheritance::NONE));
+ in_bindings.addMax(subnet->getValid(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getCalculateTeeTimes(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getT1Percent(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getT2Percent(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getAuthoritative(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsSendUpdates(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsOverrideNoUpdate(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE));
+ addDdnsReplaceClientNameBinding(in_bindings, subnet);
+ in_bindings.addOptional(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getReservationsInSubnet(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getReservationsOutOfPool(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getCacheThreshold(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getCacheMaxAge(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getOfferLft(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getAllocatorType(Network::Inheritance::NONE));
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "subnet set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateSubnet4");
+
+ try {
+
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4, in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // It already exists, rollback to the savepoint to preserve
+ // any prior work.
+ conn_.rollbackToSavepoint("createUpdateSubnet4");
+
+ // We're updating, so we need to remove any existing pools and options.
+ deletePools4(subnet);
+ deleteOptions4(ServerSelector::ANY(), subnet);
+
+ // Now we need to add two more bindings for WHERE clause.
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Attempt the update.
+ auto cnt = updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4,
+ in_bindings);
+ if (!cnt) {
+ // Possible only if someone deleted it since we tried to insert it
+ // or the query is broken.
+ isc_throw(Unexpected, "Update subnet failed to find subnet id: "
+ << subnet->getID() << ", prefix: " << subnet->toText());
+ }
+
+ // Remove existing server association.
+ PsqlBindArray server_bindings;
+ server_bindings.add(subnet->getID());
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_SERVER,
+ server_bindings);
+ }
+
+ // Subnet was successfully created/updated.
+
+ // Insert associations with the servers.
+ PsqlBindArray attach_bindings;
+ attach_bindings.add(subnet->getID());
+ attach_bindings.addTimestamp(subnet->getModificationTime());
+ attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER,
+ server_selector, attach_bindings);
+
+ // (Re)create pools.
+ for (auto pool : subnet->getPools(Lease::TYPE_V4)) {
+ createPool4(server_selector, boost::dynamic_pointer_cast<Pool4>(pool),
+ subnet);
+ }
+
+ // (Re)create options.
+ auto option_spaces = subnet->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = subnet->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption4(server_selector, subnet->getID(), desc_copy,
+ true);
+ }
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Inserts new IPv4 pool to the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool Pointer to the pool to be inserted.
+ /// @param subnet Pointer to the subnet that this pool belongs to.
+ void createPool4(const ServerSelector& server_selector,
+ const Pool4Ptr& pool,
+ const Subnet4Ptr& subnet) {
+ // Create the input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.addInet4(pool->getFirstAddress());
+ in_bindings.addInet4(pool->getLastAddress());
+ in_bindings.add(subnet->getID());
+ in_bindings.addOptional(pool->getClientClass());
+ addRequiredClassesBinding(in_bindings, pool);
+ in_bindings.add(pool->getContext());
+ in_bindings.addTimestamp(subnet->getModificationTime());
+
+ // Attempt to INSERT the pool.
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_POOL4, in_bindings);
+
+ // Get the id of the newly inserted pool.
+ uint64_t pool_id = getLastInsertId("dhcp4_pool", "id");
+
+ // Add the pool's options.
+ auto option_spaces = pool->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = pool->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption4(server_selector, pool_id, desc_copy, true);
+ }
+ }
+ }
+
+ /// @brief Sends a query to delete data from a table.
+ ///
+ /// If creates a new audit revision for this change if such audit
+ /// revision doesn't exist yet (using ScopedAuditRevision mechanism).
+ ///
+ /// @tparam Args type of the arguments to be passed to one of the existing
+ /// @c deleteFromTable methods.
+ /// @param server_selector server selector.
+ /// @param operation operation which results in calling this function. This is
+ /// used for logging purposes.
+ /// @param log_message log message to be associated with the audit revision.
+ /// @param cascade_delete boolean flag indicating if we're performing
+ /// cascade delete. If set to true, the audit entries for the child
+ /// objects (e.g. DHCPoptions) won't be created.
+ /// @param keys arguments to be passed to one of the existing
+ /// @c deleteFromTable methods.
+ ///
+ /// @return Number of deleted entries.
+ template<typename... Args>
+ uint64_t deleteTransactional(const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& operation,
+ const std::string& log_message,
+ const bool cascade_delete,
+ Args&&... keys) {
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, log_message, cascade_delete);
+
+ auto count = deleteFromTable(index, server_selector, operation, keys...);
+
+ transaction.commit();
+
+ return (count);
+ }
+
+ /// @brief Sends query to delete subnet by id.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ uint64_t deleteSubnet4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) {
+ int index = (server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_ANY :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_WITH_TAG);
+ return (deleteTransactional(index, server_selector,
+ "deleting a subnet", "subnet deleted",
+ true, static_cast<uint32_t>(subnet_id)));
+ }
+
+ /// @brief Sends query to delete subnet by id.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_prefix Prefix of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ uint64_t deleteSubnet4(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) {
+ int index = (server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_ANY :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_WITH_TAG);
+ return (deleteTransactional(index, server_selector,
+ "deleting a subnet", "subnet deleted",
+ true, subnet_prefix));
+ }
+
+ /// @brief Deletes pools belonging to a subnet from the database.
+ ///
+ /// The query deletes all pools associated with the subnet's
+ /// identifier or prefix.
+ /// @param subnet Pointer to the subnet for which pools should be
+ /// deleted.
+ uint64_t deletePools4(const Subnet4Ptr& subnet) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Run DELETE.
+ return (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_POOLS4,
+ in_bindings));
+ }
+
+ /// @brief Sends query to the database to retrieve multiple shared
+ /// networks.
+ ///
+ /// Query should order shared networks by id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] shared_networks Reference to the container where fetched
+ /// shared networks will be inserted.
+ void getSharedNetworks4(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ SharedNetwork4Collection& shared_networks) {
+ uint64_t last_network_id = 0;
+ uint64_t last_option_id = 0;
+ std::string last_tag;
+
+ selectQuery(index, in_bindings,
+ [this, &shared_networks, &last_network_id, &last_option_id, &last_tag]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ SharedNetwork4Ptr last_network;
+ if (!shared_networks.empty()) {
+ last_network = *shared_networks.rbegin();
+ }
+
+ // Network id is column 0.
+ auto network_id = worker.getBigInt(0) ;
+
+ // If this is the first shared network or the shared network id in this
+ // row points to the next shared network we use the data in the
+ // row to create the new shared network instance.
+ if (last_network_id != network_id) {
+ last_network_id = network_id;
+
+ // Reset per shared network component tracking and server tag because
+ // we're now starting to process a new shared network.
+ last_option_id = 0;
+ last_tag.clear();
+
+ // name at 1.
+ last_network = SharedNetwork4::create(worker.getString(1));
+ last_network->setId(last_network_id);
+
+ // client_class at 2.
+ if (!worker.isColumnNull(2)) {
+ last_network->allowClientClass(worker.getString(2));
+ }
+
+ // interface at 3.
+ if (!worker.isColumnNull(3)) {
+ last_network->setIface(worker.getString(3));
+ }
+
+ // match_client_id at 4.
+ if (!worker.isColumnNull(4)) {
+ last_network->setMatchClientId(worker.getBool(4));
+ }
+
+ // modification_ts at 5.
+ last_network->setModificationTime(worker.getTimestamp(5));
+
+ // rebind_timer at 6.
+ if (!worker.isColumnNull(6)) {
+ last_network->setT2(worker.getTriplet(6));
+ }
+
+ // Relay addresses at 7.
+ setRelays(worker, 7, *last_network);
+
+ // renew_timer at 8.
+ if (!worker.isColumnNull(8)) {
+ last_network->setT1(worker.getTriplet(8));
+ }
+
+ // require_client_classes at 9.
+ setRequiredClasses(worker, 9, [&last_network](const std::string& class_name) {
+ last_network->requireClientClass(class_name);
+ });
+
+ // reservations_global at 10.
+ if (!worker.isColumnNull(10)) {
+ last_network->setReservationsGlobal(worker.getBool(10));
+ }
+
+ // user_context at 11.
+ if (!worker.isColumnNull(11)) {
+ ElementPtr user_context = worker.getJSON(11);
+ if (user_context) {
+ last_network->setContext(user_context);
+ }
+ }
+
+ // valid_lifetime at 12.
+ // min_valid_lifetime at 33.
+ // max_valid_lifetime at 34.
+ if (!worker.isColumnNull(12)) {
+ last_network->setValid(worker.getTriplet(12, 33, 34));
+ }
+
+ // option from 13 to 25.
+
+ // calculate_tee_times at 26.
+ if (!worker.isColumnNull(26)) {
+ last_network->setCalculateTeeTimes(worker.getBool(26));
+ }
+
+ // t1_percent at 27.
+ if (!worker.isColumnNull(27)) {
+ last_network->setT1Percent(worker.getDouble(27));
+ }
+
+ // t2_percent at 28.
+ if (!worker.isColumnNull(28)) {
+ last_network->setT2Percent(worker.getDouble(28));
+ }
+
+ // authoritative at 29.
+ if (!worker.isColumnNull(29)) {
+ last_network->setAuthoritative(worker.getBool(29));
+ }
+
+ // boot_file_name at 30.
+ if (!worker.isColumnNull(30)) {
+ last_network->setFilename(worker.getString(30));
+ }
+
+ // next_server at 31.
+ if (!worker.isColumnNull(31)) {
+ last_network->setSiaddr(worker.getInet4(31));
+ }
+
+ // server_hostname at 32.
+ if (!worker.isColumnNull(32)) {
+ last_network->setSname(worker.getString(32));
+ }
+
+ // min_valid_lifetime at 33.
+ // max_valid_lifetime at 34.
+
+ // ddns_send_updates at 35.
+ if (!worker.isColumnNull(35)) {
+ last_network->setDdnsSendUpdates(worker.getBool(35));
+ }
+
+ // ddns_override_no_update at 36.
+ if (!worker.isColumnNull(36)) {
+ last_network->setDdnsOverrideNoUpdate(worker.getBool(36));
+ }
+
+ // ddns_override_client_update at 37.
+ if (!worker.isColumnNull(37)) {
+ last_network->setDdnsOverrideClientUpdate(worker.getBool(37));
+ }
+
+ // ddns_replace_client_name at 38.
+ if (!worker.isColumnNull(38)) {
+ last_network->setDdnsReplaceClientNameMode(
+ static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(38)));
+ }
+
+ // ddns_generated_prefix at 39.
+ if (!worker.isColumnNull(39)) {
+ last_network->setDdnsGeneratedPrefix(worker.getString(39));
+ }
+
+ // ddns_qualifying_suffix at 40.
+ if (!worker.isColumnNull(40)) {
+ last_network->setDdnsQualifyingSuffix(worker.getString(40));
+ }
+
+ // reservations_in_subnet at 41.
+ if (!worker.isColumnNull(41)) {
+ last_network->setReservationsInSubnet(worker.getBool(41));
+ }
+
+ // reservations_in_subnet at 42.
+ if (!worker.isColumnNull(42)) {
+ last_network->setReservationsOutOfPool(worker.getBool(42));
+ }
+
+ // cache_threshold at 43.
+ if (!worker.isColumnNull(43)) {
+ last_network->setCacheThreshold(worker.getDouble(43));
+ }
+
+ // cache_max_age at 44.
+ if (!worker.isColumnNull(44)) {
+ last_network->setCacheMaxAge(worker.getInt(44));
+ }
+
+ // offer_lifetime at 45.
+ if (!worker.isColumnNull(45)) {
+ last_network->setOfferLft(worker.getInt(45));
+ }
+
+ // allocator at 46.
+ if (!worker.isColumnNull(46)) {
+ last_network->setAllocatorType(worker.getString(46));
+ }
+
+ // server_tag at 47.
+
+ // Add the shared network.
+ auto ret = shared_networks.push_back(last_network);
+
+ // shared_networks is a multi index container with an unique
+ // index but this index is unique too in the database,
+ // so this is for sanity only.
+ if (!ret.second) {
+ isc_throw(Unexpected, "add shared network failed");
+ }
+ }
+
+ // Check for new server tags.
+ if (!worker.isColumnNull(47)) {
+ std::string new_tag = worker.getString(47);
+ if (last_tag != new_tag) {
+ if (!new_tag.empty() && !last_network->hasServerTag(ServerTag(new_tag))) {
+ last_network->setServerTag(new_tag);
+ }
+
+ last_tag = new_tag;
+ }
+ }
+
+ // Parse network-specific option from 13 to 25.
+ if (!worker.isColumnNull(13) &&
+ (last_option_id < worker.getBigInt(13))) {
+ last_option_id = worker.getBigInt(13);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 13);
+ if (desc) {
+ last_network->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ // Now that we're done fetching the whole network, we have to
+ // check if it has matching server tags and toss it if it
+ // doesn't. We skip matching the server tags if we're asking
+ // for ANY shared network.
+ auto& sn_index = shared_networks.get<SharedNetworkRandomAccessIndexTag>();
+ tossNonMatchingElements(server_selector, sn_index);
+ }
+
+ /// @brief Sends query to retrieve single shared network by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Shared network name.
+ ///
+ /// @return Pointer to the returned shared network or NULL if such shared
+ /// network doesn't exist.
+ SharedNetwork4Ptr getSharedNetwork4(const ServerSelector& server_selector,
+ const std::string& name) {
+ if (server_selector.hasMultipleTags()) {
+ isc_throw(InvalidOperation, "expected one server tag to be specified"
+ " while fetching a shared network. Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(name);
+
+ auto index = PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_NO_TAG;
+ if (server_selector.amUnassigned()) {
+ index = PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_UNASSIGNED;
+ } else if (server_selector.amAny()) {
+ index = PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_ANY;
+ }
+
+ SharedNetwork4Collection shared_networks;
+ getSharedNetworks4(index, server_selector, in_bindings, shared_networks);
+
+ return (shared_networks.empty() ? SharedNetwork4Ptr() : *shared_networks.begin());
+ }
+
+ /// @brief Sends query to retrieve all shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] shared_networks Reference to the shared networks collection
+ /// structure where shared networks should be inserted.
+ void getAllSharedNetworks4(const ServerSelector& server_selector,
+ SharedNetwork4Collection& shared_networks) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching all shared networks for ANY "
+ "server is not supported");
+ }
+
+ auto index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4);
+
+ PsqlBindArray in_bindings;
+ getSharedNetworks4(index, server_selector, in_bindings, shared_networks);
+ }
+
+ /// @brief Sends query to retrieve modified shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] shared_networks Reference to the shared networks collection
+ /// structure where shared networks should be inserted.
+ void getModifiedSharedNetworks4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ SharedNetwork4Collection& shared_networks) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified shared networks for ANY "
+ "server is not supported");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(modification_ts);
+
+ auto index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4);
+ getSharedNetworks4(index, server_selector, in_bindings, shared_networks);
+ }
+
+ /// @brief Sends query to insert or update shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the shared network to be inserted or updated.
+ void createUpdateSharedNetwork4(const ServerSelector& server_selector,
+ const SharedNetwork4Ptr& shared_network) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "creating or updating a shared network for ANY"
+ " server is not supported");
+
+ } else if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(shared_network->getName());
+ in_bindings.addOptional(shared_network->getClientClass(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getIface(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getMatchClientId(Network::Inheritance::NONE));
+ in_bindings.addTimestamp(shared_network->getModificationTime()),
+ in_bindings.add(shared_network->getT2(Network::Inheritance::NONE));
+ addRelayBinding(in_bindings, shared_network);
+ in_bindings.add(shared_network->getT1(Network::Inheritance::NONE));
+ addRequiredClassesBinding(in_bindings, shared_network);
+ in_bindings.addOptional(shared_network->getReservationsGlobal(Network::Inheritance::NONE));
+ in_bindings.add(shared_network->getContext());
+ in_bindings.add(shared_network->getValid(Network::Inheritance::NONE));
+ in_bindings.addMin(shared_network->getValid(Network::Inheritance::NONE));
+ in_bindings.addMax(shared_network->getValid(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getT1Percent(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getT2Percent(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getAuthoritative(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getFilename(Network::Inheritance::NONE));
+ in_bindings.addOptionalInet4(shared_network->getSiaddr(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getSname(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsSendUpdates(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsOverrideNoUpdate(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE));
+ addDdnsReplaceClientNameBinding(in_bindings, shared_network);
+ in_bindings.addOptional(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getReservationsInSubnet(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getCacheThreshold(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getCacheMaxAge(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getOfferLft(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getAllocatorType(Network::Inheritance::NONE));
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "shared network set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateSharedNetwork4");
+
+ try {
+
+ // Try to insert shared network. The shared network name must be unique,
+ // so if inserting fails with DuplicateEntry exception we'll need to
+ // update existing shared network entry.
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4,
+ in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // It already exists, rollback to the savepoint to preserve
+ // any prior work.
+ conn_.rollbackToSavepoint("createUpdateSharedNetwork4");
+
+ // We're updating, so we need to remove any options.
+ deleteOptions4(ServerSelector::ANY(), shared_network);
+
+ // Need to add one more binding for WHERE clause.
+ in_bindings.addTempString(shared_network->getName());
+
+ // Try the update.
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4,
+ in_bindings);
+
+ // Remove existing server association.
+ PsqlBindArray server_bindings;
+ server_bindings.addTempString(shared_network->getName());
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER,
+ server_bindings);
+ }
+
+ // Associate the shared network with the servers.
+ PsqlBindArray attach_bindings;
+ attach_bindings.addTempString(shared_network->getName());
+ attach_bindings.addTimestamp(shared_network->getModificationTime());
+ attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER,
+ server_selector, attach_bindings);
+
+ // (Re)create options.
+ auto option_spaces = shared_network->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = shared_network->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption4(server_selector, shared_network->getName(),
+ desc_copy, true);
+ }
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert DHCP option.
+ ///
+ /// This method expects that the server selector contains exactly one
+ /// server tag. It is intended to be used within a transaction.
+ ///
+ /// @param server_selector Server selector.
+ /// @param in_bindings Collection of bindings representing an option.
+ /// @param modification_ts option's modification timestamp
+ void insertOption4(const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ const boost::posix_time::ptime& modification_ts) {
+ // Attempt the insert.
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4, in_bindings);
+
+ // Fetch primary key value of the inserted option. We will use it in the
+ // next INSERT statement to associate this option with the server.
+ auto option_id = getLastInsertId("dhcp4_options", "option_id");
+
+ PsqlBindArray attach_bindings;
+ attach_bindings.add(option_id); // id of newly inserted global.
+ attach_bindings.addTimestamp(modification_ts);
+
+ // Associate the option with the servers.
+ attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER,
+ server_selector, attach_bindings);
+ }
+
+ /// @brief Sends query to insert or update global DHCP option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption4(const ServerSelector& server_selector,
+ const OptionDescriptorPtr& option) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "creating or updating global option");
+
+ // Create the input parameter bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.add(0);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(tag);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "global option set", false);
+
+ // Try to update the option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption4(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a subnet.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ /// @param cascade_update Boolean value indicating whether the update is
+ /// performed as part of the owning element, e.g. subnet.
+ void createUpdateOption4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option,
+ const bool cascade_update) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.add(subnet_id);
+ in_bindings.add(1);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(subnet_id);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "subnet specific option set",
+ cascade_update);
+
+ // Try to update the subnet option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption4(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a pool.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the pool.
+ /// @param pool_end_address Upper bound address of the pool.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption4(const ServerSelector& server_selector,
+ const IOAddress& pool_start_address,
+ const IOAddress& pool_end_address,
+ const OptionDescriptorPtr& option) {
+ uint64_t pool_id = 0;
+ Pool4Ptr pool = getPool4(server_selector, pool_start_address, pool_end_address,
+ pool_id);
+ if (!pool) {
+ isc_throw(BadValue, "no pool found for range of "
+ << pool_start_address << " : "
+ << pool_end_address);
+ }
+
+ createUpdateOption4(server_selector, pool_id, option, false);
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a pool.
+ ///
+ /// @param selector Server selector.
+ /// @param pool_id Identifier of the pool the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ /// @param cascade_update Boolean value indicating whether the update is
+ /// performed as part of the owning element, e.g. subnet.
+ void createUpdateOption4(const ServerSelector& server_selector,
+ const uint64_t pool_id,
+ const OptionDescriptorPtr& option,
+ const bool cascade_update) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.add(5);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.add(pool_id);
+ in_bindings.addTimestamp(option->getModificationTime());
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(pool_id);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "pool specific option set",
+ cascade_update);
+
+ // Try to update the option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption4(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a shared network.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network the option
+ /// belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ /// @param cascade_update Boolean value indicating whether the update is
+ /// performed as part of the owning element, e.g. shared network.
+ void createUpdateOption4(const ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option,
+ const bool cascade_update) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.add(4);
+ in_bindings.add(option->getContext());
+ in_bindings.add(shared_network_name);
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(shared_network_name);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "shared network specific option set",
+ cascade_update);
+
+ // Try to update the option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption4(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a client class.
+ ///
+ /// @param selector Server selector.
+ /// @param client_class Pointer to the client_class the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option..
+ void createUpdateOption4(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const OptionDescriptorPtr& option) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ PsqlBindArray in_bindings;
+ std::string class_name = client_class->getName();
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.add(class_name);
+ in_bindings.addNull();
+ in_bindings.add(2);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(class_name);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "client class specific option set",
+ true);
+
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_CLIENT_CLASS,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ insertOption4(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+ }
+
+ /// @brief Sends query to insert or update option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Pointer to the option definition to be inserted or updated.
+ void createUpdateOptionDef4(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def) {
+ createUpdateOptionDef(server_selector, Option::V4, option_def, DHCP4_OPTION_SPACE,
+ PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE,
+ PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4,
+ PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER);
+ }
+
+ /// @brief Sends query to insert or update option definition
+ /// for a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Pointer to the option definition to be inserted or updated.
+ /// @param client_class Client class name.
+ void createUpdateOptionDef4(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def,
+ const std::string& client_class_name) {
+ createUpdateOptionDef(server_selector, Option::V4, option_def, DHCP4_OPTION_SPACE,
+ PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE,
+ PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_CLIENT_CLASS,
+ PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4_CLIENT_CLASS,
+ PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER,
+ client_class_name);
+ }
+
+ /// @brief Sends query to delete option definition by code and
+ /// option space name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Option code.
+ /// @param name Option name.
+ /// @return Number of deleted option definitions.
+ uint64_t deleteOptionDef4(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEF4_CODE_NAME,
+ server_selector,
+ "deleting option definition",
+ "option definition deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Sends query to delete option definitions for a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the client class for which option
+ /// definitions should be deleted.
+ /// @return Number of deleted option definitions.
+ uint64_t deleteOptionDefs4(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(client_class->getName());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEFS4_CLIENT_CLASS,
+ server_selector,
+ "deleting option definition for a client class",
+ "option definition deleted",
+ true,
+ in_bindings));
+ }
+
+ /// @brief Deletes global option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption4(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4,
+ server_selector,
+ "deleting global option",
+ "global option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes subnet level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to which deleted option
+ /// belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet_id);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID,
+ server_selector,
+ "deleting option for a subnet",
+ "subnet specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound pool address.
+ /// @param pool_end_address Upper bound pool address.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption4(const db::ServerSelector& server_selector,
+ const IOAddress& pool_start_address,
+ const IOAddress& pool_end_address,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.addInet4(pool_start_address);
+ in_bindings.addInet4(pool_end_address);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_POOL_RANGE,
+ server_selector,
+ "deleting option for a pool",
+ "pool specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network which deleted
+ /// option belongs to
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(shared_network_name);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SHARED_NETWORK,
+ server_selector,
+ "deleting option for a shared network",
+ "shared network specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes options belonging to a subnet from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the subnet for which options should be
+ /// deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions4(const ServerSelector& server_selector,
+ const Subnet4Ptr& subnet) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SUBNET_ID_PREFIX,
+ server_selector,
+ "deleting options for a subnet",
+ "subnet specific options deleted",
+ true, in_bindings));
+ }
+
+ /// @brief Deletes options belonging to a shared network from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the subnet for which options should be
+ /// deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions4(const ServerSelector& server_selector,
+ const SharedNetwork4Ptr& shared_network) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(shared_network->getName());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::
+ DELETE_OPTIONS4_SHARED_NETWORK, server_selector,
+ "deleting options for a shared network",
+ "shared network specific options deleted",
+ true, in_bindings));
+ }
+
+ /// @brief Deletes options belonging to a client class from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the client class for which options
+ /// should be deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions4(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(client_class->getName());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv4Impl::
+ DELETE_OPTIONS4_CLIENT_CLASS, server_selector,
+ "deleting options for a client class",
+ "client class specific options deleted",
+ true, in_bindings));
+ }
+
+ /// @brief Common function to retrieve client classes.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] client_classes Reference to a container where fetched client
+ /// classes will be inserted.
+ void getClientClasses4(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ ClientClassDictionary& client_classes) {
+ std::list<ClientClassDefPtr> class_list;
+ uint64_t last_option_id = 0;
+ uint64_t last_option_def_id = 0;
+ std::string last_tag;
+
+ selectQuery(index, in_bindings,
+ [this, &class_list, &last_option_id, &last_option_def_id, &last_tag]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ ClientClassDefPtr last_client_class;
+ if (!class_list.empty()) {
+ last_client_class = *class_list.rbegin();
+ }
+
+ // Class ID is column 0.
+ uint64_t id = worker.getBigInt(0) ;
+
+ if (!last_client_class || (last_client_class->getId() != id)) {
+ last_option_id = 0;
+ last_option_def_id = 0;
+ last_tag.clear();
+
+ auto options = boost::make_shared<CfgOption>();
+ auto option_defs = boost::make_shared<CfgOptionDef>();
+
+ last_client_class = boost::make_shared<ClientClassDef>(worker.getString(1),
+ ExpressionPtr(), options);
+ last_client_class->setCfgOptionDef(option_defs);
+
+ // id
+ last_client_class->setId(id);
+
+ // name
+ last_client_class->setName(worker.getString(1));
+
+ // test
+ if (!worker.isColumnNull(2)) {
+ last_client_class->setTest(worker.getString(2));
+ }
+
+ // next server
+ if (!worker.isColumnNull(3)) {
+ last_client_class->setNextServer(worker.getInet4(3));
+ }
+
+ // sname
+ if (!worker.isColumnNull(4)) {
+ last_client_class->setSname(worker.getString(4));
+ }
+
+ // filename
+ if (!worker.isColumnNull(5)) {
+ last_client_class->setFilename(worker.getString(5));
+ }
+
+ // required
+ if (!worker.isColumnNull(6)) {
+ last_client_class->setRequired(worker.getBool(6));
+ }
+
+ // valid lifetime: default, min, max
+ last_client_class->setValid(worker.getTriplet(7, 8, 9));
+
+ // depend on known directly or indirectly
+ last_client_class->setDependOnKnown(worker.getBool(10) || worker.getBool(11));
+
+ // modification_ts
+ last_client_class->setModificationTime(worker.getTimestamp(12));
+
+ // user_context at 13.
+ if (!worker.isColumnNull(13)) {
+ ElementPtr user_context = worker.getJSON(13);
+ if (user_context) {
+ last_client_class->setContext(user_context);
+ }
+ }
+
+ // offer_lifetime at 14.
+ if (!worker.isColumnNull(14)) {
+ last_client_class->setOfferLft(worker.getInt(14));
+ }
+
+ class_list.push_back(last_client_class);
+ }
+
+ // Check for new server tags at 38.
+ if (!worker.isColumnNull(38)) {
+ std::string new_tag = worker.getString(38);
+ if (last_tag != new_tag) {
+ if (!new_tag.empty() && !last_client_class->hasServerTag(ServerTag(new_tag))) {
+ last_client_class->setServerTag(new_tag);
+ }
+
+ last_tag = new_tag;
+ }
+ }
+
+ // Parse client class specific option definition from 15 to 24.
+ if (!worker.isColumnNull(15) &&
+ (last_option_def_id < worker.getBigInt(15))) {
+ last_option_def_id = worker.getBigInt(15);
+
+ auto def = processOptionDefRow(worker, 15);
+ if (def) {
+ last_client_class->getCfgOptionDef()->add(def);
+ }
+ }
+
+ // Parse client class specific option from 25 to 37.
+ if (!worker.isColumnNull(25) &&
+ (last_option_id < worker.getBigInt(25))) {
+ last_option_id = worker.getBigInt(25);
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, worker, 25);
+ if (desc) {
+ last_client_class->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ tossNonMatchingElements(server_selector, class_list);
+
+ for (auto c : class_list) {
+ client_classes.addClass(c);
+ }
+ }
+
+ /// @brief Sends query to retrieve a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be retrieved.
+ /// @return Pointer to the client class or null if the class is not found.
+ ClientClassDefPtr getClientClass4(const ServerSelector& server_selector,
+ const std::string& name) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(name);
+
+ ClientClassDictionary client_classes;
+ getClientClasses4(PgSqlConfigBackendDHCPv4Impl::GET_CLIENT_CLASS4_NAME,
+ server_selector, in_bindings, client_classes);
+ return (client_classes.getClasses()->empty() ? ClientClassDefPtr() :
+ (*client_classes.getClasses()->begin()));
+ }
+
+ /// @brief Sends query to retrieve all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] client_classes Reference to the client classes collection
+ /// where retrieved classes will be stored.
+ void getAllClientClasses4(const ServerSelector& server_selector,
+ ClientClassDictionary& client_classes) {
+ PsqlBindArray in_bindings;
+ getClientClasses4(server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4,
+ server_selector, in_bindings, client_classes);
+ }
+
+ /// @brief Sends query to retrieve modified client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] client_classes Reference to the client classes collection
+ /// where retrieved classes will be stored.
+ void getModifiedClientClasses4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ ClientClassDictionary& client_classes) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified client classes for ANY "
+ "server is not supported");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(modification_ts);
+ getClientClasses4(server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4,
+ server_selector, in_bindings, client_classes);
+ }
+
+ /// @brief Upserts client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the upserted client class.
+ /// @param follow_class_name name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ void createUpdateClientClass4(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name) {
+ // We need to evaluate class expression to see if it references any
+ // other classes (dependencies). As part of this evaluation we will
+ // also check if the client class depends on KNOWN/UNKNOWN built-in
+ // classes.
+ std::list<std::string> dependencies;
+ auto depend_on_known = false;
+ if (!client_class->getTest().empty()) {
+ ExpressionPtr expression;
+ ExpressionParser parser;
+ // Parse the test expression. The callback function is normally used to
+ // interrupt config file parsing when one of the classes refers to a
+ // non-existing client class. It returns false in this case. Here,
+ // we use the callback to capture client classes referenced by the
+ // upserted client class and record whether this class depends on
+ // KNOWN/UNKNOWN built-ins. The callback always returns true to avoid
+ // reporting the parsing error. The dependency check is performed later
+ // at the database level.
+ parser.parse(expression, Element::create(client_class->getTest()), AF_INET,
+ [&dependencies, &depend_on_known](const ClientClass& client_class) -> bool {
+ if (isClientClassBuiltIn(client_class)) {
+ if ((client_class == "KNOWN") || (client_class == "UNKNOWN")) {
+ depend_on_known = true;
+ }
+ } else {
+ dependencies.push_back(client_class);
+ }
+ return (true);
+ });
+ }
+
+ PsqlBindArray in_bindings;
+ std::string class_name = client_class->getName();
+ in_bindings.add(class_name);
+ in_bindings.addTempString(client_class->getTest());
+ in_bindings.addInet4(client_class->getNextServer());
+ in_bindings.addTempString(client_class->getSname());
+ in_bindings.addTempString(client_class->getFilename());
+ in_bindings.add(client_class->getRequired());
+ in_bindings.add(client_class->getValid());
+ in_bindings.add(client_class->getValid().getMin());
+ in_bindings.add(client_class->getValid().getMax());
+ in_bindings.add(depend_on_known);
+
+ // follow-class-name (11)
+ if (follow_class_name.empty()) {
+ in_bindings.addNull();
+ } else {
+ in_bindings.add(follow_class_name);
+ }
+
+ in_bindings.addTimestamp(client_class->getModificationTime());
+ in_bindings.add(client_class->getContext());
+ in_bindings.addOptional(client_class->getOfferLft());
+
+ PgSqlTransaction transaction(conn_);
+
+ ScopedAuditRevision audit_revision(this, PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ server_selector, "client class set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateClass4");
+
+ // Keeps track of whether the client class is inserted or updated.
+ auto update = false;
+ try {
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4, in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // It already exists, rollback to the savepoint to preserve
+ // any prior work.
+ conn_.rollbackToSavepoint("createUpdateClass4");
+
+ // Delete options and option definitions. They will be re-created from the new class
+ // instance.
+ deleteOptions4(ServerSelector::ANY(), client_class);
+ deleteOptionDefs4(ServerSelector::ANY(), client_class);
+
+ // Note: follow_class_name is left in the bindings even though it is
+ // not needed in both cases. This allows us to use one base query.
+
+ // Add the class name for the where clause.
+ in_bindings.add(class_name);
+ if (follow_class_name.empty()) {
+ // If position is not specified, leave the class at the same position.
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4_SAME_POSITION,
+ in_bindings);
+ } else {
+ // Update with follow_class_name specifying the position.
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4,
+ in_bindings);
+ }
+
+ // Delete class associations with the servers and dependencies. We will re-create
+ // them according to the new class specification.
+ PsqlBindArray in_assoc_bindings;
+ in_assoc_bindings.add(class_name);
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_DEPENDENCY,
+ in_assoc_bindings);
+ updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_SERVER,
+ in_assoc_bindings);
+ update = true;
+ }
+
+ // Associate client class with the servers.
+ PsqlBindArray attach_bindings;
+ attach_bindings.add(class_name);
+ attach_bindings.addTimestamp(client_class->getModificationTime());
+
+ attachElementToServers(PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_SERVER,
+ server_selector, attach_bindings);
+
+ // Iterate over the captured dependencies and try to insert them into the database.
+ for (auto dependency : dependencies) {
+ try {
+ PsqlBindArray in_dependency_bindings;
+ in_dependency_bindings.add(class_name);
+ in_dependency_bindings.add(dependency);
+
+ // We deleted earlier dependencies, so we can simply insert new ones.
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_DEPENDENCY,
+ in_dependency_bindings);
+ } catch (const std::exception& ex) {
+ isc_throw(InvalidOperation, "unmet dependency on client class: " << dependency);
+ }
+ }
+
+ // If we performed client class update we also have to verify that its dependency
+ // on KNOWN/UNKNOWN client classes hasn't changed.
+ if (update) {
+ PsqlBindArray in_check_bindings;
+ insertQuery(PgSqlConfigBackendDHCPv4Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ in_check_bindings);
+ }
+
+ // (Re)create option definitions.
+ if (client_class->getCfgOptionDef()) {
+ auto option_defs = client_class->getCfgOptionDef()->getContainer();
+ auto option_spaces = option_defs.getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionDefContainerPtr defs = option_defs.getItems(option_space);
+ for (auto def = defs->begin(); def != defs->end(); ++def) {
+ createUpdateOptionDef4(server_selector, *def, client_class->getName());
+ }
+ }
+ }
+
+ // (Re)create options.
+ auto option_spaces = client_class->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = client_class->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption4(server_selector, client_class, desc_copy);
+ }
+ }
+
+ // All ok. Commit the transaction.
+ transaction.commit();
+ }
+
+ /// @brief Removes client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Removed client class name.
+ /// @return Number of deleted client classes.
+ uint64_t deleteClientClass4(const ServerSelector& server_selector,
+ const std::string& name) {
+ int index = server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_ANY :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4;
+
+ uint64_t result = deleteTransactional(index, server_selector,
+ "deleting client class",
+ "client class deleted",
+ true,
+ name);
+ return (result);
+ }
+
+ /// @brief Removes unassigned global parameters, global options and
+ /// option definitions.
+ ///
+ /// This function is called when one or more servers are deleted and
+ /// it is likely that there are some orphaned configuration elements
+ /// left in the database. This method removes those elements.
+ void purgeUnassignedConfig() {
+ multipleUpdateDeleteQueries(DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED,
+ DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED,
+ DELETE_ALL_OPTION_DEFS4_UNASSIGNED);
+ }
+
+ /// @brief Attempts to delete a server having a given tag.
+ ///
+ /// @param server_tag Tag of the server to be deleted.
+ /// @return Number of deleted servers.
+ /// @throw isc::InvalidOperation when trying to delete the logical
+ /// server 'all'.
+ uint64_t deleteServer4(const data::ServerTag& server_tag) {
+ // It is not allowed to delete 'all' logical server.
+ if (server_tag.amAll()) {
+ isc_throw(InvalidOperation, "'all' is a name reserved for the server tag which"
+ " associates the configuration elements with all servers connecting"
+ " to the database and may not be deleted");
+ }
+
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this, PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ ServerSelector::ALL(), "deleting a server", false);
+
+ // Specify which server should be deleted.
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(server_tag.get());
+
+ // Attempt to delete the server.
+ auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_SERVER4,
+ in_bindings);
+
+ // If we have deleted any servers we have to remove any dangling global
+ // parameters, options and option definitions.
+ if (count > 0) {
+ purgeUnassignedConfig();
+ }
+
+ transaction.commit();
+
+ return (count);
+ }
+
+ /// @brief Attempts to delete all servers.
+ ///
+ /// This method deletes all servers added by the user. It does not
+ /// delete the logical server 'all'.
+ ///
+ /// @return Number of deleted servers.
+ uint64_t deleteAllServers4() {
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this, PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ ServerSelector::ALL(), "deleting all servers",
+ false);
+
+ // No arguments, hence empty input bindings.
+ PsqlBindArray in_bindings;
+
+ // Attempt to delete the servers.
+ auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SERVERS4,
+ in_bindings);
+
+ // If we have deleted any servers we have to remove any dangling global
+ // parameters, options and option definitions.
+ if (count > 0) {
+ purgeUnassignedConfig();
+ }
+
+ // Commit the transaction.
+ transaction.commit();
+
+ return (count);
+ }
+
+ /// @brief Attempts to reconnect the server to the config DB backend manager.
+ ///
+ /// This is a self-rescheduling function that attempts to reconnect to the
+ /// server's config DB backends after connectivity to one or more have been
+ /// lost. Upon entry it will attempt to reconnect via
+ /// @ref ConfigBackendDHCPv4Mgr.addBackend.
+ /// If this is successful, DHCP servicing is re-enabled and server returns
+ /// to normal operation.
+ ///
+ /// If reconnection fails and the maximum number of retries has not been
+ /// exhausted, it will schedule a call to itself to occur at the
+ /// configured retry interval. DHCP service remains disabled.
+ ///
+ /// If the maximum number of retries has been exhausted an error is logged
+ /// and the server shuts down.
+ ///
+ /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the
+ /// configured reconnect parameters.
+ /// @return true if connection has been recovered, false otherwise.
+ static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
+ MultiThreadingCriticalSection cs;
+
+ // Invoke application layer connection lost callback.
+ if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
+ return (false);
+ }
+
+ bool reopened = false;
+
+ const std::string timer_name = db_reconnect_ctl->timerName();
+
+ // At least one connection was lost.
+ try {
+ auto srv_cfg = CfgMgr::instance().getCurrentCfg();
+ auto config_ctl = srv_cfg->getConfigControlInfo();
+ // Iterate over the configured DBs and instantiate them.
+ for (auto db : config_ctl->getConfigDatabases()) {
+ const std::string& access = db.getAccessString();
+ auto parameters = db.getParameters();
+ if (ConfigBackendDHCPv4Mgr::instance().delBackend(parameters["type"], access, true)) {
+ ConfigBackendDHCPv4Mgr::instance().addBackend(db.getAccessString());
+ }
+ }
+
+ reopened = true;
+ } catch (const std::exception& ex) {
+ LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_FAILED4)
+ .arg(ex.what());
+ }
+
+ if (reopened) {
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
+ // Invoke application layer connection recovered callback.
+ if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
+ return (false);
+ }
+ } else {
+ if (!db_reconnect_ctl->checkRetries()) {
+ // We're out of retries, log it and initiate shutdown.
+ LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_FAILED4)
+ .arg(db_reconnect_ctl->maxRetries());
+
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
+ // Invoke application layer connection failed callback.
+ DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl);
+
+ return (false);
+ }
+
+ LOG_INFO(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4)
+ .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
+ .arg(db_reconnect_ctl->maxRetries())
+ .arg(db_reconnect_ctl->retryInterval());
+
+ // Start the timer.
+ if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->registerTimer(timer_name,
+ std::bind(&PgSqlConfigBackendDHCPv4Impl::dbReconnect, db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval(),
+ asiolink::IntervalTimer::ONE_SHOT);
+ }
+ TimerMgr::instance()->setup(timer_name);
+ }
+
+ return (true);
+ }
+
+};
+
+namespace {
+
+/// @brief Array of tagged statements.
+typedef std::array<PgSqlTaggedStatement, PgSqlConfigBackendDHCPv4Impl::NUM_STATEMENTS>
+TaggedStatementArray;
+
+/// @brief Prepared PgSQL statements used by the backend to insert and
+/// retrieve data from the database. They must be in the same order as
+/// PgSqlConfigBackendDHCPv4Impl::StatementIndex. The statement is
+/// the corresponding enum name.
+TaggedStatementArray tagged_statements = { {
+ {
+ // PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ 4,
+ {
+ OID_TIMESTAMP, // 1 audit_ts
+ OID_VARCHAR, // 2 server_tag
+ OID_TEXT, // 3 audit_log_message
+ OID_BOOL // 4 cascade_transaction
+ },
+ "CREATE_AUDIT_REVISION",
+ "select createAuditRevisionDHCP4($1, $2, $3, $4)"
+ },
+
+ // Verify that dependency on KNOWN/UNKNOWN class has not changed.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ 0,
+ {
+ OID_NONE
+ },
+ "CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE",
+ "select checkDHCPv4ClientClassKnownDependencyChange()"
+ },
+
+ // Select global parameter by name.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_GLOBAL_PARAMETER4,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 name
+ },
+ "GET_GLOBAL_PARAMETER4",
+ PGSQL_GET_GLOBAL_PARAMETER(dhcp4, AND g.name = $2)
+ },
+
+ // Select all global parameters.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_ALL_GLOBAL_PARAMETERS4",
+ PGSQL_GET_GLOBAL_PARAMETER(dhcp4)
+ },
+
+ // Select modified global parameters.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP // 2 modification_ts
+ },
+ "GET_MODIFIED_GLOBAL_PARAMETERS4",
+ PGSQL_GET_GLOBAL_PARAMETER(dhcp4, AND g.modification_ts >= $2)
+ },
+
+ // Select subnet by id.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_NO_TAG,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "GET_SUBNET4_ID_NO_TAG",
+ PGSQL_GET_SUBNET4_NO_TAG(WHERE s.subnet_id = $1)
+ },
+
+ // Select subnet by id without specifying server tags.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_ANY,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "GET_SUBNET4_ID_ANY",
+ PGSQL_GET_SUBNET4_ANY(WHERE s.subnet_id = $1)
+ },
+
+ // Select unassigned subnet by id.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_ID_UNASSIGNED,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "GET_SUBNET4_ID_UNASSIGNED",
+ PGSQL_GET_SUBNET4_UNASSIGNED(AND s.subnet_id = $1)
+ },
+
+ // Select subnet by prefix.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_NO_TAG,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "GET_SUBNET4_PREFIX_NO_TAG",
+ PGSQL_GET_SUBNET4_NO_TAG(WHERE s.subnet_prefix = $1)
+ },
+
+ // Select subnet by prefix without specifying server tags.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "GET_SUBNET4_PREFIX_ANY",
+ PGSQL_GET_SUBNET4_ANY(WHERE s.subnet_prefix = $1)
+ },
+
+ // Select unassigned subnet by prefix.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX_UNASSIGNED,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "GET_SUBNET4_PREFIX_UNASSIGNED",
+ PGSQL_GET_SUBNET4_UNASSIGNED(AND s.subnet_prefix = $1)
+ },
+
+ // Select all subnets.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SUBNETS4",
+ PGSQL_GET_SUBNET4_NO_TAG()
+ },
+
+ // Select all unassigned subnets.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SUBNETS4_UNASSIGNED",
+ PGSQL_GET_SUBNET4_UNASSIGNED()
+ },
+
+ // Select subnets having modification time later than X.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SUBNETS4",
+ PGSQL_GET_SUBNET4_NO_TAG(WHERE s.modification_ts >= $1)
+ },
+
+ // Select modified and unassigned subnets.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4_UNASSIGNED,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SUBNETS4_UNASSIGNED",
+ PGSQL_GET_SUBNET4_UNASSIGNED(AND s.modification_ts >= $1)
+ },
+
+ // Select subnets belonging to a shared network.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK_SUBNETS4,
+ 1,
+ {
+ OID_VARCHAR // 1 share_network_name
+ },
+ "GET_SHARED_NETWORK_SUBNETS4",
+ PGSQL_GET_SUBNET4_ANY(WHERE s.shared_network_name = $1)
+ },
+
+ // Select pool by address range for a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TEXT, // 2 start_address - cast as inet
+ OID_TEXT // 3 end_address - cast as inet
+ },
+ "GET_POOL4_RANGE",
+ PGSQL_GET_POOL4_RANGE_WITH_TAG(WHERE (srv.tag = $1 OR srv.id = 1) \
+ AND (p.start_address = cast($2 as inet)) \
+ AND (p.end_address = cast($3 as inet)))
+ },
+
+ // Select pool by address range for any server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_POOL4_RANGE_ANY,
+ 2,
+ {
+ OID_TEXT, // 1 start_address - cast as inet
+ OID_TEXT // 2 end_address - cast as inet
+ },
+ "GET_POOL4_RANGE_ANY",
+ PGSQL_GET_POOL4_RANGE_NO_TAG(WHERE (p.start_address = cast($1 as inet)) AND \
+ (p.end_address = cast($2 as inet)))
+ },
+
+ // Select shared network by name.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_NO_TAG,
+ 1,
+ {
+ OID_VARCHAR // name of network
+ },
+ "GET_SHARED_NETWORK4_NAME_NO_TAG",
+ PGSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.name = $1)
+ },
+
+ // Select shared network by name without specifying server tags.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_ANY,
+ 1,
+ {
+ OID_VARCHAR // name of network
+ },
+ "GET_SHARED_NETWORK4_NAME_ANY",
+ PGSQL_GET_SHARED_NETWORK4_ANY(WHERE n.name = $1)
+ },
+
+ // Select unassigned shared network by name.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME_UNASSIGNED,
+ 1,
+ {
+ OID_VARCHAR // name of network
+ },
+ "GET_SHARED_NETWORK4_NAME_UNASSIGNED",
+ PGSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.name = $1)
+ },
+
+ // Select all shared networks.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SHARED_NETWORKS4",
+ PGSQL_GET_SHARED_NETWORK4_NO_TAG()
+ },
+
+ // Select all unassigned shared networks.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SHARED_NETWORKS4_UNASSIGNED",
+ PGSQL_GET_SHARED_NETWORK4_UNASSIGNED()
+ },
+
+ // Select modified shared networks.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SHARED_NETWORKS4",
+ PGSQL_GET_SHARED_NETWORK4_NO_TAG(WHERE n.modification_ts >= $1)
+ },
+
+ // Select modified and unassigned shared networks.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SHARED_NETWORKS4_UNASSIGNED",
+ PGSQL_GET_SHARED_NETWORK4_UNASSIGNED(AND n.modification_ts >= $1)
+ },
+
+ // Retrieves option definition by code and space.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "GET_OPTION_DEF4_CODE_SPACE",
+ PGSQL_GET_OPTION_DEF(dhcp4, AND d.code = $2 AND d.space = $3)
+ },
+
+ // Retrieves all option definitions.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_ALL_OPTION_DEFS4",
+ PGSQL_GET_OPTION_DEF(dhcp4)
+ },
+
+ // Retrieves modified option definitions.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP // 2 modification_ts
+ },
+ "GET_MODIFIED_OPTION_DEFS4",
+ PGSQL_GET_OPTION_DEF(dhcp4, AND d.modification_ts >= $2)
+ },
+
+ // Retrieves global option by code and space.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_CODE_SPACE,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "GET_OPTION4_CODE_SPACE",
+ PGSQL_GET_OPTION4(AND o.scope_id = 0 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Retrieves all global options.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_ALL_OPTIONS4",
+ PGSQL_GET_OPTION4(AND o.scope_id = 0)
+ },
+
+ // Retrieves modified options.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTIONS4,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP // 2 modification_ts
+ },
+ "GET_MODIFIED_OPTIONS4",
+ PGSQL_GET_OPTION4(AND o.scope_id = 0 AND o.modification_ts >= $2)
+ },
+
+ // Retrieves an option for a given subnet, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_SUBNET_ID_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8, // 2 subnet_id
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION4_SUBNET_ID_CODE_SPACE",
+ PGSQL_GET_OPTION4(AND o.scope_id = 1 AND o.dhcp4_subnet_id = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Retrieves an option for a given pool, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_POOL_ID_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8, // 2 pool_id
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION4_POOL_ID_CODE_SPACE",
+ PGSQL_GET_OPTION4(AND o.scope_id = 5 AND o.pool_id = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Retrieves an option for a given shared network, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_SHARED_NETWORK_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR, // 2 shared_network_name
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION4_SHARED_NETWORK_CODE_SPACE",
+ PGSQL_GET_OPTION4(AND o.scope_id = 4 AND o.shared_network_name = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Select a client class by name.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_CLIENT_CLASS4_NAME,
+ 1,
+ {
+ OID_VARCHAR // name of class
+ },
+ "GET_CLIENT_CLASS4_NAME",
+ PGSQL_GET_CLIENT_CLASS4_WITH_TAG(WHERE c.name = $1)
+ },
+
+ // Select all client classes.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_CLIENT_CLASSES4",
+ PGSQL_GET_CLIENT_CLASS4_WITH_TAG()
+ },
+
+ // Select all unassigned client classes.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_CLIENT_CLASSES4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_CLIENT_CLASSES4_UNASSIGNED",
+ PGSQL_GET_CLIENT_CLASS4_UNASSIGNED()
+ },
+
+ // Select modified client classes.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_CLIENT_CLASSES4",
+ PGSQL_GET_CLIENT_CLASS4_WITH_TAG(WHERE c.modification_ts >= $1)
+ },
+
+ // Select modified client classes.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_CLIENT_CLASSES4_UNASSIGNED",
+ PGSQL_GET_CLIENT_CLASS4_UNASSIGNED(AND c.modification_ts >= $1)
+ },
+
+ // Retrieves the most recent audit entries.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_AUDIT_ENTRIES4_TIME,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_INT8 // 3 revision id
+ },
+ "GET_AUDIT_ENTRIES4_TIME",
+ PGSQL_GET_AUDIT_ENTRIES_TIME(dhcp4)
+ },
+
+ // Retrieves a server by tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_SERVER4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_SERVER4",
+ PGSQL_GET_SERVER(dhcp4)
+ },
+
+ // Retrieves all servers.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_ALL_SERVERS4,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SERVERS4",
+ PGSQL_GET_ALL_SERVERS(dhcp4)
+ },
+
+ // Insert global parameter.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4,
+ 4,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 value
+ OID_INT2, // 3 parameter_type
+ OID_TIMESTAMP // 4 modification_ts
+ },
+ "INSERT_GLOBAL_PARAMETER4",
+ PGSQL_INSERT_GLOBAL_PARAMETER(dhcp4)
+ },
+
+ // Insert association of the global parameter with a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_GLOBAL_PARAMETER4_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 parameter_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_GLOBAL_PARAMETER4_SERVER",
+ PGSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp4)
+ },
+
+ // Insert a subnet.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4,
+ 38,
+ {
+ OID_INT8, // 1 subnet_id,
+ OID_VARCHAR, // 2 subnet_prefix
+ OID_VARCHAR, // 3 interface_4o6
+ OID_VARCHAR, // 4 interface_id_4o6
+ OID_VARCHAR, // 5 subnet_4o6
+ OID_VARCHAR, // 6 boot_file_name
+ OID_VARCHAR, // 7 client_class
+ OID_VARCHAR, // 8 interface
+ OID_BOOL, // 9 match_client_id
+ OID_TIMESTAMP, // 10 modification_ts
+ OID_TEXT, // 11 next_server - cast as inet
+ OID_INT8, // 12 rebind_timer
+ OID_TEXT, // 13 relay
+ OID_INT8, // 14 renew_timer
+ OID_TEXT, // 15 require_client_classes
+ OID_BOOL, // 16 reservations_global
+ OID_VARCHAR, // 17 server_hostname
+ OID_VARCHAR, // 18 shared_network_name
+ OID_TEXT, // 19 user_context
+ OID_INT8, // 20 valid_lifetime
+ OID_INT8, // 21 min_valid_lifetime
+ OID_INT8, // 22 max_valid_lifetime
+ OID_BOOL, // 23 calculate_tee_times
+ OID_TEXT, // 24 t1_percent - cast as float
+ OID_TEXT, // 25 t2_percent - cast as float
+ OID_BOOL, // 26 authoritative
+ OID_BOOL, // 27 ddns_send_updates
+ OID_BOOL, // 28 ddns_override_no_update
+ OID_BOOL, // 29 ddns_override_client_update
+ OID_INT8, // 30 ddns_replace_client_name
+ OID_VARCHAR, // 31 ddns_generated_prefix
+ OID_VARCHAR, // 32 ddns_qualifying_suffix
+ OID_BOOL, // 33 reservations_in_subnet
+ OID_BOOL, // 34 reservations_out_of_pool
+ OID_TEXT, // 35 cache_threshold - cast as float
+ OID_INT8, // 36 cache_max_age
+ OID_INT8, // 37 offer_lifetime
+ OID_VARCHAR // 38 allocator
+ },
+ "INSERT_SUBNET4",
+ "INSERT INTO dhcp4_subnet("
+ " subnet_id,"
+ " subnet_prefix,"
+ " interface_4o6,"
+ " interface_id_4o6,"
+ " subnet_4o6,"
+ " boot_file_name,"
+ " client_class,"
+ " interface,"
+ " match_client_id,"
+ " modification_ts,"
+ " next_server,"
+ " rebind_timer,"
+ " relay,"
+ " renew_timer,"
+ " require_client_classes,"
+ " reservations_global,"
+ " server_hostname,"
+ " shared_network_name,"
+ " user_context,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " calculate_tee_times,"
+ " t1_percent,"
+ " t2_percent,"
+ " authoritative,"
+ " ddns_send_updates,"
+ " ddns_override_no_update,"
+ " ddns_override_client_update,"
+ " ddns_replace_client_name,"
+ " ddns_generated_prefix,"
+ " ddns_qualifying_suffix,"
+ " reservations_in_subnet,"
+ " reservations_out_of_pool,"
+ " cache_threshold,"
+ " cache_max_age,"
+ " offer_lifetime,"
+ " allocator"
+ ") VALUES ("
+ "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, "
+ "cast($11 as inet), $12, $13, $14, $15, $16, $17, $18, cast($19 as json), $20, "
+ "$21, $22, $23, cast($24 as float), cast($25 as float), $26, $27, $28, $29, $30, "
+ "$31, $32, $33, $34, cast($35 as float), $36, $37, $38"
+ ")"
+ },
+
+ // Insert association of the subnet with a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_SUBNET4_SERVER",
+ PGSQL_INSERT_SUBNET_SERVER(dhcp4)
+ },
+
+ // Insert pool for a subnet.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_POOL4,
+ 7,
+ {
+ OID_TEXT, // 1 start_address - cast as inet
+ OID_TEXT, // 2 end_address - cast as inet
+ OID_INT8, // 3 subnet_id
+ OID_VARCHAR, // 4 client_class
+ OID_TEXT, // 5 require_client_classes
+ OID_TEXT, // 6 user_context - cast as json
+ OID_TIMESTAMP // 7 modification_ts
+ },
+ "INSERT_POOL4",
+ PGSQL_INSERT_POOL(dhcp4)
+ },
+
+ // Insert a shared network.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4,
+ 33,
+ {
+ OID_VARCHAR, // 1 name,
+ OID_VARCHAR, // 2 client_class,
+ OID_VARCHAR, // 3 interface,
+ OID_BOOL, // 4 match_client_id,
+ OID_TIMESTAMP, // 5 modification_ts,
+ OID_INT8, // 6 rebind_timer,
+ OID_TEXT, // 7 relay,
+ OID_INT8, // 8 renew_timer,
+ OID_TEXT, // 9 require_client_classes,
+ OID_BOOL, // 10 reservations_global,
+ OID_TEXT, // 11 user_context,
+ OID_INT8, // 12 valid_lifetime,
+ OID_INT8, // 13 min_valid_lifetime,
+ OID_INT8, // 14 max_valid_lifetime,
+ OID_BOOL, // 15 calculate_tee_times,
+ OID_TEXT, // 16 t1_percent - cast as float
+ OID_TEXT, // 17 t2_percent - cast as float
+ OID_BOOL, // 18 authoritative,
+ OID_VARCHAR, // 19 boot_file_name,
+ OID_TEXT, // 20 next_server - cast as inet
+ OID_VARCHAR, // 21 server_hostname,
+ OID_BOOL, // 22 ddns_send_updates,
+ OID_BOOL, // 23 ddns_override_no_update,
+ OID_BOOL, // 24 ddns_override_client_update,
+ OID_INT8, // 25 ddns_replace_client_name,
+ OID_VARCHAR, // 26 ddns_generated_prefix,
+ OID_VARCHAR, // 27 ddns_qualifying_suffix,
+ OID_BOOL, // 28 reservations_in_subnet,
+ OID_BOOL, // 29 reservations_out_of_pool,
+ OID_TEXT, // 30 cache_threshold - cast as float
+ OID_INT8, // 31 cache_max_age
+ OID_INT8, // 32 offer_lifetime
+ OID_VARCHAR // 33 allocator
+ },
+ "INSERT_SHARED_NETWORK4",
+ "INSERT INTO dhcp4_shared_network("
+ " name,"
+ " client_class,"
+ " interface,"
+ " match_client_id,"
+ " modification_ts,"
+ " rebind_timer,"
+ " relay,"
+ " renew_timer,"
+ " require_client_classes,"
+ " reservations_global,"
+ " user_context,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " calculate_tee_times,"
+ " t1_percent,"
+ " t2_percent,"
+ " authoritative,"
+ " boot_file_name,"
+ " next_server,"
+ " server_hostname,"
+ " ddns_send_updates,"
+ " ddns_override_no_update,"
+ " ddns_override_client_update,"
+ " ddns_replace_client_name,"
+ " ddns_generated_prefix,"
+ " ddns_qualifying_suffix,"
+ " reservations_in_subnet,"
+ " reservations_out_of_pool,"
+ " cache_threshold,"
+ " cache_max_age,"
+ " offer_lifetime,"
+ " allocator"
+ ") VALUES ("
+ "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
+ "cast($11 as json), $12, $13, $14, $15, "
+ "cast($16 as float), cast($17 as float), $18, $19, cast($20 as inet), "
+ "$21, $22, $23, $24, $25, $26, $27, $28, $29, cast($30 as float), $31, $32, $33"
+ ")"
+ },
+
+ // Insert association of the shared network with a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_SHARED_NETWORK4_SERVER,
+ 3,
+ {
+ OID_VARCHAR, // 1 shared_network_name
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_SHARED_NETWORK4_SERVER",
+ PGSQL_INSERT_SHARED_NETWORK_SERVER(dhcp4)
+ },
+
+ // Insert option definition.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4,
+ 10,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_VARCHAR, // 9 user_context
+ OID_INT8 // 10 class_id
+ },
+ "INSERT_OPTION_DEF4",
+ PGSQL_INSERT_OPTION_DEF(dhcp4)
+ },
+
+ // Insert option definition for client class.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_CLIENT_CLASS,
+ 10,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_VARCHAR, // 9 user_context
+ OID_VARCHAR // 10 class name for where clause
+ },
+ "INSERT_OPTION_DEF4_CLIENT_CLASS",
+ PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp4)
+ },
+
+ // Insert association of the option definition with a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION_DEF4_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 option_def_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_OPTION_DEF4_SERVER",
+ PGSQL_INSERT_OPTION_DEF_SERVER(dhcp4)
+ },
+
+ // Insert subnet specific option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4,
+ 13,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp4_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP // 13 modification_ts
+ },
+ "INSERT_OPTION4",
+ PGSQL_INSERT_OPTION4()
+ },
+
+ // Insert association of the DHCP option with a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_OPTION4_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 option_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_OPTION4_SERVER",
+ PGSQL_INSERT_OPTION_SERVER(dhcp4)
+ },
+
+ // Insert client class.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4,
+ 14,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 test
+ OID_TEXT, // 3 next_server - cast as inet
+ OID_VARCHAR, // 4 server_hostname
+ OID_VARCHAR, // 5 boot_file_name
+ OID_BOOL, // 6 only_if_required
+ OID_INT8, // 7 valid_lifetime
+ OID_INT8, // 8 min_valid_lifetime
+ OID_INT8, // 9 max_valid_lifetime
+ OID_BOOL, // 10 depend_on_known_directly
+ OID_VARCHAR, // 11 follow_class_name
+ OID_TIMESTAMP, // 12 modification_ts
+ OID_TEXT, // 13 user_context cast as JSON
+ OID_INT8 // 14 offer_lifetime
+ },
+ "INSERT_CLIENT_CLASS4",
+ "INSERT INTO dhcp4_client_class("
+ " name,"
+ " test,"
+ " next_server,"
+ " server_hostname,"
+ " boot_file_name,"
+ " only_if_required,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " depend_on_known_directly,"
+ " follow_class_name,"
+ " modification_ts, "
+ " user_context, "
+ " offer_lifetime "
+ ") VALUES ("
+ "$1, $2, cast($3 as inet), $4, $5, $6, $7, $8, $9, $10, $11, $12, cast($13 as JSON), $14"
+ ")"
+ },
+
+ // Insert association of a client class with a server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_SERVER,
+ 3,
+ {
+ OID_VARCHAR, // 1 class_name
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_CLIENT_CLASS4_SERVER",
+ PGSQL_INSERT_CLIENT_CLASS_SERVER(dhcp4)
+ },
+
+ // Insert client class dependency.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_CLIENT_CLASS4_DEPENDENCY,
+ 2,
+ {
+ OID_VARCHAR, // class name
+ OID_VARCHAR // dependency class name
+ },
+ "INSERT_CLIENT_CLASS4_DEPENDENCY",
+ PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp4)
+ },
+
+ // Insert server with server tag and description.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::INSERT_SERVER4,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR, // 2 description
+ OID_TIMESTAMP // 3 modification_ts
+ },
+ "INSERT_SERVER4",
+ PGSQL_INSERT_SERVER(dhcp4)
+ },
+
+ // Update existing global parameter.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_GLOBAL_PARAMETER4,
+ 6,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 value
+ OID_INT2, // 3 parameter_type
+ OID_TIMESTAMP, // 4 modification_ts
+ OID_VARCHAR, // 5 server_tag
+ OID_VARCHAR, // 6 name (of global to update)
+ },
+ "UPDATE_GLOBAL_PARAMETER4",
+ PGSQL_UPDATE_GLOBAL_PARAMETER(dhcp4)
+ },
+
+ // Update existing subnet.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4,
+ 40,
+ {
+ OID_INT8, // 1 subnet_id,
+ OID_VARCHAR, // 2 subnet_prefix
+ OID_VARCHAR, // 3 interface_4o6
+ OID_VARCHAR, // 4 interface_id_4o6
+ OID_VARCHAR, // 5 subnet_4o6
+ OID_VARCHAR, // 6 boot_file_name
+ OID_VARCHAR, // 7 client_class
+ OID_VARCHAR, // 8 interface
+ OID_BOOL, // 9 match_client_id
+ OID_TIMESTAMP, // 10 modification_ts
+ OID_TEXT, // 11 next_server - cast as inet
+ OID_INT8, // 12 rebind_timer
+ OID_TEXT, // 13 relay
+ OID_INT8, // 14 renew_timer
+ OID_TEXT, // 15 require_client_classes
+ OID_BOOL, // 16 reservations_global
+ OID_VARCHAR, // 17 server_hostname
+ OID_VARCHAR, // 18 shared_network_name
+ OID_TEXT, // 19 user_context
+ OID_INT8, // 20 valid_lifetime
+ OID_INT8, // 21 min_valid_lifetime
+ OID_INT8, // 22 max_valid_lifetime
+ OID_BOOL, // 23 calculate_tee_times
+ OID_TEXT, // 24 t1_percent - cast as float
+ OID_TEXT, // 25 t2_percent - cast as float
+ OID_BOOL, // 26 authoritative
+ OID_BOOL, // 27 ddns_send_updates
+ OID_BOOL, // 28 ddns_override_no_update
+ OID_BOOL, // 29 ddns_override_client_update
+ OID_INT8, // 30 ddns_replace_client_name
+ OID_VARCHAR, // 31 ddns_generated_prefix
+ OID_VARCHAR, // 32 ddns_qualifying_suffix
+ OID_BOOL, // 33 reservations_in_subnet
+ OID_BOOL, // 34 reservations_out_of_pool
+ OID_TEXT, // 35 cache_threshold - cast as float
+ OID_INT8, // 36 cache_max_age"
+ OID_INT8, // 37 offer_lifetime"
+ OID_VARCHAR, // 38 allocator
+ OID_INT8, // 39 subnet_id (of subnet to update)
+ OID_VARCHAR, // 40 subnet_prefix (of subnet to update)
+ },
+ "UPDATE_SUBNET4,",
+ "UPDATE dhcp4_subnet SET"
+ " subnet_id = $1,"
+ " subnet_prefix = $2,"
+ " interface_4o6 = $3,"
+ " interface_id_4o6 = $4,"
+ " subnet_4o6 = $5,"
+ " boot_file_name = $6,"
+ " client_class = $7,"
+ " interface = $8,"
+ " match_client_id = $9,"
+ " modification_ts = $10,"
+ " next_server = cast($11 as inet),"
+ " rebind_timer = $12,"
+ " relay = $13,"
+ " renew_timer = $14,"
+ " require_client_classes = $15,"
+ " reservations_global = $16,"
+ " server_hostname = $17,"
+ " shared_network_name = $18,"
+ " user_context = cast($19 as json),"
+ " valid_lifetime = $20,"
+ " min_valid_lifetime = $21,"
+ " max_valid_lifetime = $22,"
+ " calculate_tee_times = $23,"
+ " t1_percent = cast($24 as float),"
+ " t2_percent = cast($25 as float),"
+ " authoritative = $26,"
+ " ddns_send_updates = $27,"
+ " ddns_override_no_update = $28,"
+ " ddns_override_client_update = $29,"
+ " ddns_replace_client_name = $30,"
+ " ddns_generated_prefix = $31,"
+ " ddns_qualifying_suffix = $32,"
+ " reservations_in_subnet = $33,"
+ " reservations_out_of_pool = $34,"
+ " cache_threshold = cast($35 as float),"
+ " cache_max_age = $36,"
+ " offer_lifetime = $37,"
+ " allocator = $38 "
+ "WHERE subnet_id = $39 OR subnet_prefix = $40"
+ },
+
+ // Update existing shared network.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4,
+ 34,
+ {
+ OID_VARCHAR, // 1 name,
+ OID_VARCHAR, // 2 client_class,
+ OID_VARCHAR, // 3 interface,
+ OID_BOOL, // 4 match_client_id,
+ OID_TIMESTAMP, // 5 modification_ts,
+ OID_INT8, // 6 rebind_timer,
+ OID_TEXT, // 7 relay,
+ OID_INT8, // 8 renew_timer,
+ OID_TEXT, // 9 require_client_classes,
+ OID_BOOL, // 10 reservations_global,
+ OID_TEXT, // 11 user_context,
+ OID_INT8, // 12 valid_lifetime,
+ OID_INT8, // 13 min_valid_lifetime,
+ OID_INT8, // 14 max_valid_lifetime,
+ OID_BOOL, // 15 calculate_tee_times,
+ OID_TEXT, // 16 t1_percent - cast as float
+ OID_TEXT, // 17 t2_percent - cast as float
+ OID_BOOL, // 18 authoritative,
+ OID_VARCHAR, // 19 boot_file_name,
+ OID_TEXT, // 20 next_server - cast as inet
+ OID_VARCHAR, // 21 server_hostname,
+ OID_BOOL, // 22 ddns_send_updates,
+ OID_BOOL, // 23 ddns_override_no_update,
+ OID_BOOL, // 24 ddns_override_client_update,
+ OID_INT8, // 25 ddns_replace_client_name,
+ OID_VARCHAR, // 26 ddns_generated_prefix,
+ OID_VARCHAR, // 27 ddns_qualifying_suffix,
+ OID_BOOL, // 28 reservations_in_subnet,
+ OID_BOOL, // 29 reservations_out_of_pool,
+ OID_TEXT, // 30 cache_threshold - cast as float
+ OID_INT8, // 31 cache_max_age
+ OID_INT8, // 32 offer_lifetime
+ OID_VARCHAR, // 33 name (of network to update)
+ OID_VARCHAR // 34 allocator
+ },
+ "UPDATE_SHARED_NETWORK4",
+ "UPDATE dhcp4_shared_network SET"
+ " name = $1,"
+ " client_class = $2,"
+ " interface = $3,"
+ " match_client_id = $4,"
+ " modification_ts = $5,"
+ " rebind_timer = $6,"
+ " relay = $7,"
+ " renew_timer = $8,"
+ " require_client_classes = $9,"
+ " reservations_global = $10,"
+ " user_context = cast($11 as json),"
+ " valid_lifetime = $12,"
+ " min_valid_lifetime = $13,"
+ " max_valid_lifetime = $14,"
+ " calculate_tee_times = $15,"
+ " t1_percent = cast($16 as float),"
+ " t2_percent = cast($17 as float),"
+ " authoritative = $18,"
+ " boot_file_name = $19,"
+ " next_server = cast($20 as inet),"
+ " server_hostname = $21,"
+ " ddns_send_updates = $22,"
+ " ddns_override_no_update = $23,"
+ " ddns_override_client_update = $24,"
+ " ddns_replace_client_name = $25,"
+ " ddns_generated_prefix = $26,"
+ " ddns_qualifying_suffix = $27,"
+ " reservations_in_subnet = $28,"
+ " reservations_out_of_pool = $29,"
+ " cache_threshold = cast($30 as float),"
+ " cache_max_age = $31,"
+ " offer_lifetime = $32,"
+ " allocator = $33 "
+ "WHERE name = $34"
+ },
+
+ // Update existing option definition.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4,
+ 13,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_TEXT, // 9 user_context
+ OID_INT2, // 10 class_id
+ OID_VARCHAR, // 11 server_tag
+ OID_INT2, // 12 code (of option to update)
+ OID_VARCHAR, // 13 space (of option to update)
+ },
+ "UPDATE_OPTION_DEF4",
+ PGSQL_UPDATE_OPTION_DEF(dhcp4)
+ },
+
+ // Update existing client class option definition.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION_DEF4_CLIENT_CLASS,
+ 13,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_TEXT, // 9 user_context
+ OID_VARCHAR, // 10 name (of class option belongs to)
+ OID_VARCHAR, // 11 server_tag
+ OID_INT2, // 12 code (of option to update)
+ OID_VARCHAR, // 13 space (of option to update)
+ },
+ "UPDATE_OPTION_DEF4_CLIENT_CLASS",
+ PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp4)
+ },
+
+ // Update existing global option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4,
+ 16,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp4_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_VARCHAR, // 14 server_tag
+ OID_INT2, // 15 code (of option to update)
+ OID_VARCHAR, // 16 space (of option to update)
+ },
+ "UPDATE_OPTION4",
+ PGSQL_UPDATE_OPTION4_WITH_TAG(AND o.scope_id = 0 AND o.code = $15 AND o.space = $16)
+ },
+
+ // Update existing subnet level option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID,
+ 16,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp4_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 subnet_id (of option to update)
+ OID_INT2, // 15 code (of option to update)
+ OID_VARCHAR // 16 space (of option to update)
+ },
+ "UPDATE_OPTION4_SUBNET_ID",
+ PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 1 AND o.dhcp4_subnet_id = $14 AND o.code = $15 AND o.space = $16)
+ },
+
+ // Update existing pool level option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_POOL_ID,
+ 16,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp4_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pool_id (of option to update)
+ OID_INT2, // 15 code (of option to update)
+ OID_VARCHAR // 16 space (of option to update)
+ },
+ "UPDATE_OPTION4_POOL_ID",
+ PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 5 AND o.pool_id = $14 AND o.code = $15 AND o.space = $16)
+ },
+
+ // Update existing shared network level option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK,
+ 16,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp4_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_VARCHAR, // 14 shared_network_name (of option to update)
+ OID_INT2, // 15 code (of option to update)
+ OID_VARCHAR // 16 space (of option to update)
+ },
+ "UPDATE_OPTION4_SHARED_NETWORK",
+ PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $14 AND o.code = $15 AND o.space = $16)
+ },
+
+ // Update existing client class level option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_CLIENT_CLASS,
+ 16,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp4_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_VARCHAR, // 14 dhcp_client_class (of option to update)
+ OID_INT2, // 15 code (of option to update)
+ OID_VARCHAR, // 16 space (of option to update)
+ },
+ "UPDATE_OPTION4_CLIENT_CLASS",
+ PGSQL_UPDATE_OPTION4_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $14 AND o.code = $15 AND o.space = $16)
+ },
+
+ // Update existing client class with specifying its position.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4,
+ 15,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 test
+ OID_TEXT, // 3 next_server - cast as inet
+ OID_VARCHAR, // 4 server_hostname
+ OID_VARCHAR, // 5 boot_file_name
+ OID_BOOL, // 6 only_if_required
+ OID_INT8, // 7 valid_lifetime
+ OID_INT8, // 8 min_valid_lifetime
+ OID_INT8, // 9 max_valid_lifetime
+ OID_BOOL, // 10 depend_on_known_directly
+ OID_VARCHAR, // 11 follow_class_name
+ OID_TIMESTAMP, // 12 modification_ts
+ OID_TEXT, // 13 user_context cast as JSON
+ OID_INT8, // 14 offer_lifetime
+ OID_VARCHAR // 15 name (of class to update)
+ },
+ "UPDATE_CLIENT_CLASS4",
+ PGSQL_UPDATE_CLIENT_CLASS4("follow_class_name = $11,")
+ },
+
+ // Update existing client class without specifying its position.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_CLIENT_CLASS4_SAME_POSITION,
+ 15,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 test
+ OID_TEXT, // 3 next_server - cast as inet
+ OID_VARCHAR, // 4 server_hostname
+ OID_VARCHAR, // 5 boot_file_name
+ OID_BOOL, // 6 only_if_required
+ OID_INT8, // 7 valid_lifetime
+ OID_INT8, // 8 min_valid_lifetime
+ OID_INT8, // 9 max_valid_lifetime
+ OID_BOOL, // 10 depend_on_known_directly
+ OID_VARCHAR, // 11 follow_class_name
+ OID_TIMESTAMP, // 12 modification_ts
+ OID_TEXT, // 13 user_context cast as JSON
+ OID_INT8, // 14 offer_lifetime
+ OID_VARCHAR // 15 name (of class to update)
+ },
+ "UPDATE_CLIENT_CLASS4_SAME_POSITION",
+ PGSQL_UPDATE_CLIENT_CLASS4("")
+ },
+
+ // Update existing server, e.g. server description.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::UPDATE_SERVER4,
+ 4,
+ {
+ OID_VARCHAR, // 1 tag
+ OID_VARCHAR, // 2 description
+ OID_TIMESTAMP, // 3 modification_ts
+ OID_VARCHAR // 4 tag (of server to update)
+ },
+ "UPDATE_SERVER4",
+ PGSQL_UPDATE_SERVER(dhcp4)
+ },
+
+ // Delete global parameter by name.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 name of parameter
+ },
+ "DELETE_GLOBAL_PARAMETER4",
+ PGSQL_DELETE_GLOBAL_PARAMETER(dhcp4, AND g.name = $2)
+ },
+
+ // Delete all global parameters.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_GLOBAL_PARAMETERS4",
+ PGSQL_DELETE_GLOBAL_PARAMETER(dhcp4)
+ },
+
+ // Delete all global parameters which are unassigned to any servers.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_GLOBAL_PARAMETERS4_UNASSIGNED",
+ PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp4)
+ },
+
+ // Delete subnet by id with specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_WITH_TAG,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8 // 2 subnet_id
+ },
+ "DELETE_SUBNET4_ID_WITH_TAG",
+ PGSQL_DELETE_SUBNET_WITH_TAG(dhcp4, AND s.subnet_id = $2)
+ },
+
+ // Delete subnet by id without specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID_ANY,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "DELETE_SUBNET4_ID_ANY",
+ PGSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.subnet_id = $1)
+ },
+
+ // Delete subnet by prefix with specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_WITH_TAG,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_SUBNET4_PREFIX_WITH_TAG",
+ PGSQL_DELETE_SUBNET_WITH_TAG(dhcp4, AND s.subnet_prefix = $2)
+ },
+
+ // Delete subnet by prefix without specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_PREFIX_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "DELETE_SUBNET4_PREFIX_ANY",
+ PGSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.subnet_prefix = $1)
+ },
+
+ // Delete all subnets.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_SUBNETS4",
+ PGSQL_DELETE_SUBNET_WITH_TAG(dhcp4)
+ },
+
+ // Delete all unassigned subnets.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_SUBNETS4_UNASSIGNED",
+ PGSQL_DELETE_SUBNET_UNASSIGNED(dhcp4)
+ },
+
+ // Delete all subnets for a shared network.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME,
+ 1,
+ {
+ OID_VARCHAR // 1 shared_network_name
+ },
+ "DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME",
+ PGSQL_DELETE_SUBNET_ANY(dhcp4, WHERE s.shared_network_name = $1)
+ },
+
+ // Delete associations of a subnet with server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_SERVER,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "DELETE_SUBNET4_SERVER",
+ PGSQL_DELETE_SUBNET_SERVER(dhcp4),
+ },
+
+ // Delete pools for a subnet.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_POOLS4,
+ 2,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_POOLS4",
+ PGSQL_DELETE_POOLS(dhcp4)
+ },
+
+ // Delete shared network by name with specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_WITH_TAG,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 shared_network_name
+ },
+ "DELETE_SHARED_NETWORK4_NAME_WITH_TAG",
+ PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4, AND n.name = $2)
+ },
+
+ // Delete shared network by name without specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 shared_network_name
+ },
+ "DELETE_SHARED_NETWORK4_NAME_ANY",
+ PGSQL_DELETE_SHARED_NETWORK_ANY(dhcp4, WHERE n.name = $1)
+ },
+
+ // Delete all shared networks.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_SHARED_NETWORKS4",
+ PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp4)
+ },
+
+ // Delete all unassigned shared networks.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED",
+ PGSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp4)
+ },
+
+ // Delete associations of a shared network with server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_SERVER,
+ 1,
+ {
+ OID_VARCHAR // 1 shared_network_name
+ },
+ "DELETE_SHARED_NETWORK4_SERVER",
+ PGSQL_DELETE_SHARED_NETWORK_SERVER(dhcp4)
+ },
+
+ // Delete option definition.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEF4_CODE_NAME,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION_DEF4_CODE_NAME",
+ PGSQL_DELETE_OPTION_DEF(dhcp4, AND code = $2 AND space = $3)
+ },
+
+ // Delete all option definitions.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_OPTION_DEFS4",
+ PGSQL_DELETE_OPTION_DEF(dhcp4)
+ },
+
+ // Delete all option definitions which are assigned to no servers.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_OPTION_DEFS4_UNASSIGNED",
+ PGSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp4)
+ },
+
+ // Delete client class specific option definitions.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION_DEFS4_CLIENT_CLASS,
+ 1,
+ {
+ OID_VARCHAR // 1 class name
+ },
+ "DELETE_OPTION_DEFS4_CLIENT_CLASS",
+ PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp4)
+ },
+
+ // Delete single global option.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION4",
+ PGSQL_DELETE_OPTION_WITH_TAG(dhcp4, AND o.scope_id = 0 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Delete all global options which are unassigned to any servers.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_GLOBAL_OPTIONS4_UNASSIGNED",
+ PGSQL_DELETE_OPTION_UNASSIGNED(dhcp4, AND o.scope_id = 0)
+ },
+
+ // Delete single option from a subnet.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID,
+ 3,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION4_SUBNET_ID",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp4,
+ WHERE o.scope_id = 1 AND o.dhcp4_subnet_id = $1 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Delete single option from a pool.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_POOL_RANGE,
+ 4,
+ {
+ OID_TEXT, // 1 start_address - cast as inet
+ OID_TEXT, // 2 start_address - cast as inet
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "DELETE_OPTION4_POOL_RANGE",
+ PGSQL_DELETE_OPTION_POOL_RANGE(dhcp4, o.scope_id = 5 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Delete single option from a shared network.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SHARED_NETWORK,
+ 3,
+ {
+ OID_VARCHAR, // 1 shared_network_name
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION4_SHARED_NETWORK",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp4,
+ WHERE o.scope_id = 4 AND o.shared_network_name = $1 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Delete options belonging to a subnet.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SUBNET_ID_PREFIX,
+ 2,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_OPTIONS4_SUBNET_ID_PREFIX",
+ PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX(dhcp4)
+ },
+
+ // Delete options belonging to a shared_network.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SHARED_NETWORK,
+ 1,
+ {
+ OID_VARCHAR // shared_network_name
+ },
+ "DELETE_OPTIONS4_SHARED_NETWORK",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp4, WHERE o.scope_id = 4 AND o.shared_network_name = $1)
+ },
+
+ // Delete options belonging to a client class.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_CLIENT_CLASS,
+ 1,
+ {
+ OID_VARCHAR // dhcp_client_class
+ },
+ "DELETE_OPTIONS4_CLIENT_CLASS",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp4, WHERE o.scope_id = 2 AND o.dhcp_client_class = $1)
+ },
+
+ // Delete all dependencies of a client class.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_DEPENDENCY,
+ 1,
+ {
+ OID_VARCHAR, // 1 class name
+ },
+ "DELETE_CLIENT_CLASS4_DEPENDENCY",
+ PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp4)
+ },
+
+ // Delete associations of a client class with server.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_SERVER,
+ 1,
+ {
+ OID_VARCHAR // 1 class name
+ },
+ "DELETE_CLIENT_CLASS4_SERVER",
+ PGSQL_DELETE_CLIENT_CLASS_SERVER(dhcp4),
+ },
+
+ // Delete all client classes.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_CLIENT_CLASSES4",
+ PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp4)
+ },
+
+ // Delete all unassigned client classes.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED",
+ PGSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp4)
+ },
+
+ // Delete specified client class.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 name
+ },
+ "DELETE_CLIENT_CLASS4",
+ PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp4, AND name = $2)
+ },
+
+ // Delete any client class with a given name.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_CLIENT_CLASS4_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 name
+ },
+ "DELETE_CLIENT_CLASS4_ANY",
+ PGSQL_DELETE_CLIENT_CLASS_ANY(dhcp4, AND name = $1)
+ },
+
+ // Delete a server by tag.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_SERVER4,
+ 1,
+ {
+ OID_VARCHAR // server_tag
+ },
+ "DELETE_SERVER4",
+ PGSQL_DELETE_SERVER(dhcp4)
+ },
+
+ // Deletes all servers except logical server 'all'.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SERVERS4,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_SERVERS4",
+ PGSQL_DELETE_ALL_SERVERS(dhcp4)
+ },
+
+ // Fetches the last sequence id for the given table and column.
+ {
+ // PgSqlConfigBackendDHCPv4Impl::GET_LAST_INSERT_ID4,
+ // args are: table name, sequence column name
+ 2,
+ {
+ OID_VARCHAR,
+ OID_VARCHAR
+ },
+ "GET_LAST_INSERT_ID4",
+ "SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE($1, $2))"
+ }
+}
+};
+
+} // end anonymous namespace
+
+PgSqlConfigBackendDHCPv4Impl::PgSqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters)
+ : PgSqlConfigBackendImpl(parameters, &PgSqlConfigBackendDHCPv4Impl::dbReconnect,
+ PgSqlConfigBackendDHCPv4Impl::GET_LAST_INSERT_ID4) {
+ // Prepare query statements. Those are will be only used to retrieve
+ // information from the database, so they can be used even if the
+ // database is read only for the current user.
+ conn_.prepareStatements(tagged_statements.begin(),
+ tagged_statements.end());
+// @todo As part of enabling read-only CB access, statements need to
+// be limited:
+// tagged_statements.begin() + WRITE_STMTS_BEGIN);
+
+ // Create unique timer name per instance.
+ timer_name_ = "PgSqlConfigBackend4[";
+ timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
+ timer_name_ += "]DbReconnectTimer";
+
+ // Create ReconnectCtl for this connection.
+ conn_.makeReconnectCtl(timer_name_);
+}
+
+PgSqlConfigBackendDHCPv4Impl::~PgSqlConfigBackendDHCPv4Impl() {
+}
+
+PgSqlTaggedStatement&
+PgSqlConfigBackendDHCPv4Impl::getStatement(size_t index) const {
+ if (index >= tagged_statements.size()) {
+ isc_throw(BadValue, "PgSqlConfigBackendDHCPv4Impl::getStatement index: "
+ << index << ", is invalid");
+ }
+
+ return(tagged_statements[index]);
+}
+
+PgSqlConfigBackendDHCPv4::PgSqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters)
+ : impl_(new PgSqlConfigBackendDHCPv4Impl(parameters)), base_impl_(impl_) {
+}
+
+bool
+PgSqlConfigBackendDHCPv4::isUnusable() {
+ return (impl_->conn_.isUnusable());
+}
+
+DatabaseConnection::ParameterMap
+PgSqlConfigBackendDHCPv4::getParameters() const {
+ return (impl_->getParameters());
+}
+
+Subnet4Ptr
+PgSqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET4_BY_PREFIX)
+ .arg(subnet_prefix);
+ return (impl_->getSubnet4(server_selector, subnet_prefix));
+}
+
+Subnet4Ptr
+PgSqlConfigBackendDHCPv4::getSubnet4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID)
+ .arg(subnet_id);
+ return (impl_->getSubnet4(server_selector, subnet_id));
+}
+
+Subnet4Collection
+PgSqlConfigBackendDHCPv4::getAllSubnets4(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS4);
+ Subnet4Collection subnets;
+ impl_->getAllSubnets4(server_selector, subnets);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS4_RESULT)
+ .arg(subnets.size());
+ return (subnets);
+}
+
+Subnet4Collection
+PgSqlConfigBackendDHCPv4::getModifiedSubnets4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS4)
+ .arg(util::ptimeToText(modification_time));
+ Subnet4Collection subnets;
+ impl_->getModifiedSubnets4(server_selector, modification_time, subnets);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT)
+ .arg(subnets.size());
+ return (subnets);
+}
+
+Subnet4Collection
+PgSqlConfigBackendDHCPv4::getSharedNetworkSubnets4(const ServerSelector& /* server_selector */,
+ const std::string& shared_network_name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4)
+ .arg(shared_network_name);
+ Subnet4Collection subnets;
+ impl_->getSharedNetworkSubnets4(ServerSelector::ANY(), shared_network_name, subnets);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT)
+ .arg(subnets.size());
+ return (subnets);
+}
+
+SharedNetwork4Ptr
+PgSqlConfigBackendDHCPv4::getSharedNetwork4(const ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK4)
+ .arg(name);
+ return (impl_->getSharedNetwork4(server_selector, name));
+}
+
+SharedNetwork4Collection
+PgSqlConfigBackendDHCPv4::getAllSharedNetworks4(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS4);
+ SharedNetwork4Collection shared_networks;
+ impl_->getAllSharedNetworks4(server_selector, shared_networks);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT)
+ .arg(shared_networks.size());
+ return (shared_networks);
+}
+
+SharedNetwork4Collection
+PgSqlConfigBackendDHCPv4::getModifiedSharedNetworks4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4)
+ .arg(util::ptimeToText(modification_time));
+ SharedNetwork4Collection shared_networks;
+ impl_->getModifiedSharedNetworks4(server_selector, modification_time, shared_networks);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT)
+ .arg(shared_networks.size());
+ return (shared_networks);
+}
+
+OptionDefinitionPtr
+PgSqlConfigBackendDHCPv4::getOptionDef4(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION_DEF4)
+ .arg(code).arg(space);
+ return (impl_->getOptionDef(PgSqlConfigBackendDHCPv4Impl::GET_OPTION_DEF4_CODE_SPACE,
+ server_selector, code, space));
+}
+
+OptionDefContainer
+PgSqlConfigBackendDHCPv4::getAllOptionDefs4(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS4);
+ OptionDefContainer option_defs;
+ impl_->getAllOptionDefs(PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4,
+ server_selector, option_defs);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT)
+ .arg(option_defs.size());
+ return (option_defs);
+}
+
+OptionDefContainer
+PgSqlConfigBackendDHCPv4::getModifiedOptionDefs4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS4)
+ .arg(util::ptimeToText(modification_time));
+ OptionDefContainer option_defs;
+ impl_->getModifiedOptionDefs(PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4,
+ server_selector, modification_time, option_defs);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT)
+ .arg(option_defs.size());
+ return (option_defs);
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendDHCPv4::getOption4(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION4)
+ .arg(code).arg(space);
+ return (impl_->getOption(PgSqlConfigBackendDHCPv4Impl::GET_OPTION4_CODE_SPACE,
+ Option::V4, server_selector, code, space));
+}
+
+OptionContainer
+PgSqlConfigBackendDHCPv4::getAllOptions4(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS4);
+ OptionContainer options = impl_->getAllOptions(PgSqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4,
+ Option::V4, server_selector);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS4_RESULT)
+ .arg(options.size());
+ return (options);
+}
+
+OptionContainer
+PgSqlConfigBackendDHCPv4::getModifiedOptions4(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS4)
+ .arg(util::ptimeToText(modification_time));
+ OptionContainer options = impl_->getModifiedOptions(PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTIONS4,
+ Option::V4, server_selector, modification_time);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT)
+ .arg(options.size());
+ return (options);
+}
+
+StampedValuePtr
+PgSqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_GLOBAL_PARAMETER4)
+ .arg(name);
+ return (impl_->getGlobalParameter4(server_selector, name));
+}
+
+StampedValueCollection
+PgSqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4);
+ StampedValueCollection parameters;
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ impl_->getGlobalParameters(PgSqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4,
+ in_bindings, parameters);
+ }
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT)
+ .arg(parameters.size());
+ return (parameters);
+}
+
+StampedValueCollection
+PgSqlConfigBackendDHCPv4::getModifiedGlobalParameters4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4)
+ .arg(util::ptimeToText(modification_time));
+ StampedValueCollection parameters;
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addTimestamp(modification_time);
+
+ impl_->getGlobalParameters(PgSqlConfigBackendDHCPv4Impl::GET_MODIFIED_GLOBAL_PARAMETERS4,
+ in_bindings, parameters);
+ }
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT)
+ .arg(parameters.size());
+ return (parameters);
+}
+
+ClientClassDefPtr
+PgSqlConfigBackendDHCPv4::getClientClass4(const db::ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_CLIENT_CLASS4)
+ .arg(name);
+ return (impl_->getClientClass4(server_selector, name));
+}
+
+ClientClassDictionary
+PgSqlConfigBackendDHCPv4::getAllClientClasses4(const db::ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES4);
+ ClientClassDictionary client_classes;
+ impl_->getAllClientClasses4(server_selector, client_classes);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT)
+ .arg(client_classes.getClasses()->size());
+ return (client_classes);
+}
+
+ClientClassDictionary
+PgSqlConfigBackendDHCPv4::getModifiedClientClasses4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4)
+ .arg(util::ptimeToText(modification_time));
+ ClientClassDictionary client_classes;
+ impl_->getModifiedClientClasses4(server_selector, modification_time, client_classes);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT)
+ .arg(client_classes.getClasses()->size());
+ return (client_classes);
+}
+
+AuditEntryCollection
+PgSqlConfigBackendDHCPv4::getRecentAuditEntries(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t& modification_id) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4)
+ .arg(util::ptimeToText(modification_time))
+ .arg(modification_id);
+ AuditEntryCollection audit_entries;
+ impl_->getRecentAuditEntries(PgSqlConfigBackendDHCPv4Impl::GET_AUDIT_ENTRIES4_TIME,
+ server_selector, modification_time,
+ modification_id, audit_entries);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT)
+ .arg(audit_entries.size());
+ return (audit_entries);
+}
+
+ServerCollection
+PgSqlConfigBackendDHCPv4::getAllServers4() const {
+ ServerCollection servers;
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS4);
+ impl_->getAllServers(PgSqlConfigBackendDHCPv4Impl::GET_ALL_SERVERS4,
+ servers);
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS4_RESULT)
+ .arg(servers.size());
+ return (servers);
+}
+
+ServerPtr
+PgSqlConfigBackendDHCPv4::getServer4(const data::ServerTag& server_tag) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SERVER4)
+ .arg(server_tag.get());
+ return (impl_->getServer(PgSqlConfigBackendDHCPv4Impl::GET_SERVER4, server_tag));
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateSubnet4(const ServerSelector& server_selector,
+ const Subnet4Ptr& subnet) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SUBNET4)
+ .arg(subnet);
+ impl_->createUpdateSubnet4(server_selector, subnet);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateSharedNetwork4(const ServerSelector& server_selector,
+ const SharedNetwork4Ptr& shared_network) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4)
+ .arg(shared_network->getName());
+ impl_->createUpdateSharedNetwork4(server_selector, shared_network);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateOptionDef4(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION_DEF4)
+ .arg(option_def->getName()).arg(option_def->getCode());
+ impl_->createUpdateOptionDef4(server_selector, option_def);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION4);
+ impl_->createUpdateOption4(server_selector, option);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4)
+ .arg(shared_network_name);
+ impl_->createUpdateOption4(server_selector, shared_network_name, option, false);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4)
+ .arg(subnet_id);
+ impl_->createUpdateOption4(server_selector, subnet_id, option, false);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& server_selector,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4)
+ .arg(pool_start_address.toText()).arg(pool_end_address.toText());
+ impl_->createUpdateOption4(server_selector, pool_start_address, pool_end_address,
+ option);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateGlobalParameter4(const ServerSelector& server_selector,
+ const StampedValuePtr& value) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4)
+ .arg(value->getName());
+ impl_->createUpdateGlobalParameter4(server_selector, value);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateClientClass4(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4)
+ .arg(client_class->getName());
+ impl_->createUpdateClientClass4(server_selector, client_class, follow_class_name);
+}
+
+void
+PgSqlConfigBackendDHCPv4::createUpdateServer4(const ServerPtr& server) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SERVER4)
+ .arg(server->getServerTagAsText());
+ impl_->createUpdateServer(PgSqlConfigBackendDHCPv4Impl::CREATE_AUDIT_REVISION,
+ PgSqlConfigBackendDHCPv4Impl::INSERT_SERVER4,
+ PgSqlConfigBackendDHCPv4Impl::UPDATE_SERVER4,
+ server);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET4)
+ .arg(subnet_prefix);
+ uint64_t result = impl_->deleteSubnet4(server_selector, subnet_prefix);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteSubnet4(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4)
+ .arg(subnet_id);
+ uint64_t result = impl_->deleteSubnet4(server_selector, subnet_id);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteAllSubnets4(const ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS4);
+
+ int index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets",
+ "deleted all subnets", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteSharedNetworkSubnets4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name) {
+ if (!server_selector.amAny()) {
+ isc_throw(InvalidOperation, "deleting all subnets from a shared "
+ "network requires using ANY server selector");
+ }
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4)
+ .arg(shared_network_name);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SUBNETS4_SHARED_NETWORK_NAME,
+ server_selector,
+ "deleting all subnets for a shared network",
+ "deleted all subnets for a shared network",
+ true, shared_network_name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteSharedNetwork4(const ServerSelector& server_selector,
+ const std::string& name) {
+ /// @todo Using UNASSIGNED selector is allowed by the CB API but we don't have
+ /// dedicated query for this at the moment. The user should use ANY to delete
+ /// the shared network by name.
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "deleting an unassigned shared network requires "
+ "an explicit server tag or using ANY server. The UNASSIGNED server "
+ "selector is currently not supported");
+ }
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK4)
+ .arg(name);
+
+ int index = (server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_ANY :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_SHARED_NETWORK4_NAME_WITH_TAG);
+ uint64_t result = impl_->deleteTransactional(index, server_selector,
+ "deleting a shared network",
+ "shared network deleted", true, name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteAllSharedNetworks4(const ServerSelector& server_selector) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not"
+ " supported");
+ }
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4);
+
+ int index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_SHARED_NETWORKS4);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks",
+ "deleted all shared networks", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteOptionDef4(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF4)
+ .arg(code).arg(space);
+ uint64_t result = impl_->deleteOptionDef4(server_selector, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteAllOptionDefs4(const ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS4);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4,
+ server_selector, "deleting all option definitions",
+ "deleted all option definitions", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION4)
+ .arg(code).arg(space);
+ uint64_t result = impl_->deleteOption4(server_selector, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ /// @todo In the future we might use the server selector to make sure that the
+ /// option is only deleted if the pool belongs to a given server. For now, we
+ /// just delete it when there is a match with the parent object.
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4)
+ .arg(shared_network_name).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption4(ServerSelector::ANY(), shared_network_name,
+ code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ /// @todo In the future we might use the server selector to make sure that the
+ /// option is only deleted if the pool belongs to a given server. For now, we
+ /// just delete it when there is a match with the parent object.
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4)
+ .arg(subnet_id).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption4(ServerSelector::ANY(), subnet_id, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const uint16_t code,
+ const std::string& space) {
+ /// @todo In the future we might use the server selector to make sure that the
+ /// option is only deleted if the pool belongs to a given server. For now, we
+ /// just delete it when there is a match with the parent object.
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION4)
+ .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption4(ServerSelector::ANY(), pool_start_address,
+ pool_end_address, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteGlobalParameter4(const ServerSelector& server_selector,
+ const std::string& name) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER4)
+ .arg(name);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4,
+ server_selector, "deleting global parameter",
+ "global parameter deleted", false, name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteAllGlobalParameters4(const ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4,
+ server_selector, "deleting all global parameters",
+ "all global parameters deleted", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteClientClass4(const db::ServerSelector& server_selector,
+ const std::string& name) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS4)
+ .arg(name);
+ auto result = impl_->deleteClientClass4(server_selector, name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteAllClientClasses4(const db::ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4);
+
+ int index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4_UNASSIGNED :
+ PgSqlConfigBackendDHCPv4Impl::DELETE_ALL_CLIENT_CLASSES4);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes",
+ "deleted all client classes", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteServer4(const ServerTag& server_tag) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER4)
+ .arg(server_tag.get());
+ uint64_t result = impl_->deleteServer4(server_tag);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv4::deleteAllServers4() {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS4);
+ uint64_t result = impl_->deleteAllServers4();
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS4_RESULT)
+ .arg(result);
+ return (result);
+}
+
+std::string
+PgSqlConfigBackendDHCPv4::getType() const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_TYPE4);
+ return (impl_->getType());
+}
+
+std::string
+PgSqlConfigBackendDHCPv4::getHost() const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_HOST4);
+ return (impl_->getHost());
+}
+
+uint16_t
+PgSqlConfigBackendDHCPv4::getPort() const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_PORT4);
+ return (impl_->getPort());
+}
+
+bool
+PgSqlConfigBackendDHCPv4::registerBackendType() {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_REGISTER_BACKEND_TYPE4);
+ return (
+ dhcp::ConfigBackendDHCPv4Mgr::instance().registerBackendFactory("postgresql",
+ [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv4Ptr {
+ return (dhcp::PgSqlConfigBackendDHCPv4Ptr(new dhcp::PgSqlConfigBackendDHCPv4(params)));
+ })
+ );
+}
+
+void
+PgSqlConfigBackendDHCPv4::unregisterBackendType() {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_UNREGISTER_BACKEND_TYPE4);
+ dhcp::ConfigBackendDHCPv4Mgr::instance().unregisterBackendFactory("postgresql");
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h
new file mode 100644
index 0000000..d78698a
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp4.h
@@ -0,0 +1,631 @@
+// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PGSQL_CONFIG_BACKEND_DHCP4_H
+#define PGSQL_CONFIG_BACKEND_DHCP4_H
+
+#include <pgsql_cb_impl.h>
+#include <database/database_connection.h>
+#include <dhcpsrv/client_class_def.h>
+#include <dhcpsrv/config_backend_dhcp4.h>
+#include <pgsql_cb_log.h>
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dhcp {
+
+class PgSqlConfigBackendDHCPv4Impl;
+
+/// @brief Implementation of the PgSql Configuration Backend for
+/// Kea DHCPv4 server.
+///
+/// All POSIX times specified in the methods belonging to this
+/// class must be local times.
+///
+/// The server selection mechanisms used by this backend generally adhere
+/// to the rules described for @c ConfigBackendDHCPv4, but support for
+/// some of the selectors is not implemented. Whenever this is the case,
+/// the methods throw @c isc::NotImplemented exception.
+class PgSqlConfigBackendDHCPv4 : public ConfigBackendDHCPv4 {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ explicit PgSqlConfigBackendDHCPv4(const db::DatabaseConnection::ParameterMap& parameters);
+
+ /// @brief Retrieves a single subnet by subnet_prefix.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_prefix Prefix of the subnet to be retrieved.
+ /// @return Pointer to the retrieved subnet or NULL if not found.
+ virtual Subnet4Ptr
+ getSubnet4(const db::ServerSelector& server_selector,
+ const std::string& subnet_prefix) const;
+
+ /// @brief Retrieves a single subnet by subnet identifier.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of a subnet to be retrieved.
+ /// @return Pointer to the retrieved subnet or NULL if not found.
+ virtual Subnet4Ptr
+ getSubnet4(const db::ServerSelector& server_selector, const SubnetID& subnet_id) const;
+
+ /// @brief Retrieves all subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of subnets or empty collection if no subnet found.
+ virtual Subnet4Collection
+ getAllSubnets4(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves subnets modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound subnet modification time.
+ /// @return Collection of subnets or empty collection if no subnet found.
+ virtual Subnet4Collection
+ getModifiedSubnets4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves all subnets belonging to a specified shared network.
+ ///
+ /// The server selector is currently ignored by this method. All subnets
+ /// for the given shared network are returned regardless of their
+ /// associations with the servers.
+ ///
+ /// @param server_selector Server selector (currently ignored).
+ /// @param shared_network_name Name of the shared network for which the
+ /// subnets should be retrieved.
+ /// @return Collection of subnets or empty collection if no subnet found.
+ virtual Subnet4Collection
+ getSharedNetworkSubnets4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name) const;
+
+ /// @brief Retrieves shared network by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the shared network to be retrieved.
+ /// @return Pointer to the shared network or NULL if not found.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual SharedNetwork4Ptr
+ getSharedNetwork4(const db::ServerSelector& server_selector,
+ const std::string& name) const;
+
+ /// @brief Retrieves all shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of shared network or empty collection if
+ /// no shared network found.
+ virtual SharedNetwork4Collection
+ getAllSharedNetworks4(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves shared networks modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound shared network modification time.
+ /// @return Collection of shared network or empty collection if
+ /// no shared network found.
+ virtual SharedNetwork4Collection
+ getModifiedSharedNetworks4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves single option definition by code and space.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the option to be retrieved.
+ /// @param space Option space of the option to be retrieved.
+ /// @return Pointer to the option definition or NULL if not found.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual OptionDefinitionPtr
+ getOptionDef4(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space) const;
+
+ /// @brief Retrieves all option definitions.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of option definitions or empty collection if
+ /// no option definition found.
+ virtual OptionDefContainer
+ getAllOptionDefs4(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves option definitions modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound option definition modification
+ /// time.
+ /// @return Collection of option definitions or empty collection if
+ /// no option definition found.
+ virtual OptionDefContainer
+ getModifiedOptionDefs4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves single option by code and space.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Pointer to the retrieved option descriptor or null if
+ /// no option was found.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual OptionDescriptorPtr
+ getOption4(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space) const;
+
+ /// @brief Retrieves all global options.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of global options or empty collection if no
+ /// option found.
+ virtual OptionContainer
+ getAllOptions4(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves option modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound option modification time.
+ /// @return Collection of global options or empty collection if no
+ /// option found.
+ virtual OptionContainer
+ getModifiedOptions4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves global parameter value.
+ ///
+ /// Typically, the server selector used for this query should be set to
+ /// ONE. It is possible to use the MULTIPLE server selector but in that
+ /// case only the first found parameter is returned.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the global parameter to be retrieved.
+ /// @return Value of the global parameter.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual data::StampedValuePtr
+ getGlobalParameter4(const db::ServerSelector& server_selector,
+ const std::string& name) const;
+
+ /// @brief Retrieves all global parameters.
+ ///
+ /// Using the server selector it is possible to fetch the parameters for
+ /// one or more servers. The following list describes what parameters are
+ /// returned depending on the server selector specified:
+ /// - ALL: only common parameters are returned which are associated with
+ /// the logical server 'all'. No parameters associated with the explicit
+ /// server tags are returned.
+ ///
+ /// - ONE: parameters used by the particular sever are returned. This includes
+ /// parameters associated with the particular server (identified by tag)
+ /// and parameters associated with the logical server 'all' when server
+ /// specific parameters are not given. For example, if there is a
+ /// renew-timer specified for 'server1' tag, different value of the
+ /// renew-timer specified for 'all' servers and a rebind-timer specified
+ /// for 'all' servers, the caller will receive renew-timer value associated
+ /// with the server1 and the rebind-timer value associated with all servers,
+ /// because there is no explicit rebind-timer specified for server1.
+ ///
+ /// - MULTIPLE: parameters used by multiple servers, but those associated
+ /// with specific server tags take precedence over the values specified for
+ /// 'all' servers. This is similar to the case of ONE server described
+ /// above. The effect of querying for parameters belonging to multiple
+ /// servers is the same as issuing multiple queries with ONE server
+ /// being selected multiple times.
+ ///
+ /// - UNASSIGNED: parameters not associated with any servers.
+ ///
+ ///
+ /// @param server_selector Server selector.
+ virtual data::StampedValueCollection
+ getAllGlobalParameters4(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves global parameters modified after specified time.
+ ///
+ /// @param modification_time Lower bound modification time.
+ /// @return Collection of modified global parameters.
+ virtual data::StampedValueCollection
+ getModifiedGlobalParameters4(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Client class name.
+ /// @return Pointer to the retrieved client class.
+ virtual ClientClassDefPtr
+ getClientClass4(const db::ServerSelector& selector, const std::string& name) const;
+
+ /// @brief Retrieves all client classes.
+ ///
+ /// @param selector Server selector.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getAllClientClasses4(const db::ServerSelector& selector) const;
+
+ /// @brief Retrieves client classes modified after specified time.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Modification time.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getModifiedClientClasses4(const db::ServerSelector& selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves the most recent audit entries.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Timestamp being a lower limit for the returned
+ /// result set, i.e. entries later than specified time are returned.
+ /// @param modification_id Identifier being a lower limit for the returned
+ /// result set, used when two (or more) entries have the same
+ /// modification_time.
+ /// @return Collection of audit entries.
+ virtual db::AuditEntryCollection
+ getRecentAuditEntries(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t& modification_id) const;
+
+ /// @brief Retrieves all servers.
+ ///
+ /// This method returns the list of servers excluding the logical server
+ /// 'all'.
+ ///
+ /// @return Collection of servers from the backend.
+ virtual db::ServerCollection
+ getAllServers4() const;
+
+ /// @brief Retrieves a server.
+ ///
+ /// @param server_tag Tag of the server to be retrieved.
+ /// @return Pointer to the server instance or null pointer if no server
+ /// with the particular tag was found.
+ virtual db::ServerPtr
+ getServer4(const data::ServerTag& server_tag) const;
+
+ /// @brief Creates or updates a subnet.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Subnet to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateSubnet4(const db::ServerSelector& server_selector,
+ const Subnet4Ptr& subnet);
+
+ /// @brief Creates or updates a shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network Shared network to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateSharedNetwork4(const db::ServerSelector& server_selector,
+ const SharedNetwork4Ptr& shared_network);
+
+ /// @brief Creates or updates an option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Option definition to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOptionDef4(const db::ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def);
+
+ /// @brief Creates or updates global option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption4(const db::ServerSelector& server_selector,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates shared network level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of a shared network to which option
+ /// belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates subnet level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of a subnet to which option belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption4(const db::ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the pool to which
+ /// the option belongs.
+ /// @param pool_end_address Upper bound address of the pool to which the
+ /// option belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption4(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the global parameter.
+ /// @param value Value of the global parameter.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateGlobalParameter4(const db::ServerSelector& server_selector,
+ const data::StampedValuePtr& value);
+
+ /// @brief Creates or updates DHCPv4 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Client class to be added or updated.
+ /// @param follow_class_name name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ virtual void
+ createUpdateClientClass4(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name);
+
+ /// @brief Creates or updates a server.
+ ///
+ /// @param server Instance of the server to be stored.
+ /// @throw InvalidOperation when trying to create a duplicate or
+ /// update the logical server 'all'.
+ virtual void
+ createUpdateServer4(const db::ServerPtr& server);
+
+ /// @brief Deletes subnet by prefix.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_prefix Prefix of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteSubnet4(const db::ServerSelector& server_selector,
+ const std::string& subnet_prefix);
+
+ /// @brief Deletes subnet by identifier.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteSubnet4(const db::ServerSelector& server_selector, const SubnetID& subnet_id);
+
+ /// @brief Deletes all subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted subnets.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteAllSubnets4(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes all subnets belonging to a specified shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network for which the
+ /// subnets should be deleted.
+ /// @return Number of deleted subnets.
+ virtual uint64_t
+ deleteSharedNetworkSubnets4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name);
+
+ /// @brief Deletes shared network by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the shared network to be deleted.
+ /// @return Number of deleted shared networks.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteSharedNetwork4(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted shared networks.
+ virtual uint64_t
+ deleteAllSharedNetworks4(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the option to be deleted.
+ /// @param space Option space of the option to be deleted.
+ /// @return Number of deleted option definitions.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOptionDef4(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes all option definitions.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted option definitions.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteAllOptionDefs4(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes global option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the option to be deleted.
+ /// @param space Option space of the option to be deleted.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption4(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network which deleted
+ /// option belongs to
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes subnet level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to which deleted option
+ /// belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption4(const db::ServerSelector& server_selector, const SubnetID& subnet_id,
+ const uint16_t code, const std::string& space);
+
+ /// @brief Deletes pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the pool to which
+ /// deleted option belongs.
+ /// @param pool_end_address Upper bound address of the pool to which the
+ /// deleted option belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption4(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the global parameter to be deleted.
+ /// @return Number of deleted global parameters.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteGlobalParameter4(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all global parameters.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted global parameters.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteAllGlobalParameters4(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes DHCPv4 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be deleted.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteClientClass4(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteAllClientClasses4(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes a server from the backend.
+ ///
+ /// @param server_tag Tag of the server to be deleted.
+ /// @return Number of deleted servers.
+ /// @throw isc::InvalidOperation when trying to delete the logical
+ /// server 'all'.
+ virtual uint64_t
+ deleteServer4(const data::ServerTag& server_tag);
+
+ /// @brief Deletes all servers from the backend except the logical
+ /// server 'all'.
+ ///
+ /// @return Number of deleted servers.
+ virtual uint64_t
+ deleteAllServers4();
+
+ /// @brief Returns backend type in the textual format.
+ ///
+ /// @return "postgresql".
+ virtual std::string getType() const;
+
+ /// @brief Returns backend host.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return host on which the database is located.
+ virtual std::string getHost() const;
+
+ /// @brief Returns backend port number.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return Port number on which database service is available.
+ virtual uint16_t getPort() const;
+
+ /// @brief Registers the PgSQL backend factory with backend config manager
+ ///
+ /// This should be called by the hook lib load() function.
+ /// @return True if the factory was registered successfully, false otherwise.
+ static bool registerBackendType();
+
+ /// @brief Unregisters the PgSQL backend factory and discards PgSQL backends
+ ///
+ /// This should be called by the hook lib unload() function.
+ static void unregisterBackendType();
+
+ /// @brief Flag which indicates if the config backend has an unusable
+ /// connection.
+ ///
+ /// @return true if there is at least one unusable connection, false
+ /// otherwise
+ virtual bool isUnusable();
+
+ /// @brief Return backend parameters
+ ///
+ /// Returns the backend parameters
+ ///
+ /// @return Parameters of the backend.
+ isc::db::DatabaseConnection::ParameterMap getParameters() const;
+
+protected:
+
+ /// @brief Pointer to the implementation of the @c PgSqlConfigBackendDHCPv4
+ /// class.
+ boost::shared_ptr<PgSqlConfigBackendDHCPv4Impl> impl_;
+
+ /// @brief Pointer to the base implementation of the backend shared by
+ /// DHCPv4 and DHCPv6 servers.
+ boost::shared_ptr<PgSqlConfigBackendImpl> base_impl_;
+};
+
+/// @brief Pointer to the @c PgSqlConfigBackendDHCPv4 class.
+typedef boost::shared_ptr<PgSqlConfigBackendDHCPv4> PgSqlConfigBackendDHCPv4Ptr;
+
+} // end of namespace isc::cb
+} // end of namespace isc
+
+#endif // PGSQL_CONFIG_BACKEND_DHCP4_H
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc
new file mode 100644
index 0000000..20d5617
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.cc
@@ -0,0 +1,5725 @@
+// Copyright (C) 2022-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/addr_utilities.h>
+#include <pgsql_cb_dhcp6.h>
+#include <pgsql_cb_impl.h>
+#include <pgsql_query_macros_dhcp.h>
+#include <cc/data.h>
+#include <config_backend/constants.h>
+#include <database/database_connection.h>
+#include <database/db_exceptions.h>
+#include <dhcp/classify.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option_data_types.h>
+#include <dhcp/option_space.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/config_backend_dhcp6_mgr.h>
+#include <dhcpsrv/network.h>
+#include <dhcpsrv/pool.h>
+#include <dhcpsrv/lease.h>
+#include <dhcpsrv/timer_mgr.h>
+#include <dhcpsrv/parsers/client_class_def_parser.h>
+#include <util/buffer.h>
+#include <util/boost_time_utils.h>
+#include <util/multi_threading_mgr.h>
+#include <util/triplet.h>
+#include <pgsql/pgsql_connection.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/pointer_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+
+using namespace isc::cb;
+using namespace isc::db;
+using namespace isc::data;
+using namespace isc::asiolink;
+using namespace isc::log;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Implementation of the PostgreSQL Configuration Backend.
+class PgSqlConfigBackendDHCPv6Impl : public PgSqlConfigBackendImpl {
+public:
+
+ /// @brief Statement tags.
+ ///
+ /// The contents of the enum are indexes into the list of SQL statements.
+ /// It is assumed that the order is such that the indices of statements
+ /// reading the database are less than those of statements modifying the
+ /// database.
+ enum StatementIndex {
+ CREATE_AUDIT_REVISION,
+ CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ GET_GLOBAL_PARAMETER6,
+ GET_ALL_GLOBAL_PARAMETERS6,
+ GET_MODIFIED_GLOBAL_PARAMETERS6,
+ GET_SUBNET6_ID_NO_TAG,
+ GET_SUBNET6_ID_ANY,
+ GET_SUBNET6_ID_UNASSIGNED,
+ GET_SUBNET6_PREFIX_NO_TAG,
+ GET_SUBNET6_PREFIX_ANY,
+ GET_SUBNET6_PREFIX_UNASSIGNED,
+ GET_ALL_SUBNETS6,
+ GET_ALL_SUBNETS6_UNASSIGNED,
+ GET_MODIFIED_SUBNETS6,
+ GET_MODIFIED_SUBNETS6_UNASSIGNED,
+ GET_SHARED_NETWORK_SUBNETS6,
+ GET_POOL6_RANGE,
+ GET_POOL6_RANGE_ANY,
+ GET_PD_POOL,
+ GET_PD_POOL_ANY,
+ GET_SHARED_NETWORK6_NAME_NO_TAG,
+ GET_SHARED_NETWORK6_NAME_ANY,
+ GET_SHARED_NETWORK6_NAME_UNASSIGNED,
+ GET_ALL_SHARED_NETWORKS6,
+ GET_ALL_SHARED_NETWORKS6_UNASSIGNED,
+ GET_MODIFIED_SHARED_NETWORKS6,
+ GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED,
+ GET_OPTION_DEF6_CODE_SPACE,
+ GET_ALL_OPTION_DEFS6,
+ GET_MODIFIED_OPTION_DEFS6,
+ GET_OPTION6_CODE_SPACE,
+ GET_ALL_OPTIONS6,
+ GET_MODIFIED_OPTIONS6,
+ GET_OPTION6_SUBNET_ID_CODE_SPACE,
+ GET_OPTION6_POOL_ID_CODE_SPACE,
+ GET_OPTION6_PD_POOL_ID_CODE_SPACE,
+ GET_OPTION6_SHARED_NETWORK_CODE_SPACE,
+ GET_CLIENT_CLASS6_NAME,
+ GET_ALL_CLIENT_CLASSES6,
+ GET_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ GET_MODIFIED_CLIENT_CLASSES6,
+ GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED,
+ GET_AUDIT_ENTRIES6_TIME,
+ GET_SERVER6,
+ GET_ALL_SERVERS6,
+ INSERT_GLOBAL_PARAMETER6,
+ INSERT_GLOBAL_PARAMETER6_SERVER,
+ INSERT_SUBNET6,
+ INSERT_SUBNET6_SERVER,
+ INSERT_POOL6,
+ INSERT_PD_POOL,
+ INSERT_SHARED_NETWORK6,
+ INSERT_SHARED_NETWORK6_SERVER,
+ INSERT_OPTION_DEF6,
+ INSERT_OPTION_DEF6_CLIENT_CLASS,
+ INSERT_OPTION_DEF6_SERVER,
+ INSERT_OPTION6,
+ INSERT_OPTION6_SERVER,
+ INSERT_CLIENT_CLASS6,
+ INSERT_CLIENT_CLASS6_SERVER,
+ INSERT_CLIENT_CLASS6_DEPENDENCY,
+ INSERT_SERVER6,
+ UPDATE_GLOBAL_PARAMETER6,
+ UPDATE_SUBNET6,
+ UPDATE_SHARED_NETWORK6,
+ UPDATE_OPTION_DEF6,
+ UPDATE_OPTION_DEF6_CLIENT_CLASS,
+ UPDATE_OPTION6,
+ UPDATE_OPTION6_SUBNET_ID,
+ UPDATE_OPTION6_POOL_ID,
+ UPDATE_OPTION6_PD_POOL_ID,
+ UPDATE_OPTION6_SHARED_NETWORK,
+ UPDATE_OPTION6_CLIENT_CLASS,
+ UPDATE_CLIENT_CLASS6,
+ UPDATE_CLIENT_CLASS6_SAME_POSITION,
+ UPDATE_SERVER6,
+ DELETE_GLOBAL_PARAMETER6,
+ DELETE_ALL_GLOBAL_PARAMETERS6,
+ DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
+ DELETE_SUBNET6_ID_WITH_TAG,
+ DELETE_SUBNET6_ID_ANY,
+ DELETE_SUBNET6_PREFIX_WITH_TAG,
+ DELETE_SUBNET6_PREFIX_ANY,
+ DELETE_ALL_SUBNETS6,
+ DELETE_ALL_SUBNETS6_UNASSIGNED,
+ DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME,
+ DELETE_SUBNET6_SERVER,
+ DELETE_POOLS6,
+ DELETE_PD_POOLS,
+ DELETE_SHARED_NETWORK6_NAME_WITH_TAG,
+ DELETE_SHARED_NETWORK6_NAME_ANY,
+ DELETE_ALL_SHARED_NETWORKS6,
+ DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED,
+ DELETE_SHARED_NETWORK6_SERVER,
+ DELETE_OPTION_DEF6_CODE_NAME,
+ DELETE_ALL_OPTION_DEFS6,
+ DELETE_ALL_OPTION_DEFS6_UNASSIGNED,
+ DELETE_OPTION_DEFS6_CLIENT_CLASS,
+ DELETE_OPTION6,
+ DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
+ DELETE_OPTION6_SUBNET_ID,
+ DELETE_OPTION6_POOL_RANGE,
+ DELETE_OPTION6_PD_POOL,
+ DELETE_OPTION6_SHARED_NETWORK,
+ DELETE_OPTIONS6_SUBNET_ID_PREFIX,
+ DELETE_OPTIONS6_SHARED_NETWORK,
+ DELETE_OPTIONS6_CLIENT_CLASS,
+ DELETE_CLIENT_CLASS6_DEPENDENCY,
+ DELETE_CLIENT_CLASS6_SERVER,
+ DELETE_ALL_CLIENT_CLASSES6,
+ DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ DELETE_CLIENT_CLASS6,
+ DELETE_CLIENT_CLASS6_ANY,
+ DELETE_SERVER6,
+ DELETE_ALL_SERVERS6,
+ GET_LAST_INSERT_ID6,
+ NUM_STATEMENTS
+ };
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ explicit PgSqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap&
+ parameters);
+
+ /// @brief Destructor.
+ ~PgSqlConfigBackendDHCPv6Impl();
+
+ /// @brief Fetches the SQL statement for a given statement index.
+ ///
+ /// @param index index of the desired statement.
+ /// @throw BadValue if there is no statement corresponding to
+ /// the index.
+ virtual PgSqlTaggedStatement& getStatement(size_t index) const;
+
+ /// @brief Sends query to retrieve global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the parameter to be retrieved.
+ ///
+ /// @return Pointer to the retrieved value or null if such parameter
+ /// doesn't exist.
+ StampedValuePtr getGlobalParameter6(const ServerSelector& server_selector,
+ const std::string& name) {
+ StampedValueCollection parameters;
+
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.add(name);
+
+ getGlobalParameters(GET_GLOBAL_PARAMETER6, in_bindings, parameters);
+ }
+
+ return (parameters.empty() ? StampedValuePtr() : *parameters.begin());
+ }
+
+ /// @brief Sends query to insert or update global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param value StampedValue describing the parameter to create/update.
+ void createUpdateGlobalParameter6(const db::ServerSelector& server_selector,
+ const StampedValuePtr& value) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "creating or updating global parameter");
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(value->getName());
+ in_bindings.addTempString(value->getValue());
+ in_bindings.add(value->getType()),
+ in_bindings.addTimestamp(value->getModificationTime()),
+ in_bindings.addTempString(tag);
+ in_bindings.addTempString(value->getName());
+
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "global parameter set",
+ false);
+
+ // Try to update the existing row.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6,
+ in_bindings) == 0) {
+ // No such parameter found, so let's insert it. We have to adjust the
+ // bindings collection to match the prepared statement for insert.
+ in_bindings.popBack();
+ in_bindings.popBack();
+
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6,
+ in_bindings);
+
+ // Successfully inserted global parameter. Now, we have to associate it
+ // with the server tag.
+ PsqlBindArray attach_bindings;
+ uint64_t pid = getLastInsertId("dhcp6_global_parameter", "id");
+ attach_bindings.add(pid); // id of newly inserted global.
+ attach_bindings.addTimestamp(value->getModificationTime());
+ attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER,
+ server_selector, attach_bindings);
+ }
+
+ transaction.commit();
+ }
+
+ /// @brief Sends query to the database to retrieve multiple subnets.
+ ///
+ /// Query should order subnets by subnet_id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] subnets Reference to the container where fetched subnets
+ /// will be inserted.
+ void getSubnets6(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ Subnet6Collection& subnets) {
+ uint64_t last_pool_id = 0;
+ uint64_t last_pd_pool_id = 0;
+ uint64_t last_pool_option_id = 0;
+ uint64_t last_pd_pool_option_id = 0;
+ uint64_t last_option_id = 0;
+ Pool6Ptr last_pool;
+ Pool6Ptr last_pd_pool;
+ std::string last_tag;
+
+ // Execute actual query.
+ selectQuery(index, in_bindings,
+ [this, &subnets, &last_pool, &last_pd_pool,
+ &last_pool_id, &last_pd_pool_id,
+ &last_pool_option_id, &last_pd_pool_option_id,
+ &last_option_id, &last_tag](PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get pointer to the last subnet in the collection.
+ Subnet6Ptr last_subnet;
+ if (!subnets.empty()) {
+ last_subnet = *subnets.rbegin();
+ }
+ // Subnet_id is column 0.
+ SubnetID subnet_id = worker.getInt(0) ;
+
+ // Subnet has been returned. Assuming that subnets are ordered by
+ // subnet identifier, if the subnet identifier of the current row
+ // is different than the subnet identifier of the previously returned
+ // row, it means that we have to construct new subnet object.
+ if (!last_subnet || (last_subnet->getID() != subnet_id)) {
+ // Reset per subnet component tracking and server tag because
+ // we're now starting to process a new subnet.
+ last_pool_id = 0;
+ last_pd_pool_id = 0;
+ last_pool_option_id = 0;
+ last_pd_pool_option_id = 0;
+ last_option_id = 0;
+ last_pool.reset();
+ last_pd_pool.reset();
+ last_tag.clear();
+
+ // Get subnet parameters required by the constructor first.
+
+ // subnet_prefix at 1.
+ std::string subnet_prefix = worker.getString(1);
+ auto prefix_pair = Subnet6::parsePrefix(subnet_prefix);
+
+ // preferred_lifetime (5)
+ // min_preferred_lifetime (72)
+ // max_preferred_lifetime (73)
+ auto preferred_lifetime = worker.getTriplet(5, 72, 73);
+
+ // renew_timer at 9.
+ auto renew_timer = worker.getTriplet(9);
+
+ // rebind_timer at 7.
+ auto rebind_timer = worker.getTriplet(7);
+
+ // valid_lifetime at 14.
+ // min_valid_lifetime at 74.
+ // max_valid_lifetime at 75.
+ auto valid_lifetime = worker.getTriplet(14, 74, 75);
+
+ // Create subnet with basic settings.
+ last_subnet = Subnet6::create(prefix_pair.first, prefix_pair.second,
+ renew_timer, rebind_timer,
+ preferred_lifetime,
+ valid_lifetime, subnet_id);
+
+ // 0 and 1 are subnet_id and subnet_prefix
+
+ // client_class at 2.
+ if (!worker.isColumnNull(2)) {
+ last_subnet->allowClientClass(worker.getString(2));
+ }
+
+ // interface at 3.
+ if (!worker.isColumnNull(3)) {
+ last_subnet->setIface(worker.getString(3));
+ }
+
+ // modification_ts at 4.
+ last_subnet->setModificationTime(worker.getTimestamp(4));
+
+ // preferred_lifetime is 5.
+
+ if (!worker.isColumnNull(6)) {
+ last_subnet->setRapidCommit(worker.getBool(6));
+ }
+
+ // rebind_timer is 7.
+
+ // Relay addresses at 8.
+ setRelays(worker, 8, *last_subnet);
+
+ // renew_timer is 9.
+
+ // require_client_classes at 10.
+ setRequiredClasses(worker, 10, [&last_subnet](const std::string& class_name) {
+ last_subnet->requireClientClass(class_name);
+ });
+
+ // reservations_global at 11.
+ if (!worker.isColumnNull(11)) {
+ last_subnet->setReservationsGlobal(worker.getBool(11));
+ }
+
+ // shared_network_name at 12.
+ if (!worker.isColumnNull(12)) {
+ last_subnet->setSharedNetworkName(worker.getString(12));
+ }
+
+ // user_context at 13.
+ if (!worker.isColumnNull(13)) {
+ ElementPtr user_context = worker.getJSON(13);
+ if (user_context) {
+ last_subnet->setContext(user_context);
+ }
+ }
+
+ // valid_lifetime at 14.
+
+ // 15 to 19 are pool
+ // 20 to 25 are pd pool
+ // 26 to 39 are pool option
+ // 40 to 53 are pd pool option
+ // 54 to 67 are option
+
+ // calculate_tee_times at 68.
+ if (!worker.isColumnNull(68)) {
+ last_subnet->setCalculateTeeTimes(worker.getBool(68));
+ }
+
+ // t1_percent at 69.
+ if (!worker.isColumnNull(69)) {
+ last_subnet->setT1Percent(worker.getDouble(69));
+ }
+
+ // t2_percent at 70.
+ if (!worker.isColumnNull(70)) {
+ last_subnet->setT2Percent(worker.getDouble(70));
+ }
+
+ // interface_id at 71.
+ setInterfaceId(*last_subnet, worker, 71);
+
+ // 72 and 73 are {min,max}_preferred_lifetime
+
+ // 74 and 75 are {min,max}_valid_lifetime
+
+ // 76 is pool client_class
+ // 77 is pool require_client_classes
+ // 78 is pool user_context
+ // 79 is pd pool excluded_prefix
+ // 80 is pd pool excluded_prefix_length
+ // 81 is pd pool client_class
+ // 82 is pd pool require_client_classes
+ // 83 is pd pool user_context
+
+ // ddns_send_updates at 84.
+ if (!worker.isColumnNull(84)) {
+ last_subnet->setDdnsSendUpdates(worker.getBool(84));
+ }
+
+ // ddns_override_no_update at 85.
+ if (!worker.isColumnNull(85)) {
+ last_subnet->setDdnsOverrideNoUpdate(worker.getBool(85));
+ }
+
+ // ddns_override_client_update at 86.
+ if (!worker.isColumnNull(86)) {
+ last_subnet->setDdnsOverrideClientUpdate(worker.getBool(86));
+ }
+
+ // ddns_replace_client_name at 87.
+ if (!worker.isColumnNull(87)) {
+ last_subnet->setDdnsReplaceClientNameMode(
+ static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(87)));
+ }
+
+ // ddns_generated_prefix at 88.
+ if (!worker.isColumnNull(88)) {
+ last_subnet->setDdnsGeneratedPrefix(worker.getString(88));
+ }
+
+ // ddns_qualifying_suffix at 89.
+ if (!worker.isColumnNull(89)) {
+ last_subnet->setDdnsQualifyingSuffix(worker.getString(89));
+ }
+
+ // reservations_in_subnet at 90.
+ if (!worker.isColumnNull(90)) {
+ last_subnet->setReservationsInSubnet(worker.getBool(90));
+ }
+
+ // reservations_out_of_pool at 91.
+ if (!worker.isColumnNull(91)) {
+ last_subnet->setReservationsOutOfPool(worker.getBool(91));
+ }
+
+ // cache_threshold at 92.
+ if (!worker.isColumnNull(92)) {
+ last_subnet->setCacheThreshold(worker.getDouble(92));
+ }
+
+ // cache_max_age at 93.
+ if (!worker.isColumnNull(93)) {
+ last_subnet->setCacheMaxAge(worker.getInt(93));
+ }
+
+ // allocator at 94.
+ if (!worker.isColumnNull(94)) {
+ last_subnet->setAllocatorType(worker.getString(94));
+ }
+
+ // pd_allocator at 95.
+ if (!worker.isColumnNull(95)) {
+ last_subnet->setPdAllocatorType(worker.getString(95));
+ }
+
+ // server_tag at 96.
+
+ // Subnet ready. Add it to the list.
+ auto ret = subnets.insert(last_subnet);
+
+ // subnets is a multi index container with unique indexes
+ // but these indexes are unique too in the database,
+ // so this is for sanity only.
+ if (!ret.second) {
+ isc_throw(Unexpected, "add subnet failed");
+ }
+ }
+
+ // Check for new server tags at 96.
+ if (!worker.isColumnNull(96)) {
+ std::string new_tag = worker.getString(96);
+ if (last_tag != new_tag) {
+ if (!new_tag.empty() && !last_subnet->hasServerTag(ServerTag(new_tag))) {
+ last_subnet->setServerTag(new_tag);
+ }
+
+ last_tag = new_tag;
+ }
+ }
+
+ // Pool is between 15 and 19 with extra between 76 and 78
+
+ // If the row contains information about the pool and it
+ // appears to be new pool entry (checked by comparing pool
+ // id), let's create the new pool and add it to the
+ // subnet.
+ // pool id (15)
+ // pool start_address (16)
+ // pool end_address (17)
+ if (!worker.isColumnNull(15) &&
+ (worker.getInet6(16) != 0) &&
+ (worker.getInet6(17) != 0) &&
+ (worker.getBigInt(15) > last_pool_id)) {
+ last_pool_id = worker.getBigInt(15);
+ last_pool = Pool6::create(Lease::TYPE_NA,
+ IOAddress(worker.getInet6(16)),
+ IOAddress(worker.getInet6(17)));
+
+ // pool subnet_id at 18 (ignored)
+ // pool modification_ts at 19 (ignored)
+
+ // pool client_class at 76.
+ if (!worker.isColumnNull(76)) {
+ last_pool->allowClientClass(worker.getString(76));
+ }
+
+ // pool require_client_classes at 77.
+ setRequiredClasses(worker, 77, [&last_pool](const std::string& class_name) {
+ last_pool->requireClientClass(class_name);
+ });
+
+ // pool user_context at 78.
+ if (!worker.isColumnNull(78)) {
+ ElementPtr user_context = worker.getJSON(78);
+ if (user_context) {
+ last_pool->setContext(user_context);
+ }
+ }
+
+ last_subnet->addPool(last_pool);
+ }
+
+ // Pd Pool is between 20 and 25 with extra between 79 and 83
+
+ // If the row contains information about the pd pool and
+ // it appears to be new pd pool entry (checked by
+ // comparing pd pool id), let's create the new pd pool and
+ // add it to the subnet.
+ // pd pool id (20)
+ // pd pool prefix (21)
+ // pd pool prefix_length (22)
+ // pd pool delegated_prefix_length (23)
+ if (!worker.isColumnNull(20) &&
+ (!worker.getString(21).empty()) &&
+ (worker.getSmallInt(22) != 0) &&
+ (worker.getSmallInt(23) != 0) &&
+ (worker.getBigInt(20) > last_pd_pool_id)) {
+
+ // 24 is pd pool subnet_id (ignored)
+ // 25 is pd pool modification_ts (ignored)
+
+ // excluded_prefix (79) and excluded_prefix_length (80)
+ IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
+ if (!worker.isColumnNull(79)) {
+ excluded_prefix = worker.getInet6(79);
+ }
+
+ last_pd_pool_id = worker.getBigInt(20);
+ last_pd_pool = Pool6::create(worker.getInet6(21),
+ static_cast<uint8_t>(worker.getSmallInt(22)),
+ static_cast<uint8_t>(worker.getSmallInt(23)),
+ excluded_prefix,
+ static_cast<uint8_t>(worker.getSmallInt(80)));
+
+ // pd pool client_class (81)
+ if (!worker.isColumnNull(81)) {
+ last_pd_pool->allowClientClass(worker.getString(81));
+ }
+
+ // pd pool require_client_classes at 82.
+ setRequiredClasses(worker, 82, [&last_pd_pool](const std::string& class_name) {
+ last_pd_pool->requireClientClass(class_name);
+ });
+
+ // pd pool user_context at 83.
+ if (!worker.isColumnNull(83)) {
+ ElementPtr user_context = worker.getJSON(83);
+ if (user_context) {
+ last_pd_pool->setContext(user_context);
+ }
+ }
+
+ last_subnet->addPool(last_pd_pool);
+ }
+
+ // Parse pool-specific option from 26 to 39.
+ if (last_pool && !worker.isColumnNull(26) &&
+ (last_pool_option_id < worker.getBigInt(26))) {
+ last_pool_option_id = worker.getBigInt(26);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 26);
+ if (desc) {
+ last_pool->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+
+ // Parse pd pool-specific option from 40 to 53.
+ if (last_pd_pool && !worker.isColumnNull(40) &&
+ (last_pd_pool_option_id < worker.getBigInt(40))) {
+ last_pd_pool_option_id = worker.getBigInt(40);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 40);
+ if (desc) {
+ last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+
+ // Parse subnet-specific option from 54 to 67.
+ if (!worker.isColumnNull(54) &&
+ (last_option_id < worker.getBigInt(54))) {
+ last_option_id = worker.getBigInt(54);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 54);
+ if (desc) {
+ last_subnet->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ // Now that we're done fetching the whole subnet, we have to
+ // check if it has matching server tags and toss it if it
+ // doesn't. We skip matching the server tags if we're asking
+ // for ANY subnet.
+ auto& subnet_index = subnets.get<SubnetSubnetIdIndexTag>();
+ tossNonMatchingElements(server_selector, subnet_index);
+ }
+
+ /// @brief Sends query to retrieve single subnet by id.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Subnet identifier.
+ ///
+ /// @return Pointer to the returned subnet or NULL if such subnet
+ /// doesn't exist.
+ Subnet6Ptr getSubnet6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) {
+ if (server_selector.hasMultipleTags()) {
+ isc_throw(InvalidOperation, "expected one server tag to be specified"
+ " while fetching a subnet. Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet_id);
+
+ auto index = GET_SUBNET6_ID_NO_TAG;
+ if (server_selector.amUnassigned()) {
+ index = GET_SUBNET6_ID_UNASSIGNED;
+ } else if (server_selector.amAny()) {
+ index = GET_SUBNET6_ID_ANY;
+ }
+
+ Subnet6Collection subnets;
+ getSubnets6(index, server_selector, in_bindings, subnets);
+
+ return (subnets.empty() ? Subnet6Ptr() : *subnets.begin());
+ }
+
+ /// @brief Sends query to retrieve single subnet by prefix.
+ ///
+ /// The prefix should be in the following format: "2001:db8:1::/64".
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Subnet identifier.
+ ///
+ /// @return Pointer to the returned subnet or NULL if such subnet
+ /// doesn't exist.
+ Subnet6Ptr getSubnet6(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) {
+ if (server_selector.hasMultipleTags()) {
+ isc_throw(InvalidOperation, "expected one server tag to be specified"
+ " while fetching a subnet. Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet_prefix);
+
+ auto index = GET_SUBNET6_PREFIX_NO_TAG;
+ if (server_selector.amUnassigned()) {
+ index = GET_SUBNET6_PREFIX_UNASSIGNED;
+ } else if (server_selector.amAny()) {
+ index = GET_SUBNET6_PREFIX_ANY;
+ }
+
+ Subnet6Collection subnets;
+ getSubnets6(index, server_selector, in_bindings, subnets);
+
+ return (subnets.empty() ? Subnet6Ptr() : *subnets.begin());
+ }
+
+ /// @brief Sends query to retrieve all subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] subnets Reference to the subnet collection structure where
+ /// subnets should be inserted.
+ void getAllSubnets6(const ServerSelector& server_selector,
+ Subnet6Collection& subnets) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching all subnets for ANY "
+ "server is not supported");
+ }
+
+ auto index = (server_selector.amUnassigned() ? GET_ALL_SUBNETS6_UNASSIGNED :
+ GET_ALL_SUBNETS6);
+ PsqlBindArray in_bindings;
+ getSubnets6(index, server_selector, in_bindings, subnets);
+ }
+
+ /// @brief Sends query to retrieve modified subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] subnets Reference to the subnet collection structure where
+ /// subnets should be inserted.
+ void getModifiedSubnets6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ Subnet6Collection& subnets) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified subnets for ANY "
+ "server is not supported");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(modification_ts);
+
+ auto index = (server_selector.amUnassigned() ? GET_MODIFIED_SUBNETS6_UNASSIGNED :
+ GET_MODIFIED_SUBNETS6);
+ getSubnets6(index, server_selector, in_bindings, subnets);
+ }
+
+ /// @brief Sends query to retrieve all subnets belonging to a shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network for which the
+ /// subnets should be retrieved.
+ /// @param [out] subnets Reference to the subnet collection structure where
+ /// subnets should be inserted.
+ void getSharedNetworkSubnets6(const ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ Subnet6Collection& subnets) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(shared_network_name);
+ getSubnets6(GET_SHARED_NETWORK_SUBNETS6, server_selector, in_bindings, subnets);
+ }
+
+ /// @brief Sends query to retrieve multiple pools.
+ ///
+ /// Query should order pools by id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] pools Reference to the container where fetched pools
+ /// will be inserted.
+ /// @param [out] pool_ids Identifiers of the pools returned in @c pools
+ /// argument.
+ void getPools(const StatementIndex& index,
+ const PsqlBindArray& in_bindings,
+ PoolCollection& pools,
+ std::vector<uint64_t>& pool_ids) {
+ uint64_t last_pool_id = 0;
+ uint64_t last_pool_option_id = 0;
+ Pool6Ptr last_pool;
+
+ selectQuery(index, in_bindings,
+ [this, &last_pool_id, &last_pool_option_id, &last_pool, &pools, &pool_ids]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Pool id is column 0.
+ auto id = worker.getBigInt(0) ;
+ if (id > last_pool_id) {
+ // pool start_address (1)
+ // pool end_address (2)
+ last_pool_id = id;
+
+ last_pool = Pool6::create(Lease::TYPE_NA, worker.getInet6(1), worker.getInet6(2));
+
+ // pool subnet_id (3) (ignored)
+
+ // pool client_class (4)
+ if (!worker.isColumnNull(4)) {
+ last_pool->allowClientClass(worker.getString(4));
+ }
+
+ // pool require_client_classes (5)
+ setRequiredClasses(worker, 5, [&last_pool](const std::string& class_name) {
+ last_pool->requireClientClass(class_name);
+ });
+
+ // pool user_context (6)
+ if (!worker.isColumnNull(6)) {
+ ElementPtr user_context = worker.getJSON(6);
+ if (user_context) {
+ last_pool->setContext(user_context);
+ }
+ }
+
+ // pool: modification_ts (7) (ignored)
+
+ pools.push_back(last_pool);
+ pool_ids.push_back(last_pool_id);
+ }
+
+ // Parse pool specific option (8).
+ if (last_pool && !worker.isColumnNull(8) &&
+ (last_pool_option_id < worker.getBigInt(8))) {
+ last_pool_option_id = worker.getBigInt(8);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 8);
+ if (desc) {
+ last_pool->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+ }
+
+ /// @brief Sends query to retrieve multiple pd pools.
+ ///
+ /// Query should order pd pools by id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] pd_pools Reference to the container where fetched pools
+ /// will be inserted.
+ /// @param [out] pd_pool_ids Identifiers of the pd pools returned in
+ /// @c pd_pools argument.
+ void getPdPools(const StatementIndex& index,
+ const PsqlBindArray& in_bindings,
+ PoolCollection& pd_pools,
+ std::vector<uint64_t>& pd_pool_ids) {
+ uint64_t last_pd_pool_id = 0;
+ uint64_t last_pd_pool_option_id = 0;
+ Pool6Ptr last_pd_pool;
+
+ selectQuery(index, in_bindings,
+ [this, &last_pd_pool_id, &last_pd_pool_option_id,
+ &last_pd_pool, &pd_pools, &pd_pool_ids]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Pool id is column 0.
+ auto id = worker.getBigInt(0) ;
+ if (id > last_pd_pool_id) {
+ last_pd_pool_id = id;
+
+ // pd pool prefix (1)
+ // pd pool prefix_length (2)
+ // pd pool delegated_prefix_length (3)
+
+ // excluded_prefix (5) and excluded_prefix_length (6)
+ IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
+ if (!worker.isColumnNull(5)) {
+ excluded_prefix = worker.getInet6(5);
+ }
+
+ last_pd_pool = Pool6::create(worker.getInet6(1),
+ static_cast<uint8_t>(worker.getSmallInt(2)),
+ static_cast<uint8_t>(worker.getSmallInt(3)),
+ excluded_prefix,
+ static_cast<uint8_t>(worker.getSmallInt(6)));
+
+ // pd pool subnet_id (4) (ignored)
+
+ // pool client_class (7)
+ if (!worker.isColumnNull(7)) {
+ last_pd_pool->allowClientClass(worker.getString(7));
+ }
+
+ // pool require_client_classes (8)
+ setRequiredClasses(worker, 8, [&last_pd_pool](const std::string& class_name) {
+ last_pd_pool->requireClientClass(class_name);
+ });
+
+ // pd pool user_context (9)
+ if (!worker.isColumnNull(9)) {
+ ElementPtr user_context = worker.getJSON(9);
+ if (user_context) {
+ last_pd_pool->setContext(user_context);
+ }
+ }
+
+ // pd pool modification_ts (10) (ignored)
+
+ pd_pools.push_back(last_pd_pool);
+ pd_pool_ids.push_back(last_pd_pool_id);
+ }
+
+ // Parse pd pool specific option between 11 and 25.
+ if (last_pd_pool && !worker.isColumnNull(11) &&
+ (last_pd_pool_option_id < worker.getBigInt(11))) {
+ last_pd_pool_option_id = worker.getBigInt(11);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 11);
+ if (desc) {
+ last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+ }
+
+ /// @brief Sends query to retrieve single pool by address range.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound pool address.
+ /// @param pool_end_address Upper bound pool address.
+ /// @param pool_id Pool identifier for the returned pool.
+ /// @return Pointer to the pool or null if no such pool found.
+ Pool6Ptr getPool6(const ServerSelector& server_selector,
+ const IOAddress& pool_start_address,
+ const IOAddress& pool_end_address,
+ uint64_t& pool_id) {
+ PoolCollection pools;
+ std::vector<uint64_t> pool_ids;
+
+ if (server_selector.amAny()) {
+ PsqlBindArray in_bindings;
+ in_bindings.addInet6(pool_start_address);
+ in_bindings.addInet6(pool_end_address);
+ getPools(GET_POOL6_RANGE_ANY, in_bindings, pools, pool_ids);
+ } else {
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addInet6(pool_start_address);
+ in_bindings.addInet6(pool_end_address);
+
+ getPools(GET_POOL6_RANGE, in_bindings, pools, pool_ids);
+ // Break if something is found?
+ }
+ }
+
+ // Return upon the first pool found.
+ if (!pools.empty()) {
+ pool_id = pool_ids[0];
+ return (boost::dynamic_pointer_cast<Pool6>(*pools.begin()));
+ }
+
+ pool_id = 0;
+
+ return (Pool6Ptr());
+ }
+
+ /// @brief Sends query to retrieve single pd pool.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pd_pool_prefix Address part of the pd pool prefix.
+ /// @param pd_pool_prefix_length Length of the pd pool prefix.
+ /// @param pd_pool_id Pool identifier for the returned pool.
+ /// @return Pointer to the pool or null if no such pool found.
+ Pool6Ptr getPdPool6(const ServerSelector& server_selector,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ uint64_t& pd_pool_id) {
+ PoolCollection pd_pools;
+ std::vector<uint64_t> pd_pool_ids;
+
+ if (server_selector.amAny()) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(pd_pool_prefix.toText());
+ in_bindings.add(pd_pool_prefix_length);
+ getPdPools(GET_PD_POOL_ANY, in_bindings, pd_pools, pd_pool_ids);
+ } else {
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addTempString(pd_pool_prefix.toText());
+ in_bindings.add(pd_pool_prefix_length);
+ getPdPools(GET_PD_POOL, in_bindings, pd_pools, pd_pool_ids);
+ }
+ }
+
+ if (!pd_pools.empty()) {
+ pd_pool_id = pd_pool_ids[0];
+ return (boost::dynamic_pointer_cast<Pool6>(*pd_pools.begin()));
+ }
+
+ pd_pool_id = 0;
+
+ return (Pool6Ptr());
+ }
+
+ /// @brief Sends query to insert or update subnet.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the subnet to be inserted or updated.
+ void createUpdateSubnet6(const ServerSelector& server_selector,
+ const Subnet6Ptr& subnet) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "creating or updating a subnet for ANY"
+ " server is not supported");
+
+ } else if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+ in_bindings.addOptional(subnet->getClientClass(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getIface(Network::Inheritance::NONE));
+ in_bindings.addTimestamp(subnet->getModificationTime());
+ in_bindings.add(subnet->getPreferred(Network::Inheritance::NONE));
+ in_bindings.addMin(subnet->getPreferred(Network::Inheritance::NONE));
+ in_bindings.addMax(subnet->getPreferred(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getRapidCommit(Network::Inheritance::NONE));
+ in_bindings.add(subnet->getT2(Network::Inheritance::NONE));
+ addRelayBinding(in_bindings, subnet);
+ in_bindings.add(subnet->getT1(Network::Inheritance::NONE));
+ addRequiredClassesBinding(in_bindings, subnet);
+ in_bindings.addOptional(subnet->getReservationsGlobal(Network::Inheritance::NONE));
+
+ // Add shared network.
+ SharedNetwork6Ptr shared_network;
+ subnet->getSharedNetwork(shared_network);
+
+ // Check if the subnet is associated with a shared network instance.
+ // If it is, create the binding using the name of the shared network.
+ if (shared_network) {
+ in_bindings.addTempString(shared_network->getName());
+
+ // If the subnet is associated with a shared network by name (no
+ // shared network instance), use this name to create the binding.
+ // This may be the case if the subnet is added as a result of
+ // receiving a control command that merely specifies shared
+ // network name. In that case, it is expected that the shared
+ // network data is already stored in the database.
+ } else if (!subnet->getSharedNetworkName().empty()) {
+ in_bindings.addTempString(subnet->getSharedNetworkName());
+
+ // If the subnet is not associated with a shared network, create
+ // null binding.
+ } else {
+ in_bindings.addNull();
+ }
+
+ in_bindings.add(subnet->getContext());
+ in_bindings.add(subnet->getValid(Network::Inheritance::NONE));
+ in_bindings.addMin(subnet->getValid(Network::Inheritance::NONE));
+ in_bindings.addMax(subnet->getValid(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getCalculateTeeTimes(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getT1Percent(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getT2Percent(Network::Inheritance::NONE));
+ addInterfaceIdBinding(in_bindings, *subnet);
+ in_bindings.addOptional(subnet->getDdnsSendUpdates(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsOverrideNoUpdate(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsOverrideClientUpdate(Network::Inheritance::NONE));
+ addDdnsReplaceClientNameBinding(in_bindings, subnet);
+ in_bindings.addOptional(subnet->getDdnsGeneratedPrefix(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getDdnsQualifyingSuffix(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getReservationsInSubnet(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getReservationsOutOfPool(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getCacheThreshold(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getCacheMaxAge(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getAllocatorType(Network::Inheritance::NONE));
+ in_bindings.addOptional(subnet->getPdAllocatorType(Network::Inheritance::NONE));
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "subnet set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateSubnet6");
+
+ try {
+
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6, in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // It already exists, rollback to the savepoint to preserve
+ // any prior work.
+ conn_.rollbackToSavepoint("createUpdateSubnet6");
+
+ // We're updating, so we need to remove any existing pools and options.
+ deletePools6(subnet);
+ deletePdPools6(subnet);
+ deleteOptions6(ServerSelector::ANY(), subnet);
+
+ // Now we need to add two more bindings for WHERE clause.
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Attempt the update.
+ auto cnt = updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6,
+ in_bindings);
+ if (!cnt) {
+ // Possible only if someone deleted it since we tried to insert it
+ // or the query is broken.
+ isc_throw(Unexpected, "Update subnet failed to find subnet id: "
+ << subnet->getID() << ", prefix: " << subnet->toText());
+ }
+
+ // Remove existing server association.
+ PsqlBindArray server_bindings;
+ server_bindings.add(subnet->getID());
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER,
+ server_bindings);
+ }
+
+ // Subnet was successfully created/updated.
+
+ // Insert associations with the servers.
+ PsqlBindArray attach_bindings;
+ attach_bindings.add(subnet->getID());
+ attach_bindings.addTimestamp(subnet->getModificationTime());
+ attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER,
+ server_selector, attach_bindings);
+
+ // (Re)create pools.
+ for (auto pool : subnet->getPools(Lease::TYPE_NA)) {
+ createPool6(server_selector, boost::dynamic_pointer_cast<Pool6>(pool),
+ subnet);
+ }
+
+ // (Re)create pd pools.
+ for (auto pd_pool : subnet->getPools(Lease::TYPE_PD)) {
+ createPdPool6(server_selector, boost::dynamic_pointer_cast<Pool6>(pd_pool),
+ subnet);
+ }
+
+ // (Re)create options.
+ auto option_spaces = subnet->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = subnet->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption6(server_selector, subnet->getID(), desc_copy,
+ true);
+ }
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Inserts new IPv6 pool to the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool Pointer to the pool to be inserted.
+ /// @param subnet Pointer to the subnet that this pool belongs to.
+ void createPool6(const ServerSelector& server_selector,
+ const Pool6Ptr& pool,
+ const Subnet6Ptr& subnet) {
+ // Create the input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.addInet6(pool->getFirstAddress());
+ in_bindings.addInet6(pool->getLastAddress());
+ in_bindings.add(subnet->getID());
+ in_bindings.addOptional(pool->getClientClass());
+ addRequiredClassesBinding(in_bindings, pool);
+ in_bindings.add(pool->getContext());
+ in_bindings.addTimestamp(subnet->getModificationTime());
+
+ // Attempt to INSERT the pool.
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_POOL6, in_bindings);
+
+ // Get the id of the newly inserted pool.
+ uint64_t pool_id = getLastInsertId("dhcp6_pool", "id");
+
+ // Add the pool's options.
+ auto option_spaces = pool->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = pool->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption6(server_selector, Lease::TYPE_NA,
+ pool_id, desc_copy, true);
+ }
+ }
+ }
+
+ /// @brief Inserts new IPv6 pd pool to the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pd_pool Pointer to the pd pool to be inserted.
+ /// @param subnet Pointer to the subnet that this pd pool belongs to.
+ void createPdPool6(const ServerSelector& server_selector,
+ const Pool6Ptr& pd_pool,
+ const Subnet6Ptr& subnet) {
+ int plen = prefixLengthFromRange(pd_pool->getFirstAddress(),
+ pd_pool->getLastAddress());
+
+ // Extract excluded prefix components.
+ Optional<std::string> xprefix_txt;
+ uint8_t xlen = 0;
+ const Option6PDExcludePtr& xopt = pd_pool->getPrefixExcludeOption();
+ if (xopt) {
+ const IOAddress& prefix = pd_pool->getFirstAddress();
+ const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, pd_pool->getLength());
+ xprefix_txt = xprefix.toText();
+ xlen = xopt->getExcludedPrefixLength();
+ }
+
+ // Create the input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.addInet6(pd_pool->getFirstAddress());
+ in_bindings.add(plen);
+ in_bindings.add(pd_pool->getLength());
+ in_bindings.add(subnet->getID());
+ in_bindings.addOptional(xprefix_txt);
+ in_bindings.add(xlen);
+ in_bindings.addOptional(pd_pool->getClientClass());
+ addRequiredClassesBinding(in_bindings, pd_pool);
+ in_bindings.add(pd_pool->getContext());
+ in_bindings.addTimestamp(subnet->getModificationTime());
+
+ // Attempt to INSERT the pool.
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_PD_POOL, in_bindings);
+
+ // Get the id of the newly inserted pool.
+ uint64_t pd_pool_id = getLastInsertId("dhcp6_pd_pool", "id");
+
+ // Add the pool's options.
+ auto option_spaces = pd_pool->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = pd_pool->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption6(server_selector, Lease::TYPE_PD,
+ pd_pool_id, desc_copy, true);
+ }
+ }
+ }
+
+ /// @brief Sends a query to delete data from a table.
+ ///
+ /// If creates a new audit revision for this change if such audit
+ /// revision doesn't exist yet (using ScopedAuditRevision mechanism).
+ ///
+ /// @tparam Args type of the arguments to be passed to one of the existing
+ /// @c deleteFromTable methods.
+ /// @param server_selector server selector.
+ /// @param operation operation which results in calling this function. This is
+ /// used for logging purposes.
+ /// @param log_message log message to be associated with the audit revision.
+ /// @param cascade_delete boolean flag indicating if we're performing
+ /// cascade delete. If set to true, the audit entries for the child
+ /// objects (e.g. DHCPoptions) won't be created.
+ /// @param keys arguments to be passed to one of the existing
+ /// @c deleteFromTable methods.
+ ///
+ /// @return Number of deleted entries.
+ template<typename... Args>
+ uint64_t deleteTransactional(const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& operation,
+ const std::string& log_message,
+ const bool cascade_delete,
+ Args&&... keys) {
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, log_message, cascade_delete);
+
+ auto count = deleteFromTable(index, server_selector, operation, keys...);
+
+ transaction.commit();
+
+ return (count);
+ }
+
+ /// @brief Sends query to delete subnet by id.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ uint64_t deleteSubnet6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) {
+ int index = (server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG);
+ return (deleteTransactional(index, server_selector,
+ "deleting a subnet", "subnet deleted",
+ true, static_cast<uint32_t>(subnet_id)));
+ }
+
+ /// @brief Sends query to delete subnet by id.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_prefix Prefix of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ uint64_t deleteSubnet6(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) {
+ int index = (server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG);
+ return (deleteTransactional(index, server_selector,
+ "deleting a subnet", "subnet deleted",
+ true, subnet_prefix));
+ }
+
+ /// @brief Deletes pools belonging to a subnet from the database.
+ ///
+ /// The query deletes all pools associated with the subnet's
+ /// identifier or prefix.
+ /// @param subnet Pointer to the subnet for which pools should be
+ /// deleted.
+ uint64_t deletePools6(const Subnet6Ptr& subnet) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Run DELETE.
+ return (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_POOLS6,
+ in_bindings));
+ }
+
+ /// @brief Deletes prefix delegation pools belonging to a subnet from
+ /// the database.
+ ///
+ /// The query deletes all pd pools associated with the subnet's
+ /// identifier or prefix.
+ /// @param subnet Pointer to the subnet for which pd pools should be
+ /// deleted.
+ uint64_t deletePdPools6(const Subnet6Ptr& subnet) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Run DELETE.
+ return (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_PD_POOLS,
+ in_bindings));
+ }
+
+ /// @brief Sends query to the database to retrieve multiple shared
+ /// networks.
+ ///
+ /// Query should order shared networks by id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] shared_networks Reference to the container where fetched
+ /// shared networks will be inserted.
+ void getSharedNetworks6(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ SharedNetwork6Collection& shared_networks) {
+ uint64_t last_network_id = 0;
+ uint64_t last_option_id = 0;
+ std::string last_tag;
+
+ selectQuery(index, in_bindings,
+ [this, &shared_networks, &last_network_id, &last_option_id, &last_tag]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ SharedNetwork6Ptr last_network;
+ if (!shared_networks.empty()) {
+ last_network = *shared_networks.rbegin();
+ }
+
+ // Network id is column 0.
+ auto network_id = worker.getBigInt(0) ;
+
+ // If this is the first shared network or the shared network id in this
+ // row points to the next shared network we use the data in the
+ // row to create the new shared network instance.
+ if (last_network_id != network_id) {
+ last_network_id = network_id;
+
+ // Reset per shared network component tracking and server tag because
+ // we're now starting to process a new shared network.
+ last_option_id = 0;
+ last_tag.clear();
+
+ // name at 1.
+ last_network = SharedNetwork6::create(worker.getString(1));
+ last_network->setId(last_network_id);
+
+ // client_class at 2.
+ if (!worker.isColumnNull(2)) {
+ last_network->allowClientClass(worker.getString(2));
+ }
+
+ // interface at 3.
+ if (!worker.isColumnNull(3)) {
+ last_network->setIface(worker.getString(3));
+ }
+
+ // modification_ts at 4.
+ last_network->setModificationTime(worker.getTimestamp(4));
+
+ // preferred_lifetime (5)
+ // min_preferred_lifetime (32)
+ // max_preferred_lifetime (33)
+ last_network->setPreferred(worker.getTriplet(5, 32, 33));
+
+ // rapid_commit at 6.
+ if (!worker.isColumnNull(6)) {
+ last_network->setRapidCommit(worker.getBool(6));
+ }
+
+ // rebind_timer at 7.
+ if (!worker.isColumnNull(7)) {
+ last_network->setT2(worker.getTriplet(7));
+ }
+
+ // Relay addresses at 8.
+ setRelays(worker, 8, *last_network);
+
+ // renew_timer at 9.
+ if (!worker.isColumnNull(9)) {
+ last_network->setT1(worker.getTriplet(9));
+ }
+
+ // require_client_classes at 10.
+ setRequiredClasses(worker, 10, [&last_network](const std::string& class_name) {
+ last_network->requireClientClass(class_name);
+ });
+
+ // reservations_global at 11.
+ if (!worker.isColumnNull(11)) {
+ last_network->setReservationsGlobal(worker.getBool(11));
+ }
+
+ // user_context at 12.
+ if (!worker.isColumnNull(12)) {
+ ElementPtr user_context = worker.getJSON(12);
+ if (user_context) {
+ last_network->setContext(user_context);
+ }
+ }
+
+ // valid_lifetime at 13.
+ // min_valid_lifetime at 34.
+ // max_valid_lifetime at 35.
+ if (!worker.isColumnNull(13)) {
+ last_network->setValid(worker.getTriplet(13, 34, 35));
+ }
+
+ // option from 14 to 27.
+
+ // calculate_tee_times at 28.
+ if (!worker.isColumnNull(28)) {
+ last_network->setCalculateTeeTimes(worker.getBool(28));
+ }
+
+ // t1_percent at 29.
+ if (!worker.isColumnNull(29)) {
+ last_network->setT1Percent(worker.getDouble(29));
+ }
+
+ // t2_percent at 30.
+ if (!worker.isColumnNull(30)) {
+ last_network->setT2Percent(worker.getDouble(30));
+ }
+
+ // interface_id at 31.
+ setInterfaceId(*last_network, worker, 31);
+
+ // min_preferred_lifetime at 32.
+ // max_preferred_lifetime at 33.
+ // min_valid_lifetime at 34.
+ // max_valid_lifetime at 35.
+
+ // ddns_send_updates at 36.
+ if (!worker.isColumnNull(36)) {
+ last_network->setDdnsSendUpdates(worker.getBool(36));
+ }
+
+ // ddns_override_no_update at 37.
+ if (!worker.isColumnNull(37)) {
+ last_network->setDdnsOverrideNoUpdate(worker.getBool(37));
+ }
+
+ // ddns_override_client_update at 38.
+ if (!worker.isColumnNull(38)) {
+ last_network->setDdnsOverrideClientUpdate(worker.getBool(38));
+ }
+
+ // ddns_replace_client_name at 39.
+ if (!worker.isColumnNull(39)) {
+ last_network->setDdnsReplaceClientNameMode(
+ static_cast<D2ClientConfig::ReplaceClientNameMode>(worker.getSmallInt(39)));
+ }
+
+ // ddns_generated_prefix at 40.
+ if (!worker.isColumnNull(40)) {
+ last_network->setDdnsGeneratedPrefix(worker.getString(40));
+ }
+
+ // ddns_qualifying_suffix at 41.
+ if (!worker.isColumnNull(41)) {
+ last_network->setDdnsQualifyingSuffix(worker.getString(41));
+ }
+
+ // reservations_in_subnet at 42.
+ if (!worker.isColumnNull(42)) {
+ last_network->setReservationsInSubnet(worker.getBool(42));
+ }
+
+ // reservations_in_subnet at 43.
+ if (!worker.isColumnNull(43)) {
+ last_network->setReservationsOutOfPool(worker.getBool(43));
+ }
+
+ // cache_threshold at 44.
+ if (!worker.isColumnNull(44)) {
+ last_network->setCacheThreshold(worker.getDouble(44));
+ }
+
+ // cache_max_age at 45.
+ if (!worker.isColumnNull(45)) {
+ last_network->setCacheMaxAge(worker.getInt(45));
+ }
+
+ // allocator at 46.
+ if (!worker.isColumnNull(46)) {
+ last_network->setAllocatorType(worker.getString(46));
+ }
+
+ // pd_allocator at 47.
+ if (!worker.isColumnNull(47)) {
+ last_network->setPdAllocatorType(worker.getString(47));
+ }
+
+ // server_tag at 48.
+
+ // Add the shared network.
+ auto ret = shared_networks.push_back(last_network);
+
+ // shared_networks is a multi index container with an unique
+ // index but this index is unique too in the database,
+ // so this is for sanity only.
+ if (!ret.second) {
+ isc_throw(Unexpected, "add shared network failed");
+ }
+ }
+
+ // Check for new server tags.
+ if (!worker.isColumnNull(48)) {
+ std::string new_tag = worker.getString(48);
+ if (last_tag != new_tag) {
+ if (!new_tag.empty() && !last_network->hasServerTag(ServerTag(new_tag))) {
+ last_network->setServerTag(new_tag);
+ }
+
+ last_tag = new_tag;
+ }
+ }
+
+ // Parse network-specific option from 14 to 27.
+ if (!worker.isColumnNull(14) &&
+ (last_option_id < worker.getBigInt(14))) {
+ last_option_id = worker.getBigInt(14);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 14);
+ if (desc) {
+ last_network->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ // Now that we're done fetching the whole network, we have to
+ // check if it has matching server tags and toss it if it
+ // doesn't. We skip matching the server tags if we're asking
+ // for ANY shared network.
+ auto& sn_index = shared_networks.get<SharedNetworkRandomAccessIndexTag>();
+ tossNonMatchingElements(server_selector, sn_index);
+ }
+
+ /// @brief Sends query to retrieve single shared network by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Shared network name.
+ ///
+ /// @return Pointer to the returned shared network or NULL if such shared
+ /// network doesn't exist.
+ SharedNetwork6Ptr getSharedNetwork6(const ServerSelector& server_selector,
+ const std::string& name) {
+ if (server_selector.hasMultipleTags()) {
+ isc_throw(InvalidOperation, "expected one server tag to be specified"
+ " while fetching a shared network. Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(name);
+
+ auto index = PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG;
+ if (server_selector.amUnassigned()) {
+ index = PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED;
+ } else if (server_selector.amAny()) {
+ index = PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY;
+ }
+
+ SharedNetwork6Collection shared_networks;
+ getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
+
+ return (shared_networks.empty() ? SharedNetwork6Ptr() : *shared_networks.begin());
+ }
+
+ /// @brief Sends query to retrieve all shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] shared_networks Reference to the shared networks collection
+ /// structure where shared networks should be inserted.
+ void getAllSharedNetworks6(const ServerSelector& server_selector,
+ SharedNetwork6Collection& shared_networks) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching all shared networks for ANY "
+ "server is not supported");
+ }
+
+ auto index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6);
+
+ PsqlBindArray in_bindings;
+ getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
+ }
+
+ /// @brief Sends query to retrieve modified shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] shared_networks Reference to the shared networks collection
+ /// structure where shared networks should be inserted.
+ void getModifiedSharedNetworks6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ SharedNetwork6Collection& shared_networks) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified shared networks for ANY "
+ "server is not supported");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(modification_ts);
+
+ auto index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6);
+ getSharedNetworks6(index, server_selector, in_bindings, shared_networks);
+ }
+
+ /// @brief Sends query to insert or update shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the shared network to be inserted or updated.
+ void createUpdateSharedNetwork6(const ServerSelector& server_selector,
+ const SharedNetwork6Ptr& shared_network) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "creating or updating a shared network for ANY"
+ " server is not supported");
+
+ } else if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(shared_network->getName());
+ in_bindings.addOptional(shared_network->getClientClass(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getIface(Network::Inheritance::NONE));
+ in_bindings.addTimestamp(shared_network->getModificationTime());
+ in_bindings.add(shared_network->getPreferred(Network::Inheritance::NONE));
+ in_bindings.addMin(shared_network->getPreferred(Network::Inheritance::NONE));
+ in_bindings.addMax(shared_network->getPreferred(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getRapidCommit(Network::Inheritance::NONE));
+ in_bindings.add(shared_network->getT2(Network::Inheritance::NONE));
+ addRelayBinding(in_bindings, shared_network);
+ in_bindings.add(shared_network->getT1(Network::Inheritance::NONE));
+ addRequiredClassesBinding(in_bindings, shared_network);
+ in_bindings.addOptional(shared_network->getReservationsGlobal(Network::Inheritance::NONE));
+ in_bindings.add(shared_network->getContext());
+ in_bindings.add(shared_network->getValid(Network::Inheritance::NONE));
+ in_bindings.addMin(shared_network->getValid(Network::Inheritance::NONE));
+ in_bindings.addMax(shared_network->getValid(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getCalculateTeeTimes(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getT1Percent(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getT2Percent(Network::Inheritance::NONE));
+ addInterfaceIdBinding(in_bindings, *shared_network);
+ in_bindings.addOptional(shared_network->getDdnsSendUpdates(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsOverrideNoUpdate(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsOverrideClientUpdate(Network::Inheritance::NONE));
+ addDdnsReplaceClientNameBinding(in_bindings, shared_network);
+ in_bindings.addOptional(shared_network->getDdnsGeneratedPrefix(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getDdnsQualifyingSuffix(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getReservationsInSubnet(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getReservationsOutOfPool(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getCacheThreshold(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getCacheMaxAge(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getAllocatorType(Network::Inheritance::NONE));
+ in_bindings.addOptional(shared_network->getPdAllocatorType(Network::Inheritance::NONE));
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "shared network set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateSharedNetwork6");
+
+ try {
+
+ // Try to insert shared network. The shared network name must be unique,
+ // so if inserting fails with DuplicateEntry exception we'll need to
+ // update existing shared network entry.
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6,
+ in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // It already exists, rollback to the savepoint to preserve
+ // any prior work.
+ conn_.rollbackToSavepoint("createUpdateSharedNetwork6");
+
+ // We're updating, so we need to remove any options.
+ deleteOptions6(ServerSelector::ANY(), shared_network);
+
+ // Need to add one more binding for WHERE clause.
+ in_bindings.addTempString(shared_network->getName());
+
+ // Try the update.
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6,
+ in_bindings);
+
+ // Remove existing server association.
+ PsqlBindArray server_bindings;
+ server_bindings.addTempString(shared_network->getName());
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER,
+ server_bindings);
+ }
+
+ // Associate the shared network with the servers.
+ PsqlBindArray attach_bindings;
+ attach_bindings.addTempString(shared_network->getName());
+ attach_bindings.addTimestamp(shared_network->getModificationTime());
+ attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER,
+ server_selector, attach_bindings);
+
+ // (Re)create options.
+ auto option_spaces = shared_network->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = shared_network->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption6(server_selector, shared_network->getName(),
+ desc_copy, true);
+ }
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert DHCP option.
+ ///
+ /// This method expects that the server selector contains exactly one
+ /// server tag. It is intended to be used within a transaction.
+ ///
+ /// @param server_selector Server selector.
+ /// @param in_bindings Collection of bindings representing an option.
+ /// @param modification_ts option's modification timestamp
+ void insertOption6(const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ const boost::posix_time::ptime& modification_ts) {
+ // Attempt the insert.
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6, in_bindings);
+
+ // Fetch primary key value of the inserted option. We will use it in the
+ // next INSERT statement to associate this option with the server.
+ auto option_id = getLastInsertId("dhcp6_options", "option_id");
+
+ PsqlBindArray attach_bindings;
+ attach_bindings.add(option_id); // id of newly inserted global.
+ attach_bindings.addTimestamp(modification_ts);
+
+ // Associate the option with the servers.
+ attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER,
+ server_selector, attach_bindings);
+ }
+
+ /// @brief Sends query to insert or update global DHCP option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const OptionDescriptorPtr& option) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "creating or updating global option");
+
+ // Create the input parameter bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.add(0);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+ in_bindings.addNull();
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(tag);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "global option set", false);
+
+ // Try to update the option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption6(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a subnet.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ /// @param cascade_update Boolean value indicating whether the update is
+ /// performed as part of the owning element, e.g. subnet.
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option,
+ const bool cascade_update) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.add(subnet_id);
+ in_bindings.add(1);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+ in_bindings.addNull();
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(subnet_id);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "subnet specific option set",
+ cascade_update);
+
+ // Try to update the subnet option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption6(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a pool.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the pool.
+ /// @param pool_end_address Upper bound address of the pool.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const IOAddress& pool_start_address,
+ const IOAddress& pool_end_address,
+ const OptionDescriptorPtr& option) {
+ uint64_t pool_id = 0;
+ Pool6Ptr pool = getPool6(server_selector, pool_start_address, pool_end_address,
+ pool_id);
+ if (!pool) {
+ isc_throw(BadValue, "no pool found for range of "
+ << pool_start_address << " : "
+ << pool_end_address);
+ }
+
+ createUpdateOption6(server_selector, Lease::TYPE_NA,
+ pool_id, option, false);
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a pd pool.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pd_pool_prefix Address part of the pd pool prefix.
+ /// @param pd_pool_prefix_length Length of the pd pool prefix.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ const OptionDescriptorPtr& option) {
+ uint64_t pd_pool_id = 0;
+ Pool6Ptr pd_pool = getPdPool6(server_selector,
+ pd_pool_prefix,
+ pd_pool_prefix_length,
+ pd_pool_id);
+ if (!pd_pool) {
+ isc_throw(BadValue, "no prefix delegation pool found for prefix "
+ << "of " << pd_pool_prefix << "/"
+ << static_cast<unsigned>(pd_pool_prefix_length));
+ }
+
+ createUpdateOption6(server_selector, Lease::TYPE_PD,
+ pd_pool_id, option, false);
+ }
+
+ /// @brief Sends query to insert or update DHCP option in an address
+ /// or prefix delegation pool.
+ ///
+ /// @param selector Server selector.
+ /// @param pool_type Pool type (Lease::TYPE_NA or Lease::TYPE_PD).
+ /// @param pool_id Identifier of the address or prefix delegation pool
+ /// the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ /// @param cascade_update Boolean value indicating whether the update is
+ /// performed as part of the owning element, e.g. subnet.
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const Lease::Type& pool_type,
+ const uint64_t pool_id,
+ const OptionDescriptorPtr& option,
+ const bool cascade_update) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ std::string msg = "creating or updating ";
+ if (pool_type == Lease::TYPE_PD) {
+ msg += "prefix delegation";
+ } else {
+ msg += "address";
+ }
+ msg += " pool level option";
+
+ PsqlBindArray in_bindings;
+
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.addNull();
+
+ // scope_id
+ if (pool_type == Lease::TYPE_NA) {
+ in_bindings.add(5);
+ } else {
+ in_bindings.add(6);
+ }
+
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+
+ // pool_id
+ if (pool_type == Lease::TYPE_NA) {
+ in_bindings.add(pool_id);
+ } else {
+ in_bindings.addNull();
+ }
+
+ in_bindings.addTimestamp(option->getModificationTime());
+
+ // pd_pool_id
+ if (pool_type == Lease::TYPE_PD) {
+ in_bindings.add(pool_id);
+ } else {
+ in_bindings.addNull();
+ }
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(pool_id);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ if (pool_type == Lease::TYPE_PD) {
+ msg = "prefix delegation";
+ } else {
+ msg = "address";
+ }
+ msg += " pool specific option set";
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, msg, cascade_update);
+
+ auto index = (pool_type == Lease::TYPE_NA ?
+ PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID :
+ PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID);
+
+ // Try to update the option.
+ if (updateDeleteQuery(index, in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption6(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a shared network.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network the option
+ /// belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ /// @param cascade_update Boolean value indicating whether the update is
+ /// performed as part of the owning element, e.g. shared network.
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option,
+ const bool cascade_update) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ // Create input bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.add(4);
+ in_bindings.add(option->getContext());
+ in_bindings.add(shared_network_name);
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+ in_bindings.addNull();
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(shared_network_name);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "shared network specific option set",
+ cascade_update);
+
+ // Try to update the option.
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the option.
+ insertOption6(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+
+ // Commit the work.
+ transaction.commit();
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a client class.
+ ///
+ /// @param selector Server selector.
+ /// @param client_class Pointer to the client_class the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option..
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const OptionDescriptorPtr& option) {
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ PsqlBindArray in_bindings;
+ std::string class_name = client_class->getName();
+ in_bindings.add(option->option_->getType());
+ addOptionValueBinding(in_bindings, option);
+ in_bindings.addOptional(option->formatted_value_);
+ in_bindings.addOptional(option->space_name_);
+ in_bindings.add(option->persistent_);
+ in_bindings.add(option->cancelled_);
+ in_bindings.add(class_name);
+ in_bindings.addNull();
+ in_bindings.add(2);
+ in_bindings.add(option->getContext());
+ in_bindings.addNull();
+ in_bindings.addNull();
+ in_bindings.addTimestamp(option->getModificationTime());
+ in_bindings.addNull();
+
+ // Remember the size before we add where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now we add the update where clause parameters
+ in_bindings.add(class_name);
+ in_bindings.add(option->option_->getType());
+ in_bindings.addOptional(option->space_name_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "client class specific option set",
+ true);
+
+ if (updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS,
+ in_bindings) == 0) {
+ // The option doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ insertOption6(server_selector, in_bindings,
+ option->getModificationTime());
+ }
+ }
+
+ /// @brief Sends query to insert or update option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Pointer to the option definition to be inserted or updated.
+ void createUpdateOptionDef6(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def) {
+ createUpdateOptionDef(server_selector, Option::V6, option_def, DHCP6_OPTION_SPACE,
+ PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
+ PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6,
+ PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER);
+ }
+
+ /// @brief Sends query to insert or update option definition
+ /// for a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Pointer to the option definition to be inserted or updated.
+ /// @param client_class Client class name.
+ void createUpdateOptionDef6(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def,
+ const std::string& client_class_name) {
+ createUpdateOptionDef(server_selector, Option::V6, option_def, DHCP6_OPTION_SPACE,
+ PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
+ PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS,
+ PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS,
+ PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER,
+ client_class_name);
+ }
+
+ /// @brief Sends query to delete option definition by code and
+ /// option space name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Option code.
+ /// @param name Option name.
+ /// @return Number of deleted option definitions.
+ uint64_t deleteOptionDef6(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEF6_CODE_NAME,
+ server_selector,
+ "deleting option definition",
+ "option definition deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Sends query to delete option definitions for a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the client class for which option
+ /// definitions should be deleted.
+ /// @return Number of deleted option definitions.
+ uint64_t deleteOptionDefs6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(client_class->getName());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEFS6_CLIENT_CLASS,
+ server_selector,
+ "deleting option definition for a client class",
+ "option definition deleted",
+ true,
+ in_bindings));
+ }
+
+ /// @brief Deletes global option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption6(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6,
+ server_selector,
+ "deleting global option",
+ "global option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes subnet level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to which deleted option
+ /// belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet_id);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID,
+ server_selector,
+ "deleting option for a subnet",
+ "subnet specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound pool address.
+ /// @param pool_end_address Upper bound pool address.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption6(const db::ServerSelector& server_selector,
+ const IOAddress& pool_start_address,
+ const IOAddress& pool_end_address,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.addInet6(pool_start_address);
+ in_bindings.addInet6(pool_end_address);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE,
+ server_selector,
+ "deleting option for an address pool",
+ "address pool specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes pd pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pd_pool_prefix Address part of the pd pool prefix.
+ /// @param pd_pool_prefix_length Length of the pd pool prefix.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption6(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(pd_pool_prefix.toText());
+ in_bindings.add(pd_pool_prefix_length);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL,
+ server_selector,
+ "deleting option for a prefix delegation pool",
+ "prefix delegation pool specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network which deleted
+ /// option belongs to
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ uint64_t deleteOption6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(shared_network_name);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK,
+ server_selector,
+ "deleting option for a shared network",
+ "shared network specific option deleted",
+ false,
+ in_bindings));
+ }
+
+ /// @brief Deletes options belonging to a subnet from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the subnet for which options should be
+ /// deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions6(const ServerSelector& server_selector,
+ const Subnet6Ptr& subnet) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(subnet->getID());
+ in_bindings.addTempString(subnet->toText());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SUBNET_ID_PREFIX,
+ server_selector,
+ "deleting options for a subnet",
+ "subnet specific options deleted",
+ true, in_bindings));
+ }
+
+ /// @brief Deletes options belonging to a shared network from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Pointer to the subnet for which options should be
+ /// deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions6(const ServerSelector& server_selector,
+ const SharedNetwork6Ptr& shared_network) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(shared_network->getName());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::
+ DELETE_OPTIONS6_SHARED_NETWORK, server_selector,
+ "deleting options for a shared network",
+ "shared network specific options deleted",
+ true, in_bindings));
+ }
+
+ /// @brief Deletes options belonging to a client class from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the client class for which options
+ /// should be deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(client_class->getName());
+
+ // Run DELETE.
+ return (deleteTransactional(PgSqlConfigBackendDHCPv6Impl::
+ DELETE_OPTIONS6_CLIENT_CLASS, server_selector,
+ "deleting options for a client class",
+ "client class specific options deleted",
+ true, in_bindings));
+ }
+
+ /// @brief Common function to retrieve client classes.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] client_classes Reference to a container where fetched client
+ /// classes will be inserted.
+ void getClientClasses6(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings,
+ ClientClassDictionary& client_classes) {
+ std::list<ClientClassDefPtr> class_list;
+ uint64_t last_option_id = 0;
+ uint64_t last_option_def_id = 0;
+ std::string last_tag;
+
+ selectQuery(index, in_bindings,
+ [this, &class_list, &last_option_id, &last_option_def_id, &last_tag]
+ (PgSqlResult& r, int row) {
+ // Create a convenience worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ ClientClassDefPtr last_client_class;
+ if (!class_list.empty()) {
+ last_client_class = *class_list.rbegin();
+ }
+
+ // Class ID is column 0.
+ uint64_t id = worker.getBigInt(0) ;
+
+ if (!last_client_class || (last_client_class->getId() != id)) {
+ last_option_id = 0;
+ last_option_def_id = 0;
+ last_tag.clear();
+
+ auto options = boost::make_shared<CfgOption>();
+ auto option_defs = boost::make_shared<CfgOptionDef>();
+
+ last_client_class = boost::make_shared<ClientClassDef>(worker.getString(1),
+ ExpressionPtr(), options);
+ last_client_class->setCfgOptionDef(option_defs);
+
+ // id
+ last_client_class->setId(id);
+
+ // name
+ last_client_class->setName(worker.getString(1));
+
+ // test
+ if (!worker.isColumnNull(2)) {
+ last_client_class->setTest(worker.getString(2));
+ }
+
+ // required
+ if (!worker.isColumnNull(3)) {
+ last_client_class->setRequired(worker.getBool(3));
+ }
+
+ // valid lifetime: default, min, max
+ last_client_class->setValid(worker.getTriplet(4, 5, 6));
+
+ // depend on known directly or indirectly
+ last_client_class->setDependOnKnown(worker.getBool(7) || worker.getBool(8));
+
+ // modification_ts
+ last_client_class->setModificationTime(worker.getTimestamp(9));
+
+ // user_context at 10.
+ if (!worker.isColumnNull(10)) {
+ ElementPtr user_context = worker.getJSON(10);
+ if (user_context) {
+ last_client_class->setContext(user_context);
+ }
+ }
+
+ // class specific option definition from 11 to 20.
+ // class specific option from 21 to 33.
+
+ // preferred lifetime: default, min, max
+ last_client_class->setPreferred(worker.getTriplet(35, 36, 37));
+
+ class_list.push_back(last_client_class);
+ }
+
+ // Check for new server tags at 34.
+ if (!worker.isColumnNull(34)) {
+ std::string new_tag = worker.getString(34);
+ if (last_tag != new_tag) {
+ if (!new_tag.empty() && !last_client_class->hasServerTag(ServerTag(new_tag))) {
+ last_client_class->setServerTag(new_tag);
+ }
+
+ last_tag = new_tag;
+ }
+ }
+
+ // Parse client class specific option definition from 11 to 20.
+ if (!worker.isColumnNull(11) &&
+ (last_option_def_id < worker.getBigInt(11))) {
+ last_option_def_id = worker.getBigInt(11);
+
+ auto def = processOptionDefRow(worker, 11);
+ if (def) {
+ last_client_class->getCfgOptionDef()->add(def);
+ }
+ }
+
+ // Parse client class specific option from 21 to 33.
+ if (!worker.isColumnNull(21) &&
+ (last_option_id < worker.getBigInt(21))) {
+ last_option_id = worker.getBigInt(21);
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, worker, 21);
+ if (desc) {
+ last_client_class->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ tossNonMatchingElements(server_selector, class_list);
+
+ for (auto c : class_list) {
+ client_classes.addClass(c);
+ }
+ }
+
+ /// @brief Sends query to retrieve a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be retrieved.
+ /// @return Pointer to the client class or null if the class is not found.
+ ClientClassDefPtr getClientClass6(const ServerSelector& server_selector,
+ const std::string& name) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(name);
+
+ ClientClassDictionary client_classes;
+ getClientClasses6(PgSqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME,
+ server_selector, in_bindings, client_classes);
+ return (client_classes.getClasses()->empty() ? ClientClassDefPtr() :
+ (*client_classes.getClasses()->begin()));
+ }
+
+ /// @brief Sends query to retrieve all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] client_classes Reference to the client classes collection
+ /// where retrieved classes will be stored.
+ void getAllClientClasses6(const ServerSelector& server_selector,
+ ClientClassDictionary& client_classes) {
+ PsqlBindArray in_bindings;
+ getClientClasses6(server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6,
+ server_selector, in_bindings, client_classes);
+ }
+
+ /// @brief Sends query to retrieve modified client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] client_classes Reference to the client classes collection
+ /// where retrieved classes will be stored.
+ void getModifiedClientClasses6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ ClientClassDictionary& client_classes) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified client classes for ANY "
+ "server is not supported");
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(modification_ts);
+ getClientClasses6(server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6,
+ server_selector, in_bindings, client_classes);
+ }
+
+ /// @brief Upserts client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the upserted client class.
+ /// @param follow_class_name name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ void createUpdateClientClass6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name) {
+ // We need to evaluate class expression to see if it references any
+ // other classes (dependencies). As part of this evaluation we will
+ // also check if the client class depends on KNOWN/UNKNOWN built-in
+ // classes.
+ std::list<std::string> dependencies;
+ auto depend_on_known = false;
+ if (!client_class->getTest().empty()) {
+ ExpressionPtr expression;
+ ExpressionParser parser;
+ // Parse the test expression. The callback function is normally used to
+ // interrupt config file parsing when one of the classes refers to a
+ // non-existing client class. It returns false in this case. Here,
+ // we use the callback to capture client classes referenced by the
+ // upserted client class and record whether this class depends on
+ // KNOWN/UNKNOWN built-ins. The callback always returns true to avoid
+ // reporting the parsing error. The dependency check is performed later
+ // at the database level.
+ parser.parse(expression, Element::create(client_class->getTest()), AF_INET6,
+ [&dependencies, &depend_on_known](const ClientClass& client_class) -> bool {
+ if (isClientClassBuiltIn(client_class)) {
+ if ((client_class == "KNOWN") || (client_class == "UNKNOWN")) {
+ depend_on_known = true;
+ }
+ } else {
+ dependencies.push_back(client_class);
+ }
+ return (true);
+ });
+ }
+
+ PsqlBindArray in_bindings;
+ std::string class_name = client_class->getName();
+ in_bindings.add(class_name);
+ in_bindings.addTempString(client_class->getTest());
+ in_bindings.add(client_class->getRequired());
+ in_bindings.add(client_class->getValid());
+ in_bindings.add(client_class->getValid().getMin());
+ in_bindings.add(client_class->getValid().getMax());
+ in_bindings.add(depend_on_known);
+
+ // follow-class-name (8)
+ if (follow_class_name.empty()) {
+ in_bindings.addNull();
+ } else {
+ in_bindings.add(follow_class_name);
+ }
+
+ in_bindings.add(client_class->getPreferred());
+ in_bindings.add(client_class->getPreferred().getMin());
+ in_bindings.add(client_class->getPreferred().getMax());
+ in_bindings.addTimestamp(client_class->getModificationTime());
+ in_bindings.add(client_class->getContext());
+
+ PgSqlTransaction transaction(conn_);
+
+ ScopedAuditRevision audit_revision(this, PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "client class set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateClass6");
+
+ // Keeps track of whether the client class is inserted or updated.
+ auto update = false;
+ try {
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6, in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // It already exists, rollback to the savepoint to preserve
+ // any prior work.
+ conn_.rollbackToSavepoint("createUpdateClass6");
+
+ // Delete options and option definitions. They will be re-created from the new class
+ // instance.
+ deleteOptions6(ServerSelector::ANY(), client_class);
+ deleteOptionDefs6(ServerSelector::ANY(), client_class);
+
+ // Note: follow_class_name is left in the bindings even though it is
+ // not needed in both cases. This allows us to use one base query.
+
+ // Add the class name for the where clause.
+ in_bindings.add(class_name);
+ if (follow_class_name.empty()) {
+ // If position is not specified, leave the class at the same position.
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6_SAME_POSITION,
+ in_bindings);
+ } else {
+ // Update with follow_class_name specifying the position.
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6,
+ in_bindings);
+ }
+
+ // Delete class associations with the servers and dependencies. We will re-create
+ // them according to the new class specification.
+ PsqlBindArray in_assoc_bindings;
+ in_assoc_bindings.add(class_name);
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY,
+ in_assoc_bindings);
+ updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER,
+ in_assoc_bindings);
+ update = true;
+ }
+
+ // Associate client class with the servers.
+ PsqlBindArray attach_bindings;
+ attach_bindings.add(class_name);
+ attach_bindings.addTimestamp(client_class->getModificationTime());
+
+ attachElementToServers(PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER,
+ server_selector, attach_bindings);
+
+ // Iterate over the captured dependencies and try to insert them into the database.
+ for (auto dependency : dependencies) {
+ try {
+ PsqlBindArray in_dependency_bindings;
+ in_dependency_bindings.add(class_name);
+ in_dependency_bindings.add(dependency);
+
+ // We deleted earlier dependencies, so we can simply insert new ones.
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY,
+ in_dependency_bindings);
+ } catch (const std::exception& ex) {
+ isc_throw(InvalidOperation, "unmet dependency on client class: " << dependency);
+ }
+ }
+
+ // If we performed client class update we also have to verify that its dependency
+ // on KNOWN/UNKNOWN client classes hasn't changed.
+ if (update) {
+ PsqlBindArray in_check_bindings;
+ insertQuery(PgSqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ in_check_bindings);
+ }
+
+ // (Re)create option definitions.
+ if (client_class->getCfgOptionDef()) {
+ auto option_defs = client_class->getCfgOptionDef()->getContainer();
+ auto option_spaces = option_defs.getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionDefContainerPtr defs = option_defs.getItems(option_space);
+ for (auto def = defs->begin(); def != defs->end(); ++def) {
+ createUpdateOptionDef6(server_selector, *def, client_class->getName());
+ }
+ }
+ }
+
+ // (Re)create options.
+ auto option_spaces = client_class->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = client_class->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption6(server_selector, client_class, desc_copy);
+ }
+ }
+
+ // All ok. Commit the transaction.
+ transaction.commit();
+ }
+
+ /// @brief Removes client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Removed client class name.
+ /// @return Number of deleted client classes.
+ uint64_t deleteClientClass6(const ServerSelector& server_selector,
+ const std::string& name) {
+ int index = server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6;
+
+ uint64_t result = deleteTransactional(index, server_selector,
+ "deleting client class",
+ "client class deleted",
+ true,
+ name);
+ return (result);
+ }
+
+ /// @brief Removes unassigned global parameters, global options and
+ /// option definitions.
+ ///
+ /// This function is called when one or more servers are deleted and
+ /// it is likely that there are some orphaned configuration elements
+ /// left in the database. This method removes those elements.
+ void purgeUnassignedConfig() {
+ multipleUpdateDeleteQueries(DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
+ DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
+ DELETE_ALL_OPTION_DEFS6_UNASSIGNED);
+ }
+
+ /// @brief Attempts to delete a server having a given tag.
+ ///
+ /// @param server_tag Tag of the server to be deleted.
+ /// @return Number of deleted servers.
+ /// @throw isc::InvalidOperation when trying to delete the logical
+ /// server 'all'.
+ uint64_t deleteServer6(const data::ServerTag& server_tag) {
+ // It is not allowed to delete 'all' logical server.
+ if (server_tag.amAll()) {
+ isc_throw(InvalidOperation, "'all' is a name reserved for the server tag which"
+ " associates the configuration elements with all servers connecting"
+ " to the database and may not be deleted");
+ }
+
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this, PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ ServerSelector::ALL(), "deleting a server", false);
+
+ // Specify which server should be deleted.
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(server_tag.get());
+
+ // Attempt to delete the server.
+ auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_SERVER6,
+ in_bindings);
+
+ // If we have deleted any servers we have to remove any dangling global
+ // parameters, options and option definitions.
+ if (count > 0) {
+ purgeUnassignedConfig();
+ }
+
+ transaction.commit();
+
+ return (count);
+ }
+
+ /// @brief Attempts to delete all servers.
+ ///
+ /// This method deletes all servers added by the user. It does not
+ /// delete the logical server 'all'.
+ ///
+ /// @return Number of deleted servers.
+ uint64_t deleteAllServers6() {
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this, PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ ServerSelector::ALL(), "deleting all servers",
+ false);
+
+ // No arguments, hence empty input bindings.
+ PsqlBindArray in_bindings;
+
+ // Attempt to delete the servers.
+ auto count = updateDeleteQuery(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6,
+ in_bindings);
+
+ // If we have deleted any servers we have to remove any dangling global
+ // parameters, options and option definitions.
+ if (count > 0) {
+ purgeUnassignedConfig();
+ }
+
+ // Commit the transaction.
+ transaction.commit();
+
+ return (count);
+ }
+
+ /// @brief Attempts to reconnect the server to the config DB backend manager.
+ ///
+ /// This is a self-rescheduling function that attempts to reconnect to the
+ /// server's config DB backends after connectivity to one or more have been
+ /// lost. Upon entry it will attempt to reconnect via
+ /// @ref ConfigBackendDHCPv6Mgr.addBackend.
+ /// If this is successful, DHCP servicing is re-enabled and server returns
+ /// to normal operation.
+ ///
+ /// If reconnection fails and the maximum number of retries has not been
+ /// exhausted, it will schedule a call to itself to occur at the
+ /// configured retry interval. DHCP service remains disabled.
+ ///
+ /// If the maximum number of retries has been exhausted an error is logged
+ /// and the server shuts down.
+ ///
+ /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the
+ /// configured reconnect parameters.
+ /// @return true if connection has been recovered, false otherwise.
+ static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
+ MultiThreadingCriticalSection cs;
+
+ // Invoke application layer connection lost callback.
+ if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
+ return (false);
+ }
+
+ bool reopened = false;
+
+ const std::string timer_name = db_reconnect_ctl->timerName();
+
+ // At least one connection was lost.
+ try {
+ auto srv_cfg = CfgMgr::instance().getCurrentCfg();
+ auto config_ctl = srv_cfg->getConfigControlInfo();
+ // Iterate over the configured DBs and instantiate them.
+ for (auto db : config_ctl->getConfigDatabases()) {
+ const std::string& access = db.getAccessString();
+ auto parameters = db.getParameters();
+ if (ConfigBackendDHCPv6Mgr::instance().delBackend(parameters["type"], access, true)) {
+ ConfigBackendDHCPv6Mgr::instance().addBackend(db.getAccessString());
+ }
+ }
+
+ reopened = true;
+ } catch (const std::exception& ex) {
+ LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_FAILED6)
+ .arg(ex.what());
+ }
+
+ if (reopened) {
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
+ // Invoke application layer connection recovered callback.
+ if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
+ return (false);
+ }
+ } else {
+ if (!db_reconnect_ctl->checkRetries()) {
+ // We're out of retries, log it and initiate shutdown.
+ LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_FAILED6)
+ .arg(db_reconnect_ctl->maxRetries());
+
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
+ // Invoke application layer connection failed callback.
+ DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl);
+
+ return (false);
+ }
+
+ LOG_INFO(pgsql_cb_logger, PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6)
+ .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
+ .arg(db_reconnect_ctl->maxRetries())
+ .arg(db_reconnect_ctl->retryInterval());
+
+ // Start the timer.
+ if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->registerTimer(timer_name,
+ std::bind(&PgSqlConfigBackendDHCPv6Impl::dbReconnect, db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval(),
+ asiolink::IntervalTimer::ONE_SHOT);
+ }
+ TimerMgr::instance()->setup(timer_name);
+ }
+
+ return (true);
+ }
+
+ /// @brief Sets a Network6 interface ID from result set col.
+ ///
+ /// Sets the interface id of the Network6 to the value carried in the
+ /// given column in a result set row.
+ ///
+ /// @param network shared network or subnet to receive the interface ID
+ /// @param worker result set row worker contain the database row
+ /// @param col column within the row from which to take the value
+ void setInterfaceId(Network6& network, PgSqlResultRowWorker& worker, size_t col) {
+ if (!worker.isColumnNull(col)) {
+ std::vector<uint8_t> iface_id_data;
+ worker.getBytes(col, iface_id_data);
+ if (!iface_id_data.empty()) {
+ OptionPtr opt_iface_id(new Option(Option::V6, D6O_INTERFACE_ID, iface_id_data));
+ network.setInterfaceId(opt_iface_id);
+ }
+ }
+ }
+
+ /// @brief Adds network interface ID to a bind array.
+ ///
+ /// Adds the interface id to end of the given bind array as a vector of bytes.
+ ///
+ /// @param bindings PsqlBindArray to which the ID should be added.
+ /// @param network Pointer to shared network or subnet for which ID binding
+ /// should be created.
+ void addInterfaceIdBinding(PsqlBindArray& bindings, const Network6& network) {
+ auto opt_iface_id = network.getInterfaceId(Network::Inheritance::NONE);
+ if (!opt_iface_id) {
+ bindings.addNull();
+ } else {
+ auto iface_id_data = opt_iface_id->getData();
+ if (iface_id_data.empty()) {
+ bindings.addNull();
+ } else {
+ bindings.addTempBinary(iface_id_data);
+ }
+ }
+ }
+
+};
+
+namespace {
+
+/// @brief Array of tagged statements.
+typedef std::array<PgSqlTaggedStatement, PgSqlConfigBackendDHCPv6Impl::NUM_STATEMENTS>
+TaggedStatementArray;
+
+/// @brief Prepared PgSQL statements used by the backend to insert and
+/// retrieve data from the database. They must be in the same order as
+/// PgSqlConfigBackendDHCPv6Impl::StatementIndex. The statement is
+/// the corresponding enum name.
+TaggedStatementArray tagged_statements = { {
+ {
+ // PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ 4,
+ {
+ OID_TIMESTAMP, // 1 audit_ts
+ OID_VARCHAR, // 2 server_tag
+ OID_TEXT, // 3 audit_log_message
+ OID_BOOL // 4 cascade_transaction
+ },
+ "CREATE_AUDIT_REVISION",
+ "select createAuditRevisionDHCP6($1, $2, $3, $4)"
+ },
+
+ // Verify that dependency on KNOWN/UNKNOWN class has not changed.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ 0,
+ {
+ OID_NONE
+ },
+ "CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE",
+ "select checkDHCPv6ClientClassKnownDependencyChange()"
+ },
+
+ // Select global parameter by name.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_GLOBAL_PARAMETER6,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 name
+ },
+ "GET_GLOBAL_PARAMETER6",
+ PGSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.name = $2)
+ },
+
+ // Select all global parameters.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_ALL_GLOBAL_PARAMETERS6",
+ PGSQL_GET_GLOBAL_PARAMETER(dhcp6)
+ },
+
+ // Select modified global parameters.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP // 2 modification_ts
+ },
+ "GET_MODIFIED_GLOBAL_PARAMETERS6",
+ PGSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.modification_ts >= $2)
+ },
+
+ // Select subnet by id.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_NO_TAG,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "GET_SUBNET6_ID_NO_TAG",
+ PGSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_id = $1)
+ },
+
+ // Select subnet by id without specifying server tags.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_ANY,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "GET_SUBNET6_ID_ANY",
+ PGSQL_GET_SUBNET6_ANY(WHERE s.subnet_id = $1)
+ },
+
+ // Select unassigned subnet by id.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_ID_UNASSIGNED,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "GET_SUBNET6_ID_UNASSIGNED",
+ PGSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_id = $1)
+ },
+
+ // Select subnet by prefix.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_NO_TAG,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "GET_SUBNET6_PREFIX_NO_TAG",
+ PGSQL_GET_SUBNET6_NO_TAG(WHERE s.subnet_prefix = $1)
+ },
+
+ // Select subnet by prefix without specifying server tags.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "GET_SUBNET6_PREFIX_ANY",
+ PGSQL_GET_SUBNET6_ANY(WHERE s.subnet_prefix = $1)
+ },
+
+ // Select unassigned subnet by prefix.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SUBNET6_PREFIX_UNASSIGNED,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "GET_SUBNET6_PREFIX_UNASSIGNED",
+ PGSQL_GET_SUBNET6_UNASSIGNED(AND s.subnet_prefix = $1)
+ },
+
+ // Select all subnets.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SUBNETS6",
+ PGSQL_GET_SUBNET6_NO_TAG()
+ },
+
+ // Select all unassigned subnets.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SUBNETS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SUBNETS6_UNASSIGNED",
+ PGSQL_GET_SUBNET6_UNASSIGNED()
+ },
+
+ // Select subnets having modification time later than X.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SUBNETS6",
+ PGSQL_GET_SUBNET6_NO_TAG(WHERE s.modification_ts >= $1)
+ },
+
+ // Select modified and unassigned subnets.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SUBNETS6_UNASSIGNED,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SUBNETS6_UNASSIGNED",
+ PGSQL_GET_SUBNET6_UNASSIGNED(AND s.modification_ts >= $1)
+ },
+
+ // Select subnets belonging to a shared network.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK_SUBNETS6,
+ 1,
+ {
+ OID_VARCHAR // 1 share_network_name
+ },
+ "GET_SHARED_NETWORK_SUBNETS6",
+ PGSQL_GET_SUBNET6_ANY(WHERE s.shared_network_name = $1)
+ },
+
+ // Select pool by address range for a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TEXT, // 2 start_address - cast as inet
+ OID_TEXT // 3 end_address - cast as inet
+ },
+ "GET_POOL6_RANGE",
+ PGSQL_GET_POOL6_RANGE_WITH_TAG(WHERE (srv.tag = $1 OR srv.id = 1) \
+ AND (p.start_address = cast($2 as inet)) \
+ AND (p.end_address = cast($3 as inet)))
+ },
+
+ // Select pool by address range for any server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_POOL6_RANGE_ANY,
+ 2,
+ {
+ OID_TEXT, // 1 start_address - cast as inet
+ OID_TEXT // 2 end_address - cast as inet
+ },
+ "GET_POOL6_RANGE_ANY",
+ PGSQL_GET_POOL6_RANGE_NO_TAG(WHERE (p.start_address = cast($1 as inet)) AND \
+ (p.end_address = cast($2 as inet)))
+ },
+
+ // Select prefix delegation pool for a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_PD_POOL,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR, // 2 pd pool prefix
+ OID_INT2 // 3 prefix length
+ },
+ "GET_PD_POOL",
+ PGSQL_GET_PD_POOL_WITH_TAG(WHERE (srv.tag = $1 OR srv.id = 1) AND p.prefix = $2 AND p.prefix_length = $3)
+ },
+
+ // Select prefix delegation pool for any server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_PD_POOL_ANY,
+ 2,
+ {
+ OID_VARCHAR, // 1 prefix
+ OID_INT2 // 2 prefix length
+ },
+ "GET_PD_POOL_ANY",
+ PGSQL_GET_PD_POOL_NO_TAG(WHERE p.prefix = $1 AND p.prefix_length = $2)
+ },
+
+ // Select shared network by name.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_NO_TAG,
+ 1,
+ {
+ OID_VARCHAR // name of network
+ },
+ "GET_SHARED_NETWORK6_NAME_NO_TAG",
+ PGSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.name = $1)
+ },
+
+ // Select shared network by name without specifying server tags.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_ANY,
+ 1,
+ {
+ OID_VARCHAR // name of network
+ },
+ "GET_SHARED_NETWORK6_NAME_ANY",
+ PGSQL_GET_SHARED_NETWORK6_ANY(WHERE n.name = $1)
+ },
+
+ // Select unassigned shared network by name.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SHARED_NETWORK6_NAME_UNASSIGNED,
+ 1,
+ {
+ OID_VARCHAR // name of network
+ },
+ "GET_SHARED_NETWORK6_NAME_UNASSIGNED",
+ PGSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.name = $1)
+ },
+
+ // Select all shared networks.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SHARED_NETWORKS6",
+ PGSQL_GET_SHARED_NETWORK6_NO_TAG()
+ },
+
+ // Select all unassigned shared networks.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SHARED_NETWORKS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SHARED_NETWORKS6_UNASSIGNED",
+ PGSQL_GET_SHARED_NETWORK6_UNASSIGNED()
+ },
+
+ // Select modified shared networks.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SHARED_NETWORKS6",
+ PGSQL_GET_SHARED_NETWORK6_NO_TAG(WHERE n.modification_ts >= $1)
+ },
+
+ // Select modified and unassigned shared networks.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_SHARED_NETWORKS6_UNASSIGNED",
+ PGSQL_GET_SHARED_NETWORK6_UNASSIGNED(AND n.modification_ts >= $1)
+ },
+
+ // Retrieves option definition by code and space.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "GET_OPTION_DEF6_CODE_SPACE",
+ PGSQL_GET_OPTION_DEF(dhcp6, AND d.code = $2 AND d.space = $3)
+ },
+
+ // Retrieves all option definitions.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_ALL_OPTION_DEFS6",
+ PGSQL_GET_OPTION_DEF(dhcp6)
+ },
+
+ // Retrieves modified option definitions.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP // 2 modification_ts
+ },
+ "GET_MODIFIED_OPTION_DEFS6",
+ PGSQL_GET_OPTION_DEF(dhcp6, AND d.modification_ts >= $2)
+ },
+
+ // Retrieves global option by code and space.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "GET_OPTION6_CODE_SPACE",
+ PGSQL_GET_OPTION6(AND o.scope_id = 0 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Retrieves all global options.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_ALL_OPTIONS6",
+ PGSQL_GET_OPTION6(AND o.scope_id = 0)
+ },
+
+ // Retrieves modified options.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP // 2 modification_ts
+ },
+ "GET_MODIFIED_OPTIONS6",
+ PGSQL_GET_OPTION6(AND o.scope_id = 0 AND o.modification_ts >= $2)
+ },
+
+ // Retrieves an option for a given subnet, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_SUBNET_ID_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8, // 2 subnet_id
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION6_SUBNET_ID_CODE_SPACE",
+ PGSQL_GET_OPTION6(AND o.scope_id = 1 AND o.dhcp6_subnet_id = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Retrieves an option for a given pool, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_POOL_ID_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8, // 2 pool_id
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION6_POOL_ID_CODE_SPACE",
+ PGSQL_GET_OPTION6(AND o.scope_id = 5 AND o.pool_id = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Retrieves an option for a given pd pool, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_PD_POOL_ID_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8, // 2 pd_pool_id
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION6_PD_POOL_ID_CODE_SPACE",
+ PGSQL_GET_OPTION6(AND o.scope_id = 6 AND o.pd_pool_id = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Retrieves an option for a given shared network, option code and space.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_SHARED_NETWORK_CODE_SPACE,
+ 4,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR, // 2 shared_network_name
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "GET_OPTION6_SHARED_NETWORK_CODE_SPACE",
+ PGSQL_GET_OPTION6(AND o.scope_id = 4 AND o.shared_network_name = $2 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Select a client class by name.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME,
+ 1,
+ {
+ OID_VARCHAR // name of class
+ },
+ "GET_CLIENT_CLASS6_NAME",
+ PGSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.name = $1)
+ },
+
+ // Select all client classes.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_CLIENT_CLASSES6",
+ PGSQL_GET_CLIENT_CLASS6_WITH_TAG()
+ },
+
+ // Select all unassigned client classes.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_CLIENT_CLASSES6_UNASSIGNED",
+ PGSQL_GET_CLIENT_CLASS6_UNASSIGNED()
+ },
+
+ // Select modified client classes.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_CLIENT_CLASSES6",
+ PGSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.modification_ts >= $1)
+ },
+
+ // Select modified client classes.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED,
+ 1,
+ {
+ OID_TIMESTAMP // 1 modification_ts
+ },
+ "GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED",
+ PGSQL_GET_CLIENT_CLASS6_UNASSIGNED(AND c.modification_ts >= $1)
+ },
+
+ // Retrieves the most recent audit entries.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_INT8 // 3 revision id
+ },
+ "GET_AUDIT_ENTRIES6_TIME",
+ PGSQL_GET_AUDIT_ENTRIES_TIME(dhcp6)
+ },
+
+ // Retrieves a server by tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_SERVER6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "GET_SERVER6",
+ PGSQL_GET_SERVER(dhcp6)
+ },
+
+ // Retrieves all servers.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6,
+ 0,
+ {
+ OID_NONE
+ },
+ "GET_ALL_SERVERS6",
+ PGSQL_GET_ALL_SERVERS(dhcp6)
+ },
+
+ // Insert global parameter.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6,
+ 4,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 value
+ OID_INT2, // 3 parameter_type
+ OID_TIMESTAMP // 4 modification_ts
+ },
+ "INSERT_GLOBAL_PARAMETER6",
+ PGSQL_INSERT_GLOBAL_PARAMETER(dhcp6)
+ },
+
+ // Insert association of the global parameter with a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_GLOBAL_PARAMETER6_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 parameter_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_GLOBAL_PARAMETER6_SERVER",
+ PGSQL_INSERT_GLOBAL_PARAMETER_SERVER(dhcp6)
+ },
+
+ // Insert a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6,
+ 35,
+ {
+ OID_INT8, // 1 subnet_id,
+ OID_VARCHAR, // 2 subnet_prefix
+ OID_VARCHAR, // 3 client_class
+ OID_VARCHAR, // 4 interface
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_INT8, // 6 preferred_lifetime
+ OID_INT8, // 7 min_preferred_lifetime
+ OID_INT8, // 8 max_preferred_lifetime
+ OID_BOOL, // 9 rapid_commit
+ OID_INT8, // 10 rebind_timer
+ OID_TEXT, // 11 relay
+ OID_INT8, // 12 renew_timer
+ OID_TEXT, // 13 require_client_classes
+ OID_BOOL, // 14 reservations_global
+ OID_VARCHAR, // 15 shared_network_name
+ OID_TEXT, // 16 user_context - cast as json
+ OID_INT8, // 17 valid_lifetime
+ OID_INT8, // 18 min_valid_lifetime
+ OID_INT8, // 19 max_valid_lifetime
+ OID_BOOL, // 20 calculate_tee_times
+ OID_TEXT, // 21 t1_percent - cast as float
+ OID_TEXT, // 22 t2_percent - cast as float
+ OID_BYTEA, // 23 interface_id
+ OID_BOOL, // 24 ddns_send_updates
+ OID_BOOL, // 25 ddns_override_no_update
+ OID_BOOL, // 26 ddns_override_client_update
+ OID_INT8, // 27 ddns_replace_client_name
+ OID_VARCHAR, // 28 ddns_generated_prefix
+ OID_VARCHAR, // 29 ddns_qualifying_suffix
+ OID_BOOL, // 30 reservations_in_subnet
+ OID_BOOL, // 31 reservations_out_of_pool
+ OID_TEXT, // 32 cache_threshold - cast as float
+ OID_INT8, // 33 cache_max_age
+ OID_VARCHAR, // 34 allocator
+ OID_VARCHAR // 35 pd_allocator
+ },
+ "INSERT_SUBNET6",
+ "INSERT INTO dhcp6_subnet("
+ " subnet_id,"
+ " subnet_prefix,"
+ " client_class,"
+ " interface,"
+ " modification_ts,"
+ " preferred_lifetime,"
+ " min_preferred_lifetime,"
+ " max_preferred_lifetime,"
+ " rapid_commit,"
+ " rebind_timer,"
+ " relay,"
+ " renew_timer,"
+ " require_client_classes,"
+ " reservations_global,"
+ " shared_network_name,"
+ " user_context,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " calculate_tee_times,"
+ " t1_percent,"
+ " t2_percent,"
+ " interface_id,"
+ " ddns_send_updates,"
+ " ddns_override_no_update,"
+ " ddns_override_client_update,"
+ " ddns_replace_client_name,"
+ " ddns_generated_prefix,"
+ " ddns_qualifying_suffix,"
+ " reservations_in_subnet,"
+ " reservations_out_of_pool,"
+ " cache_threshold,"
+ " cache_max_age,"
+ " allocator,"
+ " pd_allocator"
+ ") VALUES ("
+ " $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, "
+ " $11, $12, $13, $14, $15, cast($16 as json), $17, $18, $19, $20, "
+ " cast($21 as float), cast($22 as float), $23, $24, $25, $26, $27, $28, $29, $30, "
+ " $31, cast($32 as float), $33, $34, $35"
+ ")"
+ },
+
+ // Insert association of the subnet with a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_SUBNET6_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_SUBNET6_SERVER",
+ PGSQL_INSERT_SUBNET_SERVER(dhcp6)
+ },
+
+ // Insert pool for a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_POOL6,
+ 7,
+ {
+ OID_TEXT, // 1 start_address - cast as inet
+ OID_TEXT, // 2 end_address - cast as inet
+ OID_INT8, // 3 subnet_id
+ OID_VARCHAR, // 4 client_class
+ OID_TEXT, // 5 require_client_classes
+ OID_TEXT, // 6 user_context - cast as json
+ OID_TIMESTAMP // 7 modification_ts
+ },
+ "INSERT_POOL6",
+ PGSQL_INSERT_POOL(dhcp6)
+ },
+
+ // Insert pd pool for a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_PD_POOL,
+ 10,
+ {
+ OID_VARCHAR, // 1 prefix
+ OID_INT2, // 2 prefix_length
+ OID_INT2, // 3 delegated_prefix_length
+ OID_INT8, // 4 subnet_id
+ OID_VARCHAR, // 5 excluded_prefix
+ OID_INT2, // 6 excluded_prefix_length
+ OID_VARCHAR, // 7 client_class
+ OID_TEXT, // 8 require_client_classes
+ OID_TEXT, // 9 user_context - cast as json
+ OID_TIMESTAMP, // 10 modification_ts
+ },
+ "INSERT_PD_POOL",
+ PGSQL_INSERT_PD_POOL()
+ },
+
+ // Insert a shared network.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6,
+ 33,
+ {
+ OID_VARCHAR, // 1 name
+ OID_VARCHAR, // 2 client_class
+ OID_VARCHAR, // 3 interface
+ OID_TIMESTAMP, // 4 modification_ts
+ OID_INT8, // 5 preferred_lifetime
+ OID_INT8, // 6 min_preferred_lifetime
+ OID_INT8, // 7 max_preferred_lifetime
+ OID_BOOL, // 8 rapid_commit
+ OID_INT8, // 9 rebind_timer
+ OID_TEXT, // 10 relay
+ OID_INT8, // 11 renew_timer
+ OID_TEXT, // 12 require_client_classes
+ OID_BOOL, // 13 reservations_global
+ OID_TEXT, // 14 user_context - cast as json
+ OID_INT8, // 15 valid_lifetime
+ OID_INT8, // 16 min_valid_lifetime
+ OID_INT8, // 17 max_valid_lifetime
+ OID_BOOL, // 18 calculate_tee_times
+ OID_TEXT, // 19 t1_percent - cast as float
+ OID_TEXT, // 20 t2_percent - cast as float
+ OID_BYTEA, // 21 interface-id
+ OID_BOOL, // 22 ddns_send_updates
+ OID_BOOL, // 23 ddns_override_no_update
+ OID_BOOL, // 24 ddns_override_client_update
+ OID_INT8, // 25 ddns_replace_client_name
+ OID_VARCHAR, // 26 ddns_generated_prefix
+ OID_VARCHAR, // 27 ddns_qualifying_suffix
+ OID_BOOL, // 28 reservations_in_subnet
+ OID_BOOL, // 29 reservations_out_of_pool
+ OID_TEXT, // 30 cache_threshold - cast as float
+ OID_INT8, // 31 cache_max_age
+ OID_VARCHAR, // 32 allocator
+ OID_VARCHAR // 33 pd_allocator
+ },
+ "INSERT_SHARED_NETWORK6",
+ "INSERT INTO dhcp6_shared_network("
+ " name,"
+ " client_class,"
+ " interface,"
+ " modification_ts,"
+ " preferred_lifetime,"
+ " min_preferred_lifetime,"
+ " max_preferred_lifetime,"
+ " rapid_commit,"
+ " rebind_timer,"
+ " relay,"
+ " renew_timer,"
+ " require_client_classes,"
+ " reservations_global,"
+ " user_context,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " calculate_tee_times,"
+ " t1_percent,"
+ " t2_percent,"
+ " interface_id,"
+ " ddns_send_updates,"
+ " ddns_override_no_update,"
+ " ddns_override_client_update,"
+ " ddns_replace_client_name,"
+ " ddns_generated_prefix,"
+ " ddns_qualifying_suffix,"
+ " reservations_in_subnet,"
+ " reservations_out_of_pool,"
+ " cache_threshold,"
+ " cache_max_age,"
+ " allocator,"
+ " pd_allocator"
+ ") VALUES ("
+ " $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, "
+ " $11, $12, $13, cast($14 as json), $15, $16, $17, $18,"
+ " cast($19 as float), cast($20 as float), $21, $22, $23,"
+ " $24, $25, $26, $27, $28, $29, cast($30 as float), $31, $32, $33"
+ ")"
+ },
+
+ // Insert association of the shared network with a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_SHARED_NETWORK6_SERVER,
+ 3,
+ {
+ OID_VARCHAR, // 1 shared_network_name
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_SHARED_NETWORK6_SERVER",
+ PGSQL_INSERT_SHARED_NETWORK_SERVER(dhcp6)
+ },
+
+ // Insert option definition.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6,
+ 10,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_VARCHAR, // 9 user_context
+ OID_INT8 // 10 class_id
+ },
+ "INSERT_OPTION_DEF6",
+ PGSQL_INSERT_OPTION_DEF(dhcp6)
+ },
+
+ // Insert option definition for client class.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS,
+ 10,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_VARCHAR, // 9 user_context
+ OID_VARCHAR // 10 class name for where clause
+ },
+ "INSERT_OPTION_DEF6_CLIENT_CLASS",
+ PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp6)
+ },
+
+ // Insert association of the option definition with a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 option_def_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_OPTION_DEF6_SERVER",
+ PGSQL_INSERT_OPTION_DEF_SERVER(dhcp6)
+ },
+
+ // Insert subnet specific option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6,
+ 14,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8 // 14 pd_pool_id
+ },
+ "INSERT_OPTION6",
+ PGSQL_INSERT_OPTION6()
+ },
+
+ // Insert association of the DHCP option with a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_OPTION6_SERVER,
+ 3,
+ {
+ OID_INT8, // 1 option_id
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_OPTION6_SERVER",
+ PGSQL_INSERT_OPTION_SERVER(dhcp6)
+ },
+
+ // Insert client class.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6,
+ 13,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 test
+ OID_BOOL, // 3 only_if_required
+ OID_INT8, // 4 valid_lifetime
+ OID_INT8, // 5 min_valid_lifetime
+ OID_INT8, // 6 max_valid_lifetime
+ OID_BOOL, // 7 depend_on_known_directly
+ OID_VARCHAR, // 8 follow_class_name
+ OID_INT8, // 9 preferred_lifetime
+ OID_INT8, // 10 min_preferred_lifetime
+ OID_INT8, // 11 max_preferred_lifetime
+ OID_TIMESTAMP, // 12 modification_ts
+ OID_TEXT // 13 user_context cast as JSON
+ },
+ "INSERT_CLIENT_CLASS6",
+ "INSERT INTO dhcp6_client_class("
+ " name,"
+ " test,"
+ " only_if_required,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " depend_on_known_directly,"
+ " follow_class_name,"
+ " preferred_lifetime,"
+ " min_preferred_lifetime,"
+ " max_preferred_lifetime,"
+ " modification_ts,"
+ " user_context "
+ ") VALUES ("
+ " $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, cast($13 as JSON)"
+ ")"
+ },
+
+ // Insert association of a client class with a server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER,
+ 3,
+ {
+ OID_VARCHAR, // 1 class_name
+ OID_TIMESTAMP, // 2 modification_ts
+ OID_VARCHAR // 3 server_tag
+ },
+ "INSERT_CLIENT_CLASS6_SERVER",
+ PGSQL_INSERT_CLIENT_CLASS_SERVER(dhcp6)
+ },
+
+ // Insert client class dependency.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY,
+ 2,
+ {
+ OID_VARCHAR, // class name
+ OID_VARCHAR // dependency class name
+ },
+ "INSERT_CLIENT_CLASS6_DEPENDENCY",
+ PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp6)
+ },
+
+ // Insert server with server tag and description.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::INSERT_SERVER6,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR, // 2 description
+ OID_TIMESTAMP // 3 modification_ts
+ },
+ "INSERT_SERVER6",
+ PGSQL_INSERT_SERVER(dhcp6)
+ },
+
+ // Update existing global parameter.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_GLOBAL_PARAMETER6,
+ 6,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 value
+ OID_INT2, // 3 parameter_type
+ OID_TIMESTAMP, // 4 modification_ts
+ OID_VARCHAR, // 5 server_tag
+ OID_VARCHAR, // 6 name (of global to update)
+ },
+ "UPDATE_GLOBAL_PARAMETER6",
+ PGSQL_UPDATE_GLOBAL_PARAMETER(dhcp6)
+ },
+
+ // Update existing subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_SUBNET6,
+ 37,
+ {
+ OID_INT8, // 1 subnet_id,
+ OID_VARCHAR, // 2 subnet_prefix
+ OID_VARCHAR, // 3 client_class
+ OID_VARCHAR, // 4 interface
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_INT8, // 6 preferred_lifetime
+ OID_INT8, // 7 min_preferred_lifetime
+ OID_INT8, // 8 max_preferred_lifetime
+ OID_BOOL, // 9 rapid_commit
+ OID_INT8, // 10 rebind_timer
+ OID_TEXT, // 11 relay
+ OID_INT8, // 12 renew_timer
+ OID_TEXT, // 13 require_client_classes
+ OID_BOOL, // 14 reservations_global
+ OID_VARCHAR, // 15 shared_network_name
+ OID_TEXT, // 16 user_context - cast as json
+ OID_INT8, // 17 valid_lifetime
+ OID_INT8, // 18 min_valid_lifetime
+ OID_INT8, // 19 max_valid_lifetime
+ OID_BOOL, // 20 calculate_tee_times
+ OID_TEXT, // 21 t1_percent - cast as float
+ OID_TEXT, // 22 t2_percent - cast as float
+ OID_BYTEA, // 23 interface_id
+ OID_BOOL, // 24 ddns_send_updates
+ OID_BOOL, // 25 ddns_override_no_update
+ OID_BOOL, // 26 ddns_override_client_update
+ OID_INT8, // 27 ddns_replace_client_name
+ OID_VARCHAR, // 28 ddns_generated_prefix
+ OID_VARCHAR, // 29 ddns_qualifying_suffix
+ OID_BOOL, // 30 reservations_in_subnet
+ OID_BOOL, // 31 reservations_out_of_pool
+ OID_TEXT, // 32 cache_threshold - cast as float
+ OID_INT8, // 33 cache_max_age
+ OID_VARCHAR, // 34 allocator
+ OID_VARCHAR // 35 pd_allocator
+ },
+ "UPDATE_SUBNET6",
+ "UPDATE dhcp6_subnet SET"
+ " subnet_id = $1,"
+ " subnet_prefix = $2,"
+ " client_class = $3,"
+ " interface = $4,"
+ " modification_ts = $5,"
+ " preferred_lifetime = $6,"
+ " min_preferred_lifetime = $7,"
+ " max_preferred_lifetime = $8,"
+ " rapid_commit = $9,"
+ " rebind_timer = $10,"
+ " relay = $11,"
+ " renew_timer = $12,"
+ " require_client_classes = $13,"
+ " reservations_global = $14,"
+ " shared_network_name = $15,"
+ " user_context = cast($16 as json),"
+ " valid_lifetime = $17,"
+ " min_valid_lifetime = $18,"
+ " max_valid_lifetime = $19,"
+ " calculate_tee_times = $20,"
+ " t1_percent = cast($21 as float),"
+ " t2_percent = cast($22 as float),"
+ " interface_id = $23,"
+ " ddns_send_updates = $24,"
+ " ddns_override_no_update = $25,"
+ " ddns_override_client_update = $26,"
+ " ddns_replace_client_name = $27,"
+ " ddns_generated_prefix = $28,"
+ " ddns_qualifying_suffix = $29,"
+ " reservations_in_subnet = $30,"
+ " reservations_out_of_pool = $31,"
+ " cache_threshold = cast($32 as float),"
+ " cache_max_age = $33,"
+ " allocator = $34,"
+ " pd_allocator = $35 "
+ "WHERE subnet_id = $36 OR subnet_prefix = $37"
+ },
+
+ // Update existing shared network.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_SHARED_NETWORK6,
+ 34,
+ {
+ OID_VARCHAR, // 1 name
+ OID_VARCHAR, // 2 client_class
+ OID_VARCHAR, // 3 interface
+ OID_TIMESTAMP, // 4 modification_ts
+ OID_INT8, // 5 preferred_lifetime
+ OID_INT8, // 6 min_preferred_lifetime
+ OID_INT8, // 7 max_preferred_lifetime
+ OID_BOOL, // 8 rapid_commit
+ OID_INT8, // 9 rebind_timer
+ OID_TEXT, // 10 relay
+ OID_INT8, // 11 renew_timer
+ OID_TEXT, // 12 require_client_classes
+ OID_BOOL, // 13 reservations_global
+ OID_TEXT, // 14 user_context - cast as json
+ OID_INT8, // 15 valid_lifetime
+ OID_INT8, // 16 min_valid_lifetime
+ OID_INT8, // 17 max_valid_lifetime
+ OID_BOOL, // 18 calculate_tee_times
+ OID_TEXT, // 19 t1_percent - cast as float
+ OID_TEXT, // 20 t2_percent - cast as float
+ OID_BYTEA, // 21 interface-id
+ OID_BOOL, // 22 ddns_send_updates
+ OID_BOOL, // 23 ddns_override_no_update
+ OID_BOOL, // 24 ddns_override_client_update
+ OID_INT8, // 25 ddns_replace_client_name
+ OID_VARCHAR, // 26 ddns_generated_prefix
+ OID_VARCHAR, // 27 ddns_qualifying_suffix
+ OID_BOOL, // 28 reservations_in_subnet
+ OID_BOOL, // 29 reservations_out_of_pool
+ OID_TEXT, // 30 cache_threshold - cast as float
+ OID_INT8, // 31 cache_max_age
+ OID_VARCHAR, // 32 allocator
+ OID_VARCHAR // 33 pd_allocator
+ },
+ "UPDATE_SHARED_NETWORK6",
+ "UPDATE dhcp6_shared_network SET"
+ " name = $1,"
+ " client_class = $2,"
+ " interface = $3,"
+ " modification_ts = $4,"
+ " preferred_lifetime = $5,"
+ " min_preferred_lifetime = $6,"
+ " max_preferred_lifetime = $7,"
+ " rapid_commit = $8,"
+ " rebind_timer = $9,"
+ " relay = $10,"
+ " renew_timer = $11,"
+ " require_client_classes = $12,"
+ " reservations_global = $13,"
+ " user_context = cast($14 as json),"
+ " valid_lifetime = $15,"
+ " min_valid_lifetime = $16,"
+ " max_valid_lifetime = $17,"
+ " calculate_tee_times = $18,"
+ " t1_percent = cast($19 as float),"
+ " t2_percent = cast($20 as float),"
+ " interface_id = $21,"
+ " ddns_send_updates = $22,"
+ " ddns_override_no_update = $23,"
+ " ddns_override_client_update = $24,"
+ " ddns_replace_client_name = $25,"
+ " ddns_generated_prefix = $26,"
+ " ddns_qualifying_suffix = $27,"
+ " reservations_in_subnet = $28,"
+ " reservations_out_of_pool = $29,"
+ " cache_threshold = cast($30 as float),"
+ " cache_max_age = $31,"
+ " allocator = $32,"
+ " pd_allocator = $33 "
+ "WHERE name = $34"
+ },
+
+ // Update existing option definition.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6,
+ 13,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_TEXT, // 9 user_context
+ OID_INT2, // 10 class_id
+ OID_VARCHAR, // 11 server_tag
+ OID_INT2, // 12 code (of option to update)
+ OID_VARCHAR, // 13 space (of option to update)
+ },
+ "UPDATE_OPTION_DEF6",
+ PGSQL_UPDATE_OPTION_DEF(dhcp6)
+ },
+
+ // Update existing client class option definition.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS,
+ 13,
+ {
+ OID_INT2, // 1 code
+ OID_VARCHAR, // 2 name
+ OID_VARCHAR, // 3 space
+ OID_INT2, // 4 type
+ OID_TIMESTAMP, // 5 modification_ts
+ OID_BOOL, // 6 is_array
+ OID_VARCHAR, // 7 encapsulate
+ OID_VARCHAR, // 8 record_types
+ OID_TEXT, // 9 user_context
+ OID_VARCHAR, // 10 name (of class option belongs to)
+ OID_VARCHAR, // 11 server_tag
+ OID_INT2, // 12 code (of option to update)
+ OID_VARCHAR, // 13 space (of option to update)
+ },
+ "UPDATE_OPTION_DEF6_CLIENT_CLASS",
+ PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp6)
+ },
+
+ // Update existing global option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
+ 17,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pd_pool_id
+ OID_VARCHAR, // 15 server_tag
+ OID_INT2, // 16 code (of option to update)
+ OID_VARCHAR, // 17 space (of option to update)
+ },
+ "UPDATE_OPTION6",
+ PGSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = $16 AND o.space = $17)
+ },
+
+ // Update existing subnet level option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SUBNET_ID,
+ 17,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pd_pool_id
+ OID_INT8, // 15 subnet_id (of option to update)
+ OID_INT2, // 16 code (of option to update)
+ OID_VARCHAR // 17 space (of option to update)
+ },
+ "UPDATE_OPTION6_SUBNET_ID",
+ PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 1 AND o.dhcp6_subnet_id = $15 AND o.code = $16 AND o.space = $17)
+ },
+
+ // Update existing pool level option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_POOL_ID,
+ 17,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pd_pool_id
+ OID_INT8, // 15 pool_id (of option to update)
+ OID_INT2, // 16 code (of option to update)
+ OID_VARCHAR // 17 space (of option to update)
+ },
+ "UPDATE_OPTION6_POOL_ID",
+ PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 5 AND o.pool_id = $15 AND o.code = $16 AND o.space = $17)
+ },
+
+ // Update existing pd pool level option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_PD_POOL_ID,
+ 17,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pd_pool_id
+ OID_INT8, // 15 pd_pool_id (of option to update)
+ OID_INT2, // 16 code (of option to update)
+ OID_VARCHAR // 17 space (of option to update)
+ },
+ "UPDATE_OPTION6_PD_POOL_ID",
+ PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 6 AND o.pd_pool_id = $15 AND o.code = $16 AND o.space = $17)
+ },
+
+ // Update existing shared network level option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_SHARED_NETWORK,
+ 17,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pd_pool_id
+ OID_VARCHAR, // 15 shared_network_name (of option to update)
+ OID_INT2, // 16 code (of option to update)
+ OID_VARCHAR // 17 space (of option to update)
+ },
+ "UPDATE_OPTION6_SHARED_NETWORK",
+ PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = $15 AND o.code = $16 AND o.space = $17)
+ },
+
+ // Update existing client class level option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS,
+ 17,
+ {
+ OID_INT2, // 1 code
+ OID_BYTEA, // 2 value
+ OID_TEXT, // 3 formatted_value
+ OID_VARCHAR, // 4 space
+ OID_BOOL, // 5 persistent
+ OID_BOOL, // 6 cancelled
+ OID_VARCHAR, // 7 dhcp_client_class
+ OID_INT8, // 8 dhcp6_subnet_id
+ OID_INT2, // 9 scope_id
+ OID_TEXT, // 10 user_context
+ OID_VARCHAR, // 11 shared_network_name
+ OID_INT8, // 12 pool_id
+ OID_TIMESTAMP, // 13 modification_ts
+ OID_INT8, // 14 pd_pool_id
+ OID_VARCHAR, // 15 client_class (of option to update)
+ OID_INT2, // 16 code (of option to update)
+ OID_VARCHAR // 17 space (of option to update)
+ },
+ "UPDATE_OPTION6_CLIENT_CLASS",
+ PGSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = $15 AND o.code = $16 AND o.space = $17)
+ },
+
+ // Update existing client class with specifying its position.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6,
+ 14,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 test
+ OID_BOOL, // 3 only_if_required
+ OID_INT8, // 4 valid_lifetime
+ OID_INT8, // 5 min_valid_lifetime
+ OID_INT8, // 6 max_valid_lifetime
+ OID_BOOL, // 7 depend_on_known_directly
+ OID_VARCHAR, // 8 follow_class_name
+ OID_INT8, // 9 preferred_lifetime
+ OID_INT8, // 10 min_preferred_lifetime
+ OID_INT8, // 11 max_preferred_lifetime
+ OID_TIMESTAMP, // 12 modification_ts
+ OID_TEXT, // 13 user_context
+ OID_VARCHAR // 14 name (of class to update)
+ },
+ "UPDATE_CLIENT_CLASS6",
+ PGSQL_UPDATE_CLIENT_CLASS6("follow_class_name = $8,")
+ },
+
+ // Update existing client class without specifying its position.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6_SAME_POSITION,
+ 14,
+ {
+ OID_VARCHAR, // 1 name
+ OID_TEXT, // 2 test
+ OID_BOOL, // 3 only_if_required
+ OID_INT8, // 4 valid_lifetime
+ OID_INT8, // 5 min_valid_lifetime
+ OID_INT8, // 6 max_valid_lifetime
+ OID_BOOL, // 7 depend_on_known_directly
+ OID_VARCHAR, // 8 follow_class_name
+ OID_INT8, // 9 preferred_lifetime
+ OID_INT8, // 10 min_preferred_lifetime
+ OID_INT8, // 11 max_preferred_lifetime
+ OID_TIMESTAMP, // 12 modification_ts
+ OID_TEXT, // 13 user_context
+ OID_VARCHAR // 14 name (of class to update)
+ },
+ "UPDATE_CLIENT_CLASS6_SAME_POSITION",
+ PGSQL_UPDATE_CLIENT_CLASS6("")
+ },
+
+ // Update existing server, e.g. server description.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::UPDATE_SERVER6,
+ 4,
+ {
+ OID_VARCHAR, // 1 tag
+ OID_VARCHAR, // 2 description
+ OID_TIMESTAMP, // 3 modification_ts
+ OID_VARCHAR // 4 tag (of server to update)
+ },
+ "UPDATE_SERVER6",
+ PGSQL_UPDATE_SERVER(dhcp6)
+ },
+
+ // Delete global parameter by name.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 name of parameter
+ },
+ "DELETE_GLOBAL_PARAMETER6",
+ PGSQL_DELETE_GLOBAL_PARAMETER(dhcp6, AND g.name = $2)
+ },
+
+ // Delete all global parameters.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_GLOBAL_PARAMETERS6",
+ PGSQL_DELETE_GLOBAL_PARAMETER(dhcp6)
+ },
+
+ // Delete all global parameters which are unassigned to any servers.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_GLOBAL_PARAMETERS6_UNASSIGNED",
+ PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(dhcp6)
+ },
+
+ // Delete subnet by id with specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_WITH_TAG,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT8 // 2 subnet_id
+ },
+ "DELETE_SUBNET6_ID_WITH_TAG",
+ PGSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_id = $2)
+ },
+
+ // Delete subnet by id without specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_ID_ANY,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "DELETE_SUBNET6_ID_ANY",
+ PGSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_id = $1)
+ },
+
+ // Delete subnet by prefix with specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_WITH_TAG,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_SUBNET6_PREFIX_WITH_TAG",
+ PGSQL_DELETE_SUBNET_WITH_TAG(dhcp6, AND s.subnet_prefix = $2)
+ },
+
+ // Delete subnet by prefix without specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_PREFIX_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 subnet_prefix
+ },
+ "DELETE_SUBNET6_PREFIX_ANY",
+ PGSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.subnet_prefix = $1)
+ },
+
+ // Delete all subnets.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_SUBNETS6",
+ PGSQL_DELETE_SUBNET_WITH_TAG(dhcp6)
+ },
+
+ // Delete all unassigned subnets.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_SUBNETS6_UNASSIGNED",
+ PGSQL_DELETE_SUBNET_UNASSIGNED(dhcp6)
+ },
+
+ // Delete all subnets for a shared network.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME,
+ 1,
+ {
+ OID_VARCHAR // 1 shared_network_name
+ },
+ "DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME",
+ PGSQL_DELETE_SUBNET_ANY(dhcp6, WHERE s.shared_network_name = $1)
+ },
+
+ // Delete associations of a subnet with server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SUBNET6_SERVER,
+ 1,
+ {
+ OID_INT8 // 1 subnet_id
+ },
+ "DELETE_SUBNET6_SERVER",
+ PGSQL_DELETE_SUBNET_SERVER(dhcp6),
+ },
+
+ // Delete pools for a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_POOLS6,
+ 2,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_POOLS6",
+ PGSQL_DELETE_POOLS(dhcp6)
+ },
+
+ // Delete pd pools for a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_PD_POOLS,
+ 2,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_PD_POOLS",
+ PGSQL_DELETE_PD_POOLS()
+ },
+
+ // Delete shared network by name with specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 shared_network_name
+ },
+ "DELETE_SHARED_NETWORK6_NAME_WITH_TAG",
+ PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6, AND n.name = $2)
+ },
+
+ // Delete shared network by name without specifying server tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 shared_network_name
+ },
+ "DELETE_SHARED_NETWORK6_NAME_ANY",
+ PGSQL_DELETE_SHARED_NETWORK_ANY(dhcp6, WHERE n.name = $1)
+ },
+
+ // Delete all shared networks.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_SHARED_NETWORKS6",
+ PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(dhcp6)
+ },
+
+ // Delete all unassigned shared networks.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED",
+ PGSQL_DELETE_SHARED_NETWORK_UNASSIGNED(dhcp6)
+ },
+
+ // Delete associations of a shared network with server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_SERVER,
+ 1,
+ {
+ OID_VARCHAR // 1 shared_network_name
+ },
+ "DELETE_SHARED_NETWORK6_SERVER",
+ PGSQL_DELETE_SHARED_NETWORK_SERVER(dhcp6)
+ },
+
+ // Delete option definition.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEF6_CODE_NAME,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION_DEF6_CODE_NAME",
+ PGSQL_DELETE_OPTION_DEF(dhcp6, AND code = $2 AND space = $3)
+ },
+
+ // Delete all option definitions.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_OPTION_DEFS6",
+ PGSQL_DELETE_OPTION_DEF(dhcp6)
+ },
+
+ // Delete all option definitions which are assigned to no servers.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_OPTION_DEFS6_UNASSIGNED",
+ PGSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp6)
+ },
+
+ // Delete client class specific option definitions.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEFS6_CLIENT_CLASS,
+ 1,
+ {
+ OID_VARCHAR // 1 class name
+ },
+ "DELETE_OPTION_DEFS6_CLIENT_CLASS",
+ PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp6)
+ },
+
+ // Delete single global option.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6,
+ 3,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION6",
+ PGSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Delete all global options which are unassigned to any servers.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED",
+ PGSQL_DELETE_OPTION_UNASSIGNED(dhcp6, AND o.scope_id = 0)
+ },
+
+ // Delete single option from a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SUBNET_ID,
+ 3,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION6_SUBNET_ID",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp6,
+ WHERE o.scope_id = 1 AND o.dhcp6_subnet_id = $1 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Delete single option from a pool.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_POOL_RANGE,
+ 4,
+ {
+ OID_TEXT, // 1 start_address - cast as inet
+ OID_TEXT, // 2 start_address - cast as inet
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "DELETE_OPTION6_POOL_RANGE",
+ PGSQL_DELETE_OPTION_POOL_RANGE(dhcp6, o.scope_id = 5 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Delete single option from a pd pool.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_PD_POOL,
+ 4,
+ {
+ OID_TEXT, // 1 prefix
+ OID_INT2, // 2 prefix_length
+ OID_INT2, // 3 code
+ OID_VARCHAR // 4 space
+ },
+ "DELETE_OPTION6_PD_POOL",
+ PGSQL_DELETE_OPTION_PD_POOL(o.scope_id = 6 AND o.code = $3 AND o.space = $4)
+ },
+
+ // Delete single option from a shared network.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTION6_SHARED_NETWORK,
+ 3,
+ {
+ OID_VARCHAR, // 1 shared_network_name
+ OID_INT2, // 2 code
+ OID_VARCHAR // 3 space
+ },
+ "DELETE_OPTION6_SHARED_NETWORK",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp6,
+ WHERE o.scope_id = 4 AND o.shared_network_name = $1 AND o.code = $2 AND o.space = $3)
+ },
+
+ // Delete options belonging to a subnet.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SUBNET_ID_PREFIX,
+ 2,
+ {
+ OID_INT8, // 1 subnet_id
+ OID_VARCHAR // 2 subnet_prefix
+ },
+ "DELETE_OPTIONS6_SUBNET_ID_PREFIX",
+ PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX(dhcp6)
+ },
+
+ // Delete options belonging to a shared_network.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_SHARED_NETWORK,
+ 1,
+ {
+ OID_VARCHAR // shared_network_name
+ },
+ "DELETE_OPTIONS6_SHARED_NETWORK",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 4 AND o.shared_network_name = $1)
+ },
+
+ // Delete options belonging to a client class.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_CLIENT_CLASS,
+ 1,
+ {
+ OID_VARCHAR // dhcp_client_class
+ },
+ "DELETE_OPTIONS6_CLIENT_CLASS",
+ PGSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 2 AND o.dhcp_client_class = $1)
+ },
+
+ // Delete all dependencies of a client class.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY,
+ 1,
+ {
+ OID_VARCHAR, // 1 class name
+ },
+ "DELETE_CLIENT_CLASS6_DEPENDENCY",
+ PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp6)
+ },
+
+ // Delete associations of a client class with server.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER,
+ 1,
+ {
+ OID_VARCHAR // 1 class name
+ },
+ "DELETE_CLIENT_CLASS6_SERVER",
+ PGSQL_DELETE_CLIENT_CLASS_SERVER(dhcp6),
+ },
+
+ // Delete all client classes.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6,
+ 1,
+ {
+ OID_VARCHAR // 1 server_tag
+ },
+ "DELETE_ALL_CLIENT_CLASSES6",
+ PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6)
+ },
+
+ // Delete all unassigned client classes.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED",
+ PGSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp6)
+ },
+
+ // Delete specified client class.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6,
+ 2,
+ {
+ OID_VARCHAR, // 1 server_tag
+ OID_VARCHAR // 2 name
+ },
+ "DELETE_CLIENT_CLASS6",
+ PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6, AND name = $2)
+ },
+
+ // Delete any client class with a given name.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY,
+ 1,
+ {
+ OID_VARCHAR // 1 name
+ },
+ "DELETE_CLIENT_CLASS6_ANY",
+ PGSQL_DELETE_CLIENT_CLASS_ANY(dhcp6, AND name = $1)
+ },
+
+ // Delete a server by tag.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_SERVER6,
+ 1,
+ {
+ OID_VARCHAR // server_tag
+ },
+ "DELETE_SERVER6",
+ PGSQL_DELETE_SERVER(dhcp6)
+ },
+
+ // Deletes all servers except logical server 'all'.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SERVERS6,
+ 0,
+ {
+ OID_NONE
+ },
+ "DELETE_ALL_SERVERS6",
+ PGSQL_DELETE_ALL_SERVERS(dhcp6)
+ },
+
+ // Fetches the last sequence id for the given table and column.
+ {
+ // PgSqlConfigBackendDHCPv6Impl::GET_LAST_INSERT_ID6,
+ // args are: table name, sequence column name
+ 2,
+ {
+ OID_VARCHAR,
+ OID_VARCHAR
+ },
+ "GET_LAST_INSERT_ID6",
+ "SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE($1, $2))"
+ }
+}
+};
+
+} // end anonymous namespace
+
+PgSqlConfigBackendDHCPv6Impl::PgSqlConfigBackendDHCPv6Impl(const DatabaseConnection::ParameterMap& parameters)
+ : PgSqlConfigBackendImpl(parameters, &PgSqlConfigBackendDHCPv6Impl::dbReconnect,
+ PgSqlConfigBackendDHCPv6Impl::GET_LAST_INSERT_ID6) {
+ // Prepare query statements. Those are will be only used to retrieve
+ // information from the database, so they can be used even if the
+ // database is read only for the current user.
+ conn_.prepareStatements(tagged_statements.begin(),
+ tagged_statements.end());
+// @todo As part of enabling read-only CB access, statements need to
+// be limited:
+// tagged_statements.begin() + WRITE_STMTS_BEGIN);
+
+ // Create unique timer name per instance.
+ timer_name_ = "PgSqlConfigBackend6[";
+ timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
+ timer_name_ += "]DbReconnectTimer";
+
+ // Create ReconnectCtl for this connection.
+ conn_.makeReconnectCtl(timer_name_);
+}
+
+PgSqlConfigBackendDHCPv6Impl::~PgSqlConfigBackendDHCPv6Impl() {
+}
+
+PgSqlTaggedStatement&
+PgSqlConfigBackendDHCPv6Impl::getStatement(size_t index) const {
+ if (index >= tagged_statements.size()) {
+ isc_throw(BadValue, "PgSqlConfigBackendDHCPv6Impl::getStatement index: "
+ << index << ", is invalid");
+ }
+
+ return(tagged_statements[index]);
+}
+
+PgSqlConfigBackendDHCPv6::PgSqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters)
+ : impl_(new PgSqlConfigBackendDHCPv6Impl(parameters)), base_impl_(impl_) {
+}
+
+bool
+PgSqlConfigBackendDHCPv6::isUnusable() {
+ return (impl_->conn_.isUnusable());
+}
+
+DatabaseConnection::ParameterMap
+PgSqlConfigBackendDHCPv6::getParameters() const {
+ return (impl_->getParameters());
+}
+
+Subnet6Ptr
+PgSqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET6_BY_PREFIX)
+ .arg(subnet_prefix);
+ return (impl_->getSubnet6(server_selector, subnet_prefix));
+}
+
+Subnet6Ptr
+PgSqlConfigBackendDHCPv6::getSubnet6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID)
+ .arg(subnet_id);
+ return (impl_->getSubnet6(server_selector, subnet_id));
+}
+
+Subnet6Collection
+PgSqlConfigBackendDHCPv6::getAllSubnets6(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS6);
+ Subnet6Collection subnets;
+ impl_->getAllSubnets6(server_selector, subnets);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SUBNETS6_RESULT)
+ .arg(subnets.size());
+ return (subnets);
+}
+
+Subnet6Collection
+PgSqlConfigBackendDHCPv6::getModifiedSubnets6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS6)
+ .arg(util::ptimeToText(modification_time));
+ Subnet6Collection subnets;
+ impl_->getModifiedSubnets6(server_selector, modification_time, subnets);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT)
+ .arg(subnets.size());
+ return (subnets);
+}
+
+Subnet6Collection
+PgSqlConfigBackendDHCPv6::getSharedNetworkSubnets6(const ServerSelector& /* server_selector */,
+ const std::string& shared_network_name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6)
+ .arg(shared_network_name);
+ Subnet6Collection subnets;
+ impl_->getSharedNetworkSubnets6(ServerSelector::ANY(), shared_network_name, subnets);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT)
+ .arg(subnets.size());
+ return (subnets);
+}
+
+SharedNetwork6Ptr
+PgSqlConfigBackendDHCPv6::getSharedNetwork6(const ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SHARED_NETWORK6)
+ .arg(name);
+ return (impl_->getSharedNetwork6(server_selector, name));
+}
+
+SharedNetwork6Collection
+PgSqlConfigBackendDHCPv6::getAllSharedNetworks6(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS6);
+ SharedNetwork6Collection shared_networks;
+ impl_->getAllSharedNetworks6(server_selector, shared_networks);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT)
+ .arg(shared_networks.size());
+ return (shared_networks);
+}
+
+SharedNetwork6Collection
+PgSqlConfigBackendDHCPv6::getModifiedSharedNetworks6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6)
+ .arg(util::ptimeToText(modification_time));
+ SharedNetwork6Collection shared_networks;
+ impl_->getModifiedSharedNetworks6(server_selector, modification_time, shared_networks);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT)
+ .arg(shared_networks.size());
+ return (shared_networks);
+}
+
+OptionDefinitionPtr
+PgSqlConfigBackendDHCPv6::getOptionDef6(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION_DEF6)
+ .arg(code).arg(space);
+ return (impl_->getOptionDef(PgSqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
+ server_selector, code, space));
+}
+
+OptionDefContainer
+PgSqlConfigBackendDHCPv6::getAllOptionDefs6(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS6);
+ OptionDefContainer option_defs;
+ impl_->getAllOptionDefs(PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTION_DEFS6,
+ server_selector, option_defs);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT)
+ .arg(option_defs.size());
+ return (option_defs);
+}
+
+OptionDefContainer
+PgSqlConfigBackendDHCPv6::getModifiedOptionDefs6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS6)
+ .arg(util::ptimeToText(modification_time));
+ OptionDefContainer option_defs;
+ impl_->getModifiedOptionDefs(PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTION_DEFS6,
+ server_selector, modification_time, option_defs);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT)
+ .arg(option_defs.size());
+ return (option_defs);
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendDHCPv6::getOption6(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_OPTION6)
+ .arg(code).arg(space);
+ return (impl_->getOption(PgSqlConfigBackendDHCPv6Impl::GET_OPTION6_CODE_SPACE,
+ Option::V6, server_selector, code, space));
+}
+
+OptionContainer
+PgSqlConfigBackendDHCPv6::getAllOptions6(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS6);
+ OptionContainer options = impl_->getAllOptions(PgSqlConfigBackendDHCPv6Impl::GET_ALL_OPTIONS6,
+ Option::V6, server_selector);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_OPTIONS6_RESULT)
+ .arg(options.size());
+ return (options);
+}
+
+OptionContainer
+PgSqlConfigBackendDHCPv6::getModifiedOptions6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS6)
+ .arg(util::ptimeToText(modification_time));
+ OptionContainer options = impl_->getModifiedOptions(PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_OPTIONS6,
+ Option::V6, server_selector, modification_time);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT)
+ .arg(options.size());
+ return (options);
+}
+
+StampedValuePtr
+PgSqlConfigBackendDHCPv6::getGlobalParameter6(const ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_GLOBAL_PARAMETER6)
+ .arg(name);
+ return (impl_->getGlobalParameter6(server_selector, name));
+}
+
+StampedValueCollection
+PgSqlConfigBackendDHCPv6::getAllGlobalParameters6(const ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6);
+ StampedValueCollection parameters;
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ impl_->getGlobalParameters(PgSqlConfigBackendDHCPv6Impl::GET_ALL_GLOBAL_PARAMETERS6,
+ in_bindings, parameters);
+ }
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT)
+ .arg(parameters.size());
+ return (parameters);
+}
+
+StampedValueCollection
+PgSqlConfigBackendDHCPv6::getModifiedGlobalParameters6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6)
+ .arg(util::ptimeToText(modification_time));
+ StampedValueCollection parameters;
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addTimestamp(modification_time);
+
+ impl_->getGlobalParameters(PgSqlConfigBackendDHCPv6Impl::GET_MODIFIED_GLOBAL_PARAMETERS6,
+ in_bindings, parameters);
+ }
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT)
+ .arg(parameters.size());
+ return (parameters);
+}
+
+ClientClassDefPtr
+PgSqlConfigBackendDHCPv6::getClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_CLIENT_CLASS6)
+ .arg(name);
+ return (impl_->getClientClass6(server_selector, name));
+}
+
+ClientClassDictionary
+PgSqlConfigBackendDHCPv6::getAllClientClasses6(const db::ServerSelector& server_selector) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES6);
+ ClientClassDictionary client_classes;
+ impl_->getAllClientClasses6(server_selector, client_classes);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT)
+ .arg(client_classes.getClasses()->size());
+ return (client_classes);
+}
+
+ClientClassDictionary
+PgSqlConfigBackendDHCPv6::getModifiedClientClasses6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6)
+ .arg(util::ptimeToText(modification_time));
+ ClientClassDictionary client_classes;
+ impl_->getModifiedClientClasses6(server_selector, modification_time, client_classes);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT)
+ .arg(client_classes.getClasses()->size());
+ return (client_classes);
+}
+
+AuditEntryCollection
+PgSqlConfigBackendDHCPv6::getRecentAuditEntries(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t& modification_id) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6)
+ .arg(util::ptimeToText(modification_time))
+ .arg(modification_id);
+ AuditEntryCollection audit_entries;
+ impl_->getRecentAuditEntries(PgSqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME,
+ server_selector, modification_time,
+ modification_id, audit_entries);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT)
+ .arg(audit_entries.size());
+ return (audit_entries);
+}
+
+ServerCollection
+PgSqlConfigBackendDHCPv6::getAllServers6() const {
+ ServerCollection servers;
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS6);
+ impl_->getAllServers(PgSqlConfigBackendDHCPv6Impl::GET_ALL_SERVERS6,
+ servers);
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_ALL_SERVERS6_RESULT)
+ .arg(servers.size());
+ return (servers);
+}
+
+ServerPtr
+PgSqlConfigBackendDHCPv6::getServer6(const data::ServerTag& server_tag) const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_SERVER6)
+ .arg(server_tag.get());
+ return (impl_->getServer(PgSqlConfigBackendDHCPv6Impl::GET_SERVER6, server_tag));
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateSubnet6(const ServerSelector& server_selector,
+ const Subnet6Ptr& subnet) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SUBNET6)
+ .arg(subnet);
+ impl_->createUpdateSubnet6(server_selector, subnet);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateSharedNetwork6(const ServerSelector& server_selector,
+ const SharedNetwork6Ptr& shared_network) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6)
+ .arg(shared_network->getName());
+ impl_->createUpdateSharedNetwork6(server_selector, shared_network);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateOptionDef6(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION_DEF6)
+ .arg(option_def->getName()).arg(option_def->getCode());
+ impl_->createUpdateOptionDef6(server_selector, option_def);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_OPTION6);
+ impl_->createUpdateOption6(server_selector, option);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateOption6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6)
+ .arg(shared_network_name);
+ impl_->createUpdateOption6(server_selector, shared_network_name, option, false);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6)
+ .arg(subnet_id);
+ impl_->createUpdateOption6(server_selector, subnet_id, option, false);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6)
+ .arg(pool_start_address.toText()).arg(pool_end_address.toText());
+ impl_->createUpdateOption6(server_selector, pool_start_address, pool_end_address,
+ option);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateOption6(const ServerSelector& server_selector,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ const OptionDescriptorPtr& option) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6)
+ .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length);
+ impl_->createUpdateOption6(server_selector, pd_pool_prefix,
+ pd_pool_prefix_length, option);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateGlobalParameter6(const ServerSelector& server_selector,
+ const StampedValuePtr& value) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6)
+ .arg(value->getName());
+ impl_->createUpdateGlobalParameter6(server_selector, value);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6)
+ .arg(client_class->getName());
+ impl_->createUpdateClientClass6(server_selector, client_class, follow_class_name);
+}
+
+void
+PgSqlConfigBackendDHCPv6::createUpdateServer6(const ServerPtr& server) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_CREATE_UPDATE_SERVER6)
+ .arg(server->getServerTagAsText());
+ impl_->createUpdateServer(PgSqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ PgSqlConfigBackendDHCPv6Impl::INSERT_SERVER6,
+ PgSqlConfigBackendDHCPv6Impl::UPDATE_SERVER6,
+ server);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector,
+ const std::string& subnet_prefix) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET6)
+ .arg(subnet_prefix);
+ uint64_t result = impl_->deleteSubnet6(server_selector, subnet_prefix);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteSubnet6(const ServerSelector& server_selector,
+ const SubnetID& subnet_id) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6)
+ .arg(subnet_id);
+ uint64_t result = impl_->deleteSubnet6(server_selector, subnet_id);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteAllSubnets6(const ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS6);
+
+ int index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all subnets",
+ "deleted all subnets", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteSharedNetworkSubnets6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name) {
+ if (!server_selector.amAny()) {
+ isc_throw(InvalidOperation, "deleting all subnets from a shared "
+ "network requires using ANY server selector");
+ }
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6)
+ .arg(shared_network_name);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SUBNETS6_SHARED_NETWORK_NAME,
+ server_selector,
+ "deleting all subnets for a shared network",
+ "deleted all subnets for a shared network",
+ true, shared_network_name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteSharedNetwork6(const ServerSelector& server_selector,
+ const std::string& name) {
+ /// @todo Using UNASSIGNED selector is allowed by the CB API but we don't have
+ /// dedicated query for this at the moment. The user should use ANY to delete
+ /// the shared network by name.
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "deleting an unassigned shared network requires "
+ "an explicit server tag or using ANY server. The UNASSIGNED server "
+ "selector is currently not supported");
+ }
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK6)
+ .arg(name);
+
+ int index = (server_selector.amAny() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_ANY :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_SHARED_NETWORK6_NAME_WITH_TAG);
+ uint64_t result = impl_->deleteTransactional(index, server_selector,
+ "deleting a shared network",
+ "shared network deleted", true, name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteAllSharedNetworks6(const ServerSelector& server_selector) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "deleting all shared networks for ANY server is not"
+ " supported");
+ }
+
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6);
+
+ int index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_SHARED_NETWORKS6);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all shared networks",
+ "deleted all shared networks", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteOptionDef6(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF6)
+ .arg(code).arg(space);
+ uint64_t result = impl_->deleteOptionDef6(server_selector, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION_DEF6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteAllOptionDefs6(const ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS6);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_OPTION_DEFS6,
+ server_selector, "deleting all option definitions",
+ "deleted all option definitions", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION6)
+ .arg(code).arg(space);
+ uint64_t result = impl_->deleteOption6(server_selector, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_OPTION6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ /// @todo In the future we might use the server selector to make sure that the
+ /// option is only deleted if the pool belongs to a given server. For now, we
+ /// just delete it when there is a match with the parent object.
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6)
+ .arg(shared_network_name).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), shared_network_name,
+ code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ /// @todo In the future we might use the server selector to make sure that the
+ /// option is only deleted if the pool belongs to a given server. For now, we
+ /// just delete it when there is a match with the parent object.
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6)
+ .arg(subnet_id).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), subnet_id, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const uint16_t code,
+ const std::string& space) {
+ /// @todo In the future we might use the server selector to make sure that the
+ /// option is only deleted if the pool belongs to a given server. For now, we
+ /// just delete it when there is a match with the parent object.
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION6)
+ .arg(pool_start_address.toText()).arg(pool_end_address.toText()).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pool_start_address,
+ pool_end_address, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteOption6(const ServerSelector& /* server_selector */,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ const uint16_t code,
+ const std::string& space) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6)
+ .arg(pd_pool_prefix.toText()).arg(pd_pool_prefix_length).arg(code).arg(space);
+ uint64_t result = impl_->deleteOption6(ServerSelector::ANY(), pd_pool_prefix,
+ pd_pool_prefix_length, code, space);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteGlobalParameter6(const ServerSelector& server_selector,
+ const std::string& name) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER6)
+ .arg(name);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_GLOBAL_PARAMETER6,
+ server_selector, "deleting global parameter",
+ "global parameter deleted", false, name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteAllGlobalParameters6(const ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6);
+ uint64_t result = impl_->deleteTransactional(PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_GLOBAL_PARAMETERS6,
+ server_selector, "deleting all global parameters",
+ "all global parameters deleted", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS6)
+ .arg(name);
+ auto result = impl_->deleteClientClass6(server_selector, name);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteAllClientClasses6(const db::ServerSelector& server_selector) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6);
+
+ int index = (server_selector.amUnassigned() ?
+ PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED :
+ PgSqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes",
+ "deleted all client classes", true);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteServer6(const ServerTag& server_tag) {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER6)
+ .arg(server_tag.get());
+ uint64_t result = impl_->deleteServer6(server_tag);
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_SERVER6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+PgSqlConfigBackendDHCPv6::deleteAllServers6() {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS6);
+ uint64_t result = impl_->deleteAllServers6();
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_DELETE_ALL_SERVERS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+std::string
+PgSqlConfigBackendDHCPv6::getType() const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_TYPE6);
+ return (impl_->getType());
+}
+
+std::string
+PgSqlConfigBackendDHCPv6::getHost() const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_HOST6);
+ return (impl_->getHost());
+}
+
+uint16_t
+PgSqlConfigBackendDHCPv6::getPort() const {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_GET_PORT6);
+ return (impl_->getPort());
+}
+
+bool
+PgSqlConfigBackendDHCPv6::registerBackendType() {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_REGISTER_BACKEND_TYPE6);
+ return (
+ dhcp::ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("postgresql",
+ [](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv6Ptr {
+ return (dhcp::PgSqlConfigBackendDHCPv6Ptr(new dhcp::PgSqlConfigBackendDHCPv6(params)));
+ })
+ );
+}
+
+void
+PgSqlConfigBackendDHCPv6::unregisterBackendType() {
+ LOG_DEBUG(pgsql_cb_logger, DBGLVL_TRACE_BASIC, PGSQL_CB_UNREGISTER_BACKEND_TYPE6);
+ dhcp::ConfigBackendDHCPv6Mgr::instance().unregisterBackendFactory("postgresql");
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h
new file mode 100644
index 0000000..e3f08f5
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_dhcp6.h
@@ -0,0 +1,664 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PGSQL_CONFIG_BACKEND_DHCP6_H
+#define PGSQL_CONFIG_BACKEND_DHCP6_H
+
+#include <pgsql_cb_impl.h>
+#include <database/database_connection.h>
+#include <dhcpsrv/client_class_def.h>
+#include <dhcpsrv/config_backend_dhcp6.h>
+#include <pgsql_cb_log.h>
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dhcp {
+
+class PgSqlConfigBackendDHCPv6Impl;
+
+/// @brief Implementation of the PgSql Configuration Backend for
+/// Kea DHCPv6 server.
+///
+/// All POSIX times specified in the methods belonging to this
+/// class must be local times.
+///
+/// The server selection mechanisms used by this backend generally adhere
+/// to the rules described for @c ConfigBackendDHCPv6, but support for
+/// some of the selectors is not implemented. Whenever this is the case,
+/// the methods throw @c isc::NotImplemented exception.
+class PgSqlConfigBackendDHCPv6 : public ConfigBackendDHCPv6 {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ explicit PgSqlConfigBackendDHCPv6(const db::DatabaseConnection::ParameterMap& parameters);
+
+ /// @brief Retrieves a single subnet by subnet_prefix.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_prefix Prefix of the subnet to be retrieved.
+ /// @return Pointer to the retrieved subnet or NULL if not found.
+ virtual Subnet6Ptr
+ getSubnet6(const db::ServerSelector& server_selector,
+ const std::string& subnet_prefix) const;
+
+ /// @brief Retrieves a single subnet by subnet identifier.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of a subnet to be retrieved.
+ /// @return Pointer to the retrieved subnet or NULL if not found.
+ virtual Subnet6Ptr
+ getSubnet6(const db::ServerSelector& server_selector, const SubnetID& subnet_id) const;
+
+ /// @brief Retrieves all subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of subnets or empty collection if no subnet found.
+ virtual Subnet6Collection
+ getAllSubnets6(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves subnets modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound subnet modification time.
+ /// @return Collection of subnets or empty collection if no subnet found.
+ virtual Subnet6Collection
+ getModifiedSubnets6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves all subnets belonging to a specified shared network.
+ ///
+ /// The server selector is currently ignored by this method. All subnets
+ /// for the given shared network are returned regardless of their
+ /// associations with the servers.
+ ///
+ /// @param server_selector Server selector (currently ignored).
+ /// @param shared_network_name Name of the shared network for which the
+ /// subnets should be retrieved.
+ /// @return Collection of subnets or empty collection if no subnet found.
+ virtual Subnet6Collection
+ getSharedNetworkSubnets6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name) const;
+
+ /// @brief Retrieves shared network by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the shared network to be retrieved.
+ /// @return Pointer to the shared network or NULL if not found.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual SharedNetwork6Ptr
+ getSharedNetwork6(const db::ServerSelector& server_selector,
+ const std::string& name) const;
+
+ /// @brief Retrieves all shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of shared network or empty collection if
+ /// no shared network found.
+ virtual SharedNetwork6Collection
+ getAllSharedNetworks6(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves shared networks modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound shared network modification time.
+ /// @return Collection of shared network or empty collection if
+ /// no shared network found.
+ virtual SharedNetwork6Collection
+ getModifiedSharedNetworks6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves single option definition by code and space.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the option to be retrieved.
+ /// @param space Option space of the option to be retrieved.
+ /// @return Pointer to the option definition or NULL if not found.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual OptionDefinitionPtr
+ getOptionDef6(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space) const;
+
+ /// @brief Retrieves all option definitions.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of option definitions or empty collection if
+ /// no option definition found.
+ virtual OptionDefContainer
+ getAllOptionDefs6(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves option definitions modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound option definition modification
+ /// time.
+ /// @return Collection of option definitions or empty collection if
+ /// no option definition found.
+ virtual OptionDefContainer
+ getModifiedOptionDefs6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves single option by code and space.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Pointer to the retrieved option descriptor or null if
+ /// no option was found.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual OptionDescriptorPtr
+ getOption6(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space) const;
+
+ /// @brief Retrieves all global options.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Collection of global options or empty collection if no
+ /// option found.
+ virtual OptionContainer
+ getAllOptions6(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves option modified after specified time.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound option modification time.
+ /// @return Collection of global options or empty collection if no
+ /// option found.
+ virtual OptionContainer
+ getModifiedOptions6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves global parameter value.
+ ///
+ /// Typically, the server selector used for this query should be set to
+ /// ONE. It is possible to use the MULTIPLE server selector but in that
+ /// case only the first found parameter is returned.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the global parameter to be retrieved.
+ /// @return Value of the global parameter.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual data::StampedValuePtr
+ getGlobalParameter6(const db::ServerSelector& server_selector,
+ const std::string& name) const;
+
+ /// @brief Retrieves all global parameters.
+ ///
+ /// Using the server selector it is possible to fetch the parameters for
+ /// one or more servers. The following list describes what parameters are
+ /// returned depending on the server selector specified:
+ /// - ALL: only common parameters are returned which are associated with
+ /// the logical server 'all'. No parameters associated with the explicit
+ /// server tags are returned.
+ ///
+ /// - ONE: parameters used by the particular sever are returned. This includes
+ /// parameters associated with the particular server (identified by tag)
+ /// and parameters associated with the logical server 'all' when server
+ /// specific parameters are not given. For example, if there is a
+ /// renew-timer specified for 'server1' tag, different value of the
+ /// renew-timer specified for 'all' servers and a rebind-timer specified
+ /// for 'all' servers, the caller will receive renew-timer value associated
+ /// with the server1 and the rebind-timer value associated with all servers,
+ /// because there is no explicit rebind-timer specified for server1.
+ ///
+ /// - MULTIPLE: parameters used by multiple servers, but those associated
+ /// with specific server tags take precedence over the values specified for
+ /// 'all' servers. This is similar to the case of ONE server described
+ /// above. The effect of querying for parameters belonging to multiple
+ /// servers is the same as issuing multiple queries with ONE server
+ /// being selected multiple times.
+ ///
+ /// - UNASSIGNED: parameters not associated with any servers.
+ ///
+ ///
+ /// @param server_selector Server selector.
+ virtual data::StampedValueCollection
+ getAllGlobalParameters6(const db::ServerSelector& server_selector) const;
+
+ /// @brief Retrieves global parameters modified after specified time.
+ ///
+ /// @param modification_time Lower bound modification time.
+ /// @return Collection of modified global parameters.
+ virtual data::StampedValueCollection
+ getModifiedGlobalParameters6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Client class name.
+ /// @return Pointer to the retrieved client class.
+ virtual ClientClassDefPtr
+ getClientClass6(const db::ServerSelector& selector, const std::string& name) const;
+
+ /// @brief Retrieves all client classes.
+ ///
+ /// @param selector Server selector.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getAllClientClasses6(const db::ServerSelector& selector) const;
+
+ /// @brief Retrieves client classes modified after specified time.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Modification time.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getModifiedClientClasses6(const db::ServerSelector& selector,
+ const boost::posix_time::ptime& modification_time) const;
+
+ /// @brief Retrieves the most recent audit entries.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Timestamp being a lower limit for the returned
+ /// result set, i.e. entries later than specified time are returned.
+ /// @param modification_id Identifier being a lower limit for the returned
+ /// result set, used when two (or more) entries have the same
+ /// modification_time.
+ /// @return Collection of audit entries.
+ virtual db::AuditEntryCollection
+ getRecentAuditEntries(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t& modification_id) const;
+
+ /// @brief Retrieves all servers.
+ ///
+ /// This method returns the list of servers excluding the logical server
+ /// 'all'.
+ ///
+ /// @return Collection of servers from the backend.
+ virtual db::ServerCollection
+ getAllServers6() const;
+
+ /// @brief Retrieves a server.
+ ///
+ /// @param server_tag Tag of the server to be retrieved.
+ /// @return Pointer to the server instance or null pointer if no server
+ /// with the particular tag was found.
+ virtual db::ServerPtr
+ getServer6(const data::ServerTag& server_tag) const;
+
+ /// @brief Creates or updates a subnet.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet Subnet to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateSubnet6(const db::ServerSelector& server_selector,
+ const Subnet6Ptr& subnet);
+
+ /// @brief Creates or updates a shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network Shared network to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateSharedNetwork6(const db::ServerSelector& server_selector,
+ const SharedNetwork6Ptr& shared_network);
+
+ /// @brief Creates or updates an option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Option definition to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOptionDef6(const db::ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def);
+
+ /// @brief Creates or updates global option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption6(const db::ServerSelector& server_selector,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates shared network level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of a shared network to which option
+ /// belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates subnet level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of a subnet to which option belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption6(const db::ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the pool to which
+ /// the option belongs.
+ /// @param pool_end_address Upper bound address of the pool to which the
+ /// option belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption6(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates prefix delegation pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pd_pool_prefix Address part of the prefix of the prefix
+ /// delegation pool to which the option belongs.
+ /// @param pd_pool_prefix_length Prefix length of the prefix
+ /// delegation pool to which the option belongs.
+ /// @param option Option to be added or updated.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateOption6(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the global parameter.
+ /// @param value Value of the global parameter.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual void
+ createUpdateGlobalParameter6(const db::ServerSelector& server_selector,
+ const data::StampedValuePtr& value);
+
+ /// @brief Creates or updates DHCPv6 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Client class to be added or updated.
+ /// @param follow_class_name name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ virtual void
+ createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name);
+
+ /// @brief Creates or updates a server.
+ ///
+ /// @param server Instance of the server to be stored.
+ /// @throw InvalidOperation when trying to create a duplicate or
+ /// update the logical server 'all'.
+ virtual void
+ createUpdateServer6(const db::ServerPtr& server);
+
+ /// @brief Deletes subnet by prefix.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_prefix Prefix of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteSubnet6(const db::ServerSelector& server_selector,
+ const std::string& subnet_prefix);
+
+ /// @brief Deletes subnet by identifier.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to be deleted.
+ /// @return Number of deleted subnets.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteSubnet6(const db::ServerSelector& server_selector, const SubnetID& subnet_id);
+
+ /// @brief Deletes all subnets.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted subnets.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteAllSubnets6(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes all subnets belonging to a specified shared network.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network for which the
+ /// subnets should be deleted.
+ /// @return Number of deleted subnets.
+ virtual uint64_t
+ deleteSharedNetworkSubnets6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name);
+
+ /// @brief Deletes shared network by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the shared network to be deleted.
+ /// @return Number of deleted shared networks.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteSharedNetwork6(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all shared networks.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted shared networks.
+ virtual uint64_t
+ deleteAllSharedNetworks6(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the option to be deleted.
+ /// @param space Option space of the option to be deleted.
+ /// @return Number of deleted option definitions.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOptionDef6(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes all option definitions.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted option definitions.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteAllOptionDefs6(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes global option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param code Code of the option to be deleted.
+ /// @param space Option space of the option to be deleted.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption6(const db::ServerSelector& server_selector, const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of the shared network which deleted
+ /// option belongs to
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption6(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes subnet level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param subnet_id Identifier of the subnet to which deleted option
+ /// belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption6(const db::ServerSelector& server_selector, const SubnetID& subnet_id,
+ const uint16_t code, const std::string& space);
+
+ /// @brief Deletes pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the pool to which
+ /// deleted option belongs.
+ /// @param pool_end_address Upper bound address of the pool to which the
+ /// deleted option belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption6(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pool_start_address,
+ const asiolink::IOAddress& pool_end_address,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes prefix delegation pool level option.
+ ///
+ /// @param server_selector Server selector.
+ /// @param pool_start_address Lower bound address of the prefix
+ /// delegation pool to which deleted option belongs.
+ /// @param pool_end_address Upper bound address of the prefix
+ /// delegation pool to which the deleted option belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ /// @return Number of deleted options.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteOption6(const db::ServerSelector& server_selector,
+ const asiolink::IOAddress& pd_pool_prefix,
+ const uint8_t pd_pool_prefix_length,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Deletes global parameter.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the global parameter to be deleted.
+ /// @return Number of deleted global parameters.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteGlobalParameter6(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all global parameters.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted global parameters.
+ /// @throw NotImplemented if server selector is "unassigned".
+ virtual uint64_t
+ deleteAllGlobalParameters6(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes DHCPv6 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be deleted.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteAllClientClasses6(const db::ServerSelector& server_selector);
+
+ /// @brief Deletes a server from the backend.
+ ///
+ /// @param server_tag Tag of the server to be deleted.
+ /// @return Number of deleted servers.
+ /// @throw isc::InvalidOperation when trying to delete the logical
+ /// server 'all'.
+ virtual uint64_t
+ deleteServer6(const data::ServerTag& server_tag);
+
+ /// @brief Deletes all servers from the backend except the logical
+ /// server 'all'.
+ ///
+ /// @return Number of deleted servers.
+ virtual uint64_t
+ deleteAllServers6();
+
+ /// @brief Returns backend type in the textual format.
+ ///
+ /// @return "postgresql".
+ virtual std::string getType() const;
+
+ /// @brief Returns backend host.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return host on which the database is located.
+ virtual std::string getHost() const;
+
+ /// @brief Returns backend port number.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return Port number on which database service is available.
+ virtual uint16_t getPort() const;
+
+ /// @brief Registers the PgSQL backend factory with backend config manager
+ ///
+ /// This should be called by the hook lib load() function.
+ /// @return True if the factory was registered successfully, false otherwise.
+ static bool registerBackendType();
+
+ /// @brief Unregisters the PgSQL backend factory and discards PgSQL backends
+ ///
+ /// This should be called by the hook lib unload() function.
+ static void unregisterBackendType();
+
+ /// @brief Flag which indicates if the config backend has an unusable
+ /// connection.
+ ///
+ /// @return true if there is at least one unusable connection, false
+ /// otherwise
+ virtual bool isUnusable();
+
+ /// @brief Return backend parameters
+ ///
+ /// Returns the backend parameters
+ ///
+ /// @return Parameters of the backend.
+ isc::db::DatabaseConnection::ParameterMap getParameters() const;
+
+protected:
+
+ /// @brief Pointer to the implementation of the @c PgSqlConfigBackendDHCPv6
+ /// class.
+ boost::shared_ptr<PgSqlConfigBackendDHCPv6Impl> impl_;
+
+ /// @brief Pointer to the base implementation of the backend shared by
+ /// DHCPv4 and DHCPv6 servers.
+ boost::shared_ptr<PgSqlConfigBackendImpl> base_impl_;
+};
+
+/// @brief Pointer to the @c PgSqlConfigBackendDHCPv6 class.
+typedef boost::shared_ptr<PgSqlConfigBackendDHCPv6> PgSqlConfigBackendDHCPv6Ptr;
+
+} // end of namespace isc::cb
+} // end of namespace isc
+
+#endif // PGSQL_CONFIG_BACKEND_DHCP6_H
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc
new file mode 100644
index 0000000..c8addbf
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc
@@ -0,0 +1,1148 @@
+// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <config_backend/constants.h>
+#include <dhcp/option_space.h>
+#include <database/db_exceptions.h>
+#include <pgsql/pgsql_exchange.h>
+#include <util/buffer.h>
+
+#include <pgsql_cb_impl.h>
+#include <pgsql_cb_log.h>
+#include <cstdint>
+#include <utility>
+
+using namespace isc::asiolink;
+using namespace isc::cb;
+using namespace isc::data;
+using namespace isc::db;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr();
+
+PgSqlTaggedStatement&
+PgSqlConfigBackendImpl::getStatement(size_t /* index */) const {
+ isc_throw(NotImplemented, "derivations must override this");
+}
+
+void
+PgSqlConfigBackendImpl::selectQuery(size_t index,
+ const PsqlBindArray& in_bindings,
+ PgSqlConnection::ConsumeResultRowFun process_result_row) {
+ conn_.selectQuery(getStatement(index), in_bindings, process_result_row);
+}
+
+void
+PgSqlConfigBackendImpl::insertQuery(size_t index,
+ const PsqlBindArray& in_bindings) {
+ conn_.insertQuery(getStatement(index), in_bindings);
+}
+
+uint64_t
+PgSqlConfigBackendImpl::updateDeleteQuery(size_t index,
+ const PsqlBindArray& in_bindings) {
+ return(conn_.updateDeleteQuery(getStatement(index), in_bindings));
+}
+
+PgSqlConfigBackendImpl::ScopedAuditRevision::ScopedAuditRevision(
+ PgSqlConfigBackendImpl* impl,
+ const int index,
+ const ServerSelector& server_selector,
+ const std::string& log_message,
+ bool cascade_transaction)
+ : impl_(impl) {
+ impl_->createAuditRevision(index, server_selector,
+ boost::posix_time::microsec_clock::local_time(),
+ log_message,
+ cascade_transaction);
+}
+
+PgSqlConfigBackendImpl::ScopedAuditRevision::~ScopedAuditRevision() {
+ impl_->clearAuditRevision();
+}
+
+PgSqlConfigBackendImpl::PgSqlConfigBackendImpl(const DatabaseConnection::ParameterMap& parameters,
+ const DbCallback db_reconnect_callback,
+ size_t last_insert_id_index)
+ : conn_(parameters,
+ IOServiceAccessorPtr(new IOServiceAccessor(PgSqlConfigBackendImpl::getIOService)),
+ db_reconnect_callback), timer_name_(""),
+ audit_revision_ref_count_(0), parameters_(parameters),
+ last_insert_id_index_(last_insert_id_index) {
+
+ // Check TLS support.
+ size_t tls(0);
+ tls += parameters.count("trust-anchor");
+ tls += parameters.count("cert-file");
+ tls += parameters.count("key-file");
+ tls += parameters.count("cipher-list");
+#ifdef HAVE_PGSQL_SSL
+ if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
+ PgSqlConnection::warned_about_tls = true;
+ LOG_INFO(pgsql_cb_logger, PGSQL_CB_TLS_SUPPORT)
+ .arg(DatabaseConnection::redactedAccessString(parameters);
+ PQinitSSL(1);
+ }
+#else
+ if (tls > 0) {
+ LOG_ERROR(pgsql_cb_logger, PGSQL_CB_NO_TLS_SUPPORT)
+ .arg(DatabaseConnection::redactedAccessString(parameters));
+ isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
+ << "backend (built with this feature disabled)");
+ }
+#endif
+
+ // Test schema version first.
+ std::pair<uint32_t, uint32_t> code_version(PGSQL_SCHEMA_VERSION_MAJOR, PGSQL_SCHEMA_VERSION_MINOR);
+ std::pair<uint32_t, uint32_t> db_version = PgSqlConnection::getVersion(parameters);
+ if (code_version != db_version) {
+ isc_throw(DbOpenError, "PostgreSQL schema version mismatch: need version: "
+ << code_version.first << "." << code_version.second
+ << " found version: " << db_version.first << "."
+ << db_version.second);
+ }
+
+ // Open the database.
+ conn_.openDatabase();
+}
+
+PgSqlConfigBackendImpl::~PgSqlConfigBackendImpl() {
+ /// nothing to do there. The conn_ connection will be deleted and its dtor
+ /// will take care of releasing the compiled statements and similar.
+}
+
+void
+PgSqlConfigBackendImpl::createAuditRevision(const int index,
+ const ServerSelector& server_selector,
+ const boost::posix_time::ptime& audit_ts,
+ const std::string& log_message,
+ const bool cascade_transaction) {
+ // Do not touch existing audit revision in case of the cascade update.
+ if (++audit_revision_ref_count_ > 1) {
+ return;
+ }
+
+ /// @todo The audit trail is not really well prepared to handle multiple server
+ /// tags or no server tags. Therefore, if the server selector appears to be
+ /// pointing to multiple servers, no servers or any server we simply associate the
+ /// audit revision with all servers. The only case when we create a dedicated
+ /// audit entry is when there is a single server tag, i.e. "all" or explicit
+ /// server name. In fact, these are the most common two cases.
+ std::string tag = ServerTag::ALL;
+ auto const& tags = server_selector.getTags();
+ if (tags.size() == 1) {
+ tag = tags.begin()->get();
+ }
+
+ PsqlBindArray in_bindings;
+ in_bindings.addTimestamp(audit_ts);
+ in_bindings.add(tag);
+ in_bindings.add(log_message);
+ in_bindings.add(cascade_transaction);
+
+ insertQuery(index, in_bindings);
+}
+
+void
+PgSqlConfigBackendImpl::clearAuditRevision() {
+ if (audit_revision_ref_count_ <= 0) {
+ isc_throw(Unexpected, "attempted to clear audit revision that does not exist - coding error");
+ }
+ --audit_revision_ref_count_;
+}
+
+void
+PgSqlConfigBackendImpl::getRecentAuditEntries(const int index,
+ const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t& modification_id,
+ AuditEntryCollection& audit_entries) {
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ // Create the input parameters.
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addTimestamp(modification_time);
+ in_bindings.add(modification_id);
+
+ // Execute select.
+ selectQuery(index, in_bindings,
+ [&audit_entries] (PgSqlResult& r, int row) {
+ // Extract the column values for r[row].
+ // Create a worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get the object type. Column 0 is the entry ID which
+ // we don't need here.
+ std::string object_type = worker.getString(1);
+
+ // Get the object ID.
+ uint64_t object_id = worker.getBigInt(2);
+
+ // Get the modification type.
+ AuditEntry::ModificationType mod_type =
+ static_cast<AuditEntry::ModificationType>(worker.getSmallInt(3));
+
+ // Get the modification time.
+ boost::posix_time::ptime mod_time = worker.getTimestamp(4);
+
+ // Get the revision ID.
+ uint64_t revision_id = worker.getBigInt(5);;
+
+ // Get the revision log message.
+ std::string log_message = worker.getString(6);
+
+ // Create new audit entry and add it to the collection of received
+ // entries.
+ AuditEntryPtr audit_entry =
+ AuditEntry::create(object_type, object_id, mod_type, mod_time,
+ revision_id, log_message);
+ audit_entries.insert(audit_entry);
+ });
+ }
+}
+
+uint64_t
+PgSqlConfigBackendImpl::deleteFromTable(const int index,
+ const ServerSelector& server_selector,
+ const std::string& operation) {
+ // When deleting multiple objects we must not use ANY server.
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "deleting multiple objects for ANY server is not"
+ " supported");
+ }
+
+ PsqlBindArray in_bindings;
+ return (deleteFromTable(index, server_selector, operation, in_bindings));
+}
+
+uint64_t
+PgSqlConfigBackendImpl::deleteFromTable(const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& operation,
+ db::PsqlBindArray& in_bindings) {
+ // For ANY server, we use queries that lack server tag, otherwise
+ // we need to insert the server tag as the first input parameter.
+ if (!server_selector.amAny() && !server_selector.amUnassigned()) {
+ std::string tag = getServerTag(server_selector, operation);
+ in_bindings.insert(tag, 0);
+ }
+
+ return (updateDeleteQuery(index, in_bindings));
+}
+
+uint64_t
+PgSqlConfigBackendImpl::getLastInsertId(const std::string& table, const std::string& column) {
+ PsqlBindArray in_bindings;
+ in_bindings.add(table);
+ in_bindings.add(column);
+ uint64_t last_id = 0;
+ conn_.selectQuery(getStatement(last_insert_id_index_), in_bindings,
+ [&last_id] (PgSqlResult& r, int row) {
+ // Get the object type. Column 0 is the entry ID which
+ PgSqlExchange::getColumnValue(r, row, 0, last_id);
+ });
+
+ return (last_id);
+}
+
+void
+PgSqlConfigBackendImpl::getGlobalParameters(const int index,
+ const PsqlBindArray& in_bindings,
+ StampedValueCollection& parameters) {
+ // The following parameters from the dhcp[46]_global_parameter table are
+ // returned per row:
+ // - id
+ // - parameter name
+ // - parameter value
+ // - parameter type
+ // - modification timestamp
+
+ StampedValuePtr last_param;
+
+ StampedValueCollection local_parameters;
+
+ selectQuery(index, in_bindings,
+ [&local_parameters, &last_param](PgSqlResult& r, int row) {
+ // Extract the column values for r[row].
+ // Create a worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get parameter ID.
+ uint64_t id = worker.getBigInt(0);
+
+ // If we're starting or if this is new parameter being processed...
+ if (!last_param || (last_param->getId() != id)) {
+ // Create the parameter instance.
+
+ // Get parameter name.
+ std::string name = worker.getString(1);
+ if (!name.empty()) {
+ // Fetch the value.
+ std::string value = worker.getString(2);
+
+ // Fetch the type.
+ Element::types ptype = static_cast<Element::types>(worker.getSmallInt(3));
+
+ // Create the parameter.
+ last_param = StampedValue::create(name, value, ptype);
+
+ // Set the id.
+ last_param->setId(id);
+
+ // Get and set the modification time.
+ boost::posix_time::ptime mod_time = worker.getTimestamp(4);
+ last_param->setModificationTime(mod_time);
+
+ // server_tag
+ std::string server_tag_str = worker.getString(5);
+ last_param->setServerTag(server_tag_str);
+
+ // If we're fetching parameters for a given server (explicit server
+ // tag is provided), it takes precedence over the same parameter
+ // specified for all servers. Therefore, we check if the given
+ // parameter already exists and belongs to 'all'.
+ ServerTag last_param_server_tag(server_tag_str);
+ auto& index = local_parameters.get<StampedValueNameIndexTag>();
+ auto existing = index.find(name);
+ if (existing != index.end()) {
+ // This parameter was already fetched. Let's check if we should
+ // replace it or not.
+ if (!last_param_server_tag.amAll() && (*existing)->hasAllServerTag()) {
+ // Replace parameter specified for 'all' with the one associated
+ // with the particular server tag.
+ local_parameters.replace(existing, last_param);
+ return;
+ }
+
+ }
+
+ // If there is no such parameter yet or the existing parameter
+ // belongs to a different server and the inserted parameter is
+ // not for all servers.
+ if ((existing == index.end()) ||
+ (!(*existing)->hasServerTag(last_param_server_tag) &&
+ !last_param_server_tag.amAll())) {
+ local_parameters.insert(last_param);
+ }
+ }
+ }
+ });
+
+ parameters.insert(local_parameters.begin(), local_parameters.end());
+}
+
+OptionDefinitionPtr
+PgSqlConfigBackendImpl::getOptionDef(const int index,
+ const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "fetching option definition");
+
+ OptionDefContainer option_defs;
+ PsqlBindArray in_bindings;
+ in_bindings.add(tag);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ getOptionDefs(index, in_bindings, option_defs);
+ return (option_defs.empty() ? OptionDefinitionPtr() : *option_defs.begin());
+}
+
+void
+PgSqlConfigBackendImpl::getAllOptionDefs(const int index,
+ const ServerSelector& server_selector,
+ OptionDefContainer& option_defs) {
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ getOptionDefs(index, in_bindings, option_defs);
+ }
+}
+
+void
+PgSqlConfigBackendImpl::getModifiedOptionDefs(const int index,
+ const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ OptionDefContainer& option_defs) {
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ in_bindings.addTimestamp(modification_time);
+ getOptionDefs(index, in_bindings, option_defs);
+ }
+}
+
+void
+PgSqlConfigBackendImpl::getOptionDefs(const int index,
+ const PsqlBindArray& in_bindings,
+ OptionDefContainer& option_defs) {
+ uint64_t last_def_id = 0;
+
+ OptionDefContainer local_option_defs;
+
+ // Run select query.
+ selectQuery(index, in_bindings, [this, &local_option_defs, &last_def_id]
+ (PgSqlResult& r, int row) {
+ // Extract the column values for r[row].
+ // Create a worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get pointer to last fetched option definition.
+ OptionDefinitionPtr last_def;
+ if (!local_option_defs.empty()) {
+ last_def = *local_option_defs.rbegin();
+ }
+
+ // Get option def ID.
+ uint64_t id = worker.getBigInt(0);
+
+ // See if the last fetched definition is the one for which we now got
+ // the row of data. If not, it means that we need to create new option
+ // definition.
+ if ((last_def_id == 0) || (last_def_id != id)) {
+ last_def_id = id;
+ last_def = processOptionDefRow(worker, 0);
+
+ // server_tag
+ ServerTag last_def_server_tag(worker.getString(10));
+ last_def->setServerTag(last_def_server_tag.get());
+
+ // If we're fetching option definitions for a given server
+ // (explicit server tag is provided), it takes precedence over
+ // the same option definition specified for all servers.
+ // Therefore, we check if the given option already exists and
+ // belongs to 'all'.
+ auto& index = local_option_defs.get<1>();
+ auto existing_it_pair = index.equal_range(last_def->getCode());
+ auto existing_it = existing_it_pair.first;
+ bool found = false;
+ for ( ; existing_it != existing_it_pair.second; ++existing_it) {
+ if ((*existing_it)->getOptionSpaceName() == last_def->getOptionSpaceName()) {
+ found = true;
+ // This option definition was already fetched. Let's check
+ // if we should replace it or not.
+ if (!last_def_server_tag.amAll() && (*existing_it)->hasAllServerTag()) {
+ index.replace(existing_it, last_def);
+ return;
+ }
+ break;
+ }
+ }
+
+ // If there is no such option definition yet or the existing option
+ // definition belongs to a different server and the inserted option
+ // definition is not for all servers.
+ if (!found ||
+ (!(*existing_it)->hasServerTag(last_def_server_tag) &&
+ !last_def_server_tag.amAll())) {
+ static_cast<void>(local_option_defs.push_back(last_def));
+ }
+ }
+ });
+
+ // Append the option definition fetched by this function into the container
+ // supplied by the caller. The container supplied by the caller may already
+ // hold some option definitions fetched for other server tags.
+ option_defs.insert(option_defs.end(), local_option_defs.begin(),
+ local_option_defs.end());
+}
+
+void
+PgSqlConfigBackendImpl::createUpdateOptionDef(const db::ServerSelector& server_selector,
+ const Option::Universe& universe,
+ const OptionDefinitionPtr& option_def,
+ const std::string& /* space */,
+ const int& /*get_option_def_code_space*/,
+ const int& insert_option_def,
+ const int& update_option_def,
+ const int& create_audit_revision,
+ const int& insert_option_def_server,
+ const std::string& client_class_name) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "creating or updating option definition");
+
+ // Create input parameter bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.add(option_def->getCode());
+ in_bindings.addTempString(option_def->getName());
+ in_bindings.addTempString(option_def->getOptionSpaceName());
+ in_bindings.add(option_def->getType());
+ in_bindings.addTimestamp(option_def->getModificationTime());
+ in_bindings.add(option_def->getArrayType());
+ in_bindings.addTempString(option_def->getEncapsulatedSpace());
+
+ ElementPtr record_types = Element::createList();
+ for (auto field : option_def->getRecordFields()) {
+ record_types->add(Element::create(static_cast<int>(field)));
+ }
+
+ if (record_types->empty()) {
+ in_bindings.addNull();
+ } else {
+ in_bindings.addTempString(record_types->str());
+ }
+
+ in_bindings.add(option_def->getContext());
+
+ if (client_class_name.empty()) {
+ in_bindings.addNull();
+ } else {
+ in_bindings.add(client_class_name);
+ }
+
+ // Remember the size before we added where clause arguments.
+ size_t pre_where_size = in_bindings.size();
+
+ // Now the add the update where clause parameters
+ in_bindings.add(tag);
+ in_bindings.add(option_def->getCode());
+ in_bindings.addTempString(option_def->getOptionSpaceName());
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision audit_revision(this,
+ create_audit_revision,
+ server_selector,
+ "option definition set",
+ true);
+
+ // Try to update the definition.
+ if (updateDeleteQuery(update_option_def, in_bindings) == 0) {
+ // It doesn't exist, so we'll try to insert it.
+ // Remove the update where clause bindings.
+ while (in_bindings.size() > pre_where_size) {
+ in_bindings.popBack();
+ }
+
+ // Try to insert the definition.
+ insertQuery(insert_option_def, in_bindings);
+
+ // Successfully inserted the definition. Now, we have to associate it
+ // with the server tag.
+ PsqlBindArray attach_bindings;
+ uint64_t id = getLastInsertId((universe == Option::V4 ?
+ "dhcp4_option_def" : "dhcp6_option_def"), "id");
+ attach_bindings.add(id);
+ attach_bindings.addTimestamp(option_def->getModificationTime());
+
+ // Insert associations of the option definition with servers.
+ attachElementToServers(insert_option_def_server, server_selector, attach_bindings);
+ }
+
+ // Commit the work.
+ transaction.commit();
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendImpl::getOption(const int index,
+ const Option::Universe& universe,
+ const ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "fetching global option");
+
+ OptionContainer options;
+ PsqlBindArray in_bindings;
+ in_bindings.add(tag);
+ in_bindings.add(code);
+ in_bindings.add(space);
+
+ getOptions(index, in_bindings, universe, options);
+ return (options.empty() ? OptionDescriptorPtr() :
+ OptionDescriptor::create(*options.begin()));
+}
+
+OptionContainer
+PgSqlConfigBackendImpl::getAllOptions(const int index,
+ const Option::Universe& universe,
+ const ServerSelector& server_selector) {
+ OptionContainer options;
+
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(tag.get());
+ getOptions(index, in_bindings, universe, options);
+ }
+
+ return (options);
+}
+
+OptionContainer
+PgSqlConfigBackendImpl::getModifiedOptions(const int index,
+ const Option::Universe& universe,
+ const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) {
+ OptionContainer options;
+
+ PsqlBindArray in_bindings;
+ auto const& tags = server_selector.getTags();
+ for (auto const& tag : tags) {
+ in_bindings.addTempString(tag.get());
+ in_bindings.addTimestamp(modification_time);
+ getOptions(index, in_bindings, universe, options);
+ }
+
+ return (options);
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendImpl::getOption(const int index,
+ const Option::Universe& universe,
+ const ServerSelector& server_selector,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "fetching subnet level option");
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(tag);
+ in_bindings.add(subnet_id);
+ in_bindings.add(code); // Postgresql code is same size regardless of universe
+ in_bindings.add(space);
+
+ OptionContainer options;
+ getOptions(index, in_bindings, universe, options);
+ return (options.empty() ? OptionDescriptorPtr() :
+ OptionDescriptor::create(*options.begin()));
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendImpl::getOption(const int index,
+ const ServerSelector& server_selector,
+ const Lease::Type& pool_type,
+ const uint64_t pool_id,
+ const uint16_t code,
+ const std::string& space) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ std::string msg = "fetching ";
+ if (pool_type == Lease::TYPE_PD) {
+ msg += "prefix delegation";
+ } else {
+ msg += "address";
+ }
+ msg += " pool level option";
+ auto tag = getServerTag(server_selector, msg);
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(tag);
+ in_bindings.add(pool_id);
+ in_bindings.add(code); // Postgresql code is same size regardless of universe
+ in_bindings.add(space);
+ Option::Universe universe = Option::V4;
+ OptionContainer options;
+ if (pool_type != Lease::TYPE_V4) {
+ universe = Option::V6;
+ }
+ getOptions(index, in_bindings, universe, options);
+ return (options.empty() ? OptionDescriptorPtr() :
+ OptionDescriptor::create(*options.begin()));
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendImpl::getOption(const int index,
+ const Option::Universe& universe,
+ const ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ auto tag = getServerTag(server_selector, "fetching shared network level option");
+
+ PsqlBindArray in_bindings;
+ in_bindings.add(tag);
+ in_bindings.add(shared_network_name);
+ in_bindings.add(code); // Postgresql code is same size regardless of universe
+ in_bindings.add(space);
+
+ OptionContainer options;
+ getOptions(index, in_bindings, universe, options);
+ return (options.empty() ? OptionDescriptorPtr() :
+ OptionDescriptor::create(*options.begin()));
+}
+
+void
+PgSqlConfigBackendImpl::getOptions(const int index,
+ const db::PsqlBindArray& in_bindings,
+ const Option::Universe& universe,
+ OptionContainer& options) {
+ uint64_t last_option_id = 0;
+ OptionContainer local_options;
+ selectQuery(index, in_bindings, [this, universe, &local_options, &last_option_id]
+ (PgSqlResult& r, int row) {
+ // Extract the column values for r[row].
+ // Create a worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get option ID.
+ uint64_t id = worker.getBigInt(0);
+
+ // Parse option.
+ if ((last_option_id == 0) || (last_option_id < id)) {
+ last_option_id = id;
+
+ OptionDescriptorPtr desc = processOptionRow(universe, worker, 0);
+ if (desc) {
+ // server_tag for the global option
+ ServerTag last_option_server_tag(worker.getString(13));
+ desc->setServerTag(last_option_server_tag.get());
+
+ // If we're fetching options for a given server (explicit server
+ // tag is provided), it takes precedence over the same option
+ // specified for all servers. Therefore, we check if the given
+ // option already exists and belongs to 'all'.
+ auto& index = local_options.get<1>();
+ auto existing_it_pair = index.equal_range(desc->option_->getType());
+ auto existing_it = existing_it_pair.first;
+ bool found = false;
+ for ( ; existing_it != existing_it_pair.second; ++existing_it) {
+ if (existing_it->space_name_ == desc->space_name_) {
+ found = true;
+ // This option was already fetched. Let's check if we should
+ // replace it or not.
+ if (!last_option_server_tag.amAll() && existing_it->hasAllServerTag()) {
+ index.replace(existing_it, *desc);
+ return;
+ }
+ break;
+ }
+ }
+
+ // If there is no such global option yet or the existing option
+ // belongs to a different server and the inserted option is not
+ // for all servers.
+ if (!found ||
+ (!existing_it->hasServerTag(last_option_server_tag) &&
+ !last_option_server_tag.amAll())) {
+ static_cast<void>(local_options.push_back(*desc));
+ }
+ }
+ }
+ });
+
+ // Append the options fetched by this function into the container supplied
+ // by the caller. The container supplied by the caller may already hold
+ // some options fetched for other server tags.
+ options.insert(options.end(), local_options.begin(), local_options.end());
+}
+
+OptionDescriptorPtr
+PgSqlConfigBackendImpl::processOptionRow(const Option::Universe& universe,
+ PgSqlResultRowWorker& worker,
+ size_t first_col) {
+ // Some of the options have standard or custom definitions.
+ // Depending whether the option has a definition or not a different
+ // C++ class may be used to represent the option. Therefore, the
+ // first thing to do is to see if there is a definition for our
+ // parsed option. The option code and space is needed for it.
+ std::string space = worker.getString(first_col + 4);
+ uint16_t code = worker.getSmallInt(first_col + 1);
+
+ OptionPtr option = Option::create(universe, code);
+
+ // Get formatted value if available.
+ std::string formatted_value;
+ if (!worker.isColumnNull(first_col + 3)) {
+ formatted_value = worker.getString(first_col + 3);
+ }
+
+ // If we don't have a formatted value, check for a blob. Add it to the
+ // option if it exists.
+ if (formatted_value.empty() && !worker.isColumnNull(first_col + 2)) {
+ std::vector<uint8_t> blob;
+ worker.getBytes(first_col + 2, blob);
+ option->setData(blob.begin(), blob.end());
+ }
+
+ // Check if the option is persistent.
+ bool persistent = false;
+ if (!worker.isColumnNull(first_col + 5)) {
+ persistent = worker.getBool(first_col + 5);
+ }
+
+ // Check if the option is cancelled.
+ bool cancelled = false;
+ if (!worker.isColumnNull(first_col + 6)) {
+ cancelled = worker.getBool(first_col + 6);
+ }
+
+ // Create option descriptor which encapsulates our option and adds
+ // additional information, i.e. whether the option is persistent,
+ // its option space and timestamp.
+ OptionDescriptorPtr desc = OptionDescriptor::create(option,
+ persistent,
+ cancelled,
+ formatted_value);
+ desc->space_name_ = space;
+ desc->setModificationTime(worker.getTimestamp(first_col + 12));
+
+ // Set database id for the option.
+ // @todo Can this actually ever be null and if it is, isn't that an error?
+ if (!worker.isColumnNull(first_col)) {
+ desc->setId(worker.getBigInt(first_col));
+ }
+
+ return (desc);
+}
+
+OptionDefinitionPtr
+PgSqlConfigBackendImpl::processOptionDefRow(PgSqlResultRowWorker& worker,
+ const size_t first_col) {
+ OptionDefinitionPtr def;
+
+ // Check array type, because depending on this value we have to use
+ // different constructor.
+ std::string name = worker.getString(first_col + 2);
+ uint16_t code = worker.getSmallInt(first_col + 1);
+ std::string space = worker.getString(first_col + 3);
+ OptionDataType type = static_cast<OptionDataType>(worker.getSmallInt(first_col + 4));
+
+ bool array_type = worker.getBool(first_col + 6);
+ if (array_type) {
+ // Create array option.
+ def = OptionDefinition::create(name, code, space, type, true);
+ } else {
+ // Create non-array option.
+ def = OptionDefinition::create(name, code, space, type,
+ (worker.isColumnNull(first_col + 7) ? ""
+ : worker.getString(first_col + 7).c_str()));
+ }
+
+ // id
+ def->setId(worker.getBigInt(first_col));
+
+ // record_types
+ if (!worker.isColumnNull(first_col + 8)) {
+ ElementPtr record_types_element = worker.getJSON(first_col + 8);
+ if (record_types_element->getType() != Element::list) {
+ isc_throw(BadValue, "invalid record_types value "
+ << worker.getString(first_col + 8));
+ }
+
+ // This element must contain a list of integers specifying
+ // types of the record fields.
+ for (auto i = 0; i < record_types_element->size(); ++i) {
+ auto type_element = record_types_element->get(i);
+ if (type_element->getType() != Element::integer) {
+ isc_throw(BadValue, "record type values must be integers");
+ }
+
+ def->addRecordField(static_cast<OptionDataType>(type_element->intValue()));
+ }
+ }
+
+ // Update modification time.
+ def->setModificationTime(worker.getTimestamp(first_col + 5));
+
+ return (def);
+}
+
+void
+PgSqlConfigBackendImpl::attachElementToServers(const int index,
+ const ServerSelector& server_selector,
+ const PsqlBindArray& in_bindings) {
+ // Copy the bindings because we're going to modify them.
+ PsqlBindArray server_bindings = in_bindings;
+ for (auto const& tag : server_selector.getTags()) {
+ // Add the server tag to end of the bindings.
+ std::string server_tag = tag.get();
+ server_bindings.add(server_tag);
+
+ // Insert the server association.
+ // Handles the case where the server does not exists.
+ try {
+ insertQuery(index, server_bindings);
+ } catch (const NullKeyError&) {
+ // The message should give the tag value.
+ isc_throw(NullKeyError,
+ "server '" << tag.get() << "' does not exist");
+ }
+ // Remove the prior server tag.
+ server_bindings.popBack();
+ }
+}
+
+ServerPtr
+PgSqlConfigBackendImpl::getServer(const int index, const ServerTag& server_tag) {
+ ServerCollection servers;
+
+ // Create input parameter bindings.
+ PsqlBindArray in_bindings;
+ in_bindings.addTempString(server_tag.get());
+
+ getServers(index, in_bindings, servers);
+
+ return (servers.empty() ? ServerPtr() : *servers.begin());
+}
+
+void
+PgSqlConfigBackendImpl::getAllServers(const int index, db::ServerCollection& servers) {
+ PsqlBindArray in_bindings;
+ getServers(index, in_bindings, servers);
+}
+
+void
+PgSqlConfigBackendImpl::getServers(const int index,
+ const PsqlBindArray& in_bindings,
+ ServerCollection& servers) {
+ // Track the last server added to avoid duplicates. This
+ // assumes the rows are ordered by server ID.
+ ServerPtr last_server;
+ selectQuery(index, in_bindings,
+ [&servers, &last_server](PgSqlResult& r, int row) {
+ // Extract the column values for r[row].
+ // Create a worker for the row.
+ PgSqlResultRowWorker worker(r, row);
+
+ // Get the server ID.
+ uint64_t id = worker.getBigInt(0);
+
+ // Get the server tag.
+ std::string tag = worker.getString(1);
+
+ // Get the description.
+ std::string description = worker.getString(2);
+
+ // Get the modification time.
+ boost::posix_time::ptime mod_time = worker.getTimestamp(3);
+
+ if (!last_server || (last_server->getId() != id)) {
+ // Create the server instance.
+ last_server = Server::create(ServerTag(tag), description);
+
+ // id
+ last_server->setId(id);
+
+ // modification_ts
+ last_server->setModificationTime(mod_time);
+
+ // New server fetched. Let's store it.
+ servers.insert(last_server);
+ }
+ });
+}
+
+void
+PgSqlConfigBackendImpl::createUpdateServer(const int& create_audit_revision,
+ const int& create_index,
+ const int& update_index,
+ const ServerPtr& server) {
+ // The server tag 'all' is reserved.
+ if (server->getServerTag().amAll()) {
+ isc_throw(InvalidOperation,
+ "'all' is a name reserved for the server tag which"
+ " associates the configuration elements with all servers connecting"
+ " to the database and a server with this name may not be created");
+ }
+
+ // Populate the input bindings.
+ PsqlBindArray in_bindings;
+ std::string tag = server->getServerTagAsText();
+ in_bindings.add(tag);
+ in_bindings.addTempString(server->getDescription());
+ in_bindings.addTimestamp(server->getModificationTime());
+
+ // Start transaction.
+ PgSqlTransaction transaction(conn_);
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision audit_revision(this, create_audit_revision, ServerSelector::ALL(),
+ "server set", true);
+
+ // Create a savepoint in case we are called as part of larger
+ // transaction.
+ conn_.createSavepoint("createUpdateServer");
+
+ try {
+ // Attempt to insert the server.
+ insertQuery(create_index, in_bindings);
+ } catch (const DuplicateEntry&) {
+ // Rollback to the savepoint to preserve an outer
+ // transaction work.
+ conn_.rollbackToSavepoint("createUpdateServer");
+
+ // Add another instance of tag to the bindings to be used
+ // as the where clause parameter. PostgreSQL uses
+ // numbered placeholders so we could use $1 again, but
+ // doing it this way leaves the SQL more generic.
+ in_bindings.add(tag);
+
+ // Attempt to update the server.
+ if (!updateDeleteQuery(update_index, in_bindings)) {
+ // Possible only if someone deleted it since we tried to insert it,
+ // the query is broken, or the bindings are nonsense.
+ isc_throw(Unexpected, "Update server failed to find server tag: " << tag);
+ }
+ }
+
+ // Commit the transaction.
+ transaction.commit();
+}
+
+std::string
+PgSqlConfigBackendImpl::getType() const {
+ return ("postgresql");
+}
+
+std::string
+PgSqlConfigBackendImpl::getHost() const {
+ std::string host = "localhost";
+ try {
+ host = conn_.getParameter("host");
+ } catch (...) {
+ // No host parameter. Return localhost as a default.
+ }
+ return (host);
+}
+
+uint16_t
+PgSqlConfigBackendImpl::getPort() const {
+ try {
+ std::string sport = conn_.getParameter("port");
+ return (boost::lexical_cast<uint16_t>(sport));
+
+ } catch (...) {
+ // No port parameter or parameter invalid.
+ }
+ return (0);
+}
+
+void
+PgSqlConfigBackendImpl::addDdnsReplaceClientNameBinding(PsqlBindArray& bindings,
+ const NetworkPtr& network) {
+ auto ddns_rcn_mode = network->getDdnsReplaceClientNameMode(Network::Inheritance::NONE);
+ if (!ddns_rcn_mode.unspecified()) {
+ bindings.add(static_cast<uint8_t>(ddns_rcn_mode.get()));
+ } else {
+ bindings.addNull();
+ }
+}
+
+void
+PgSqlConfigBackendImpl::addRelayBinding(PsqlBindArray& bindings,
+ const NetworkPtr& network) {
+ ElementPtr relay_element = Element::createList();
+ const auto& addresses = network->getRelayAddresses();
+ if (!addresses.empty()) {
+ for (const auto& address : addresses) {
+ relay_element->add(Element::create(address.toText()));
+ }
+ }
+
+ bindings.add(relay_element);
+}
+
+void
+PgSqlConfigBackendImpl::setRelays(PgSqlResultRowWorker& worker, size_t col, Network& network) {
+ if (worker.isColumnNull(col)) {
+ return;
+ }
+
+ ElementPtr relay_element = worker.getJSON(col);
+ if (relay_element->getType() != Element::list) {
+ isc_throw(BadValue, "invalid relay list: " << worker.getString(col));
+ }
+
+ for (auto i = 0; i < relay_element->size(); ++i) {
+ auto relay_address_element = relay_element->get(i);
+ if (relay_address_element->getType() != Element::string) {
+ isc_throw(BadValue, "elements of relay_addresses list must"
+ "be valid strings");
+ }
+
+ network.addRelayAddress(IOAddress(relay_address_element->stringValue()));
+ }
+}
+
+void
+PgSqlConfigBackendImpl::setRequiredClasses(PgSqlResultRowWorker& worker, size_t col,
+ std::function<void(const std::string&)> setter) {
+ if (worker.isColumnNull(col)) {
+ return;
+ }
+
+ ElementPtr require_element = worker.getJSON(col);
+ if (require_element->getType() != Element::list) {
+ std::ostringstream ss;
+ require_element->toJSON(ss);
+ isc_throw(BadValue, "invalid require_client_classes value " << ss.str());
+ }
+
+ for (auto i = 0; i < require_element->size(); ++i) {
+ auto require_item = require_element->get(i);
+ if (require_item->getType() != Element::string) {
+ isc_throw(BadValue, "elements of require_client_classes list must"
+ "be valid strings");
+ }
+
+ setter(require_item->stringValue());
+ }
+}
+
+void
+PgSqlConfigBackendImpl::addOptionValueBinding(PsqlBindArray& bindings,
+ const OptionDescriptorPtr& option) {
+ OptionPtr opt = option->option_;
+ if (option->formatted_value_.empty() && (opt->len() > opt->getHeaderLen())) {
+ OutputBuffer buf(opt->len());
+ opt->pack(buf);
+ const char* buf_ptr = static_cast<const char*>(buf.getData());
+ std::vector<uint8_t> blob(buf_ptr + opt->getHeaderLen(),
+ buf_ptr + buf.getLength());
+ bindings.addTempBinary(blob);
+ } else {
+ bindings.addNull();
+ }
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h
new file mode 100644
index 0000000..68df199
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h
@@ -0,0 +1,902 @@
+// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PGSQL_CONFIG_BACKEND_IMPL_H
+#define PGSQL_CONFIG_BACKEND_IMPL_H
+
+#include <cc/stamped_value.h>
+#include <database/audit_entry.h>
+#include <database/database_connection.h>
+#include <database/server.h>
+#include <database/server_collection.h>
+#include <database/server_selector.h>
+#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
+#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/lease.h>
+#include <dhcpsrv/network.h>
+#include <dhcpsrv/subnet_id.h>
+#include <exceptions/exceptions.h>
+#include <pgsql/pgsql_connection.h>
+#include <pgsql/pgsql_exchange.h>
+
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Base class for PostgreSQL Config Backend implementations.
+///
+/// This class contains common methods for manipulating data in the
+/// PostgreSQL database, used by all servers.
+///
+/// All POSIX times specified in the methods belonging to this
+/// class must be local times.
+class PgSqlConfigBackendImpl {
+protected:
+
+ /// @brief RAII object used to protect against creating multiple
+ /// audit revisions during cascade configuration updates.
+ ///
+ /// Audit revision is created per a single database transaction.
+ /// It includes log message associated with the configuration
+ /// change. Single command sent over the control API should
+ /// result in a single audit revision entry in the database.
+ /// A single configuration update often consists of multiple
+ /// insertions, updates and/or deletes in the database. For
+ /// example, a subnet contains pools and DHCP options which are
+ /// inserted to their respective tables. We refer to such update
+ /// as a cascade update. Cascade update should result in a single
+ /// audit revision and an audit entry for a subnet, rather than
+ /// multiple audit revisions and audit entries for the subnet,
+ /// pools and child DHCP options.
+ ///
+ /// Creating an instance of the @c ScopedAuditRevision guards
+ /// against creation of multiple audit revisions when child
+ /// objects are inserted or updated in the database. When the
+ /// instance of this object goes out of scope the new audit
+ /// revisions can be created. The caller must ensure that
+ /// the instance of this object exists throughout the whole
+ /// transaction with the database.
+ class ScopedAuditRevision {
+ public:
+
+ /// @brief Constructor.
+ ///
+ /// Creates new audit revision and sets the flag in the
+ /// PostgreSQL CB implementation object which prevents new audit
+ /// revisions to be created while this instance exists.
+ ///
+ /// @param impl pointer to the PostgreSQL CB implementation.
+ /// @param index index of the query to set session variables
+ /// used for creation of the audit revision and the audit
+ /// entries.
+ /// @param server_selector Server selector.
+ /// @param log_message log message associated with the audit
+ /// revision to be inserted into the database.
+ /// @param cascade_transaction boolean flag indicating if
+ /// we're performing cascade transaction. If set to true,
+ /// the audit entries for the child objects (e.g. DHCP
+ /// options) won't be created.
+ ScopedAuditRevision(PgSqlConfigBackendImpl* impl,
+ const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& log_message,
+ bool cascade_transaction);
+
+ /// @brief Destructor.
+ ///
+ /// Clears the flag which is blocking creation of the new
+ /// audit revisions.
+ ~ScopedAuditRevision();
+
+ private:
+
+ /// @brief Pointer to the PostgreSQL CB implementation.
+ PgSqlConfigBackendImpl* impl_;
+ };
+
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ /// @param db_reconnect_callback The connection recovery callback.
+ /// @param last_insert_id_index statement index of the SQL statement to
+ /// use when fetching the last insert id for a given table.
+ explicit PgSqlConfigBackendImpl(const db::DatabaseConnection::ParameterMap& parameters,
+ const db::DbCallback db_reconnect_callback,
+ const size_t last_insert_id_index);
+
+ /// @brief Destructor.
+ virtual ~PgSqlConfigBackendImpl();
+
+ /// @brief Returns server tag associated with the particular selector.
+ ///
+ /// This method expects that there is exactly one server tag associated with
+ /// the server selector.
+ ///
+ /// @param server_selector Server selector.
+ /// @param operation Operation which results in calling this function. This is
+ /// used for error reporting purposes.
+ /// @return Server tag.
+ /// @throw InvalidOperation if the server selector is unassigned or if there
+ /// is more than one server tag associated with the selector.
+ std::string getServerTag(const db::ServerSelector& server_selector,
+ const std::string& operation) const {
+ auto const& tags = server_selector.getTags();
+ if (tags.size() != 1) {
+ isc_throw(InvalidOperation, "expected exactly one server tag to be specified"
+ " while " << operation << ". Got: "
+ << getServerTagsAsText(server_selector));
+ }
+
+ return (tags.begin()->get());
+ }
+
+ /// @brief Returns server tags associated with the particular selector
+ /// as text.
+ ///
+ /// This method is useful for logging purposes.
+ std::string getServerTagsAsText(const db::ServerSelector& server_selector) const {
+ std::ostringstream s;
+ auto const& server_tags = server_selector.getTags();
+ for (auto const& tag : server_tags) {
+ if (s.tellp() != 0) {
+ s << ", ";
+ }
+ s << tag.get();
+ }
+
+ return (s.str());
+ }
+
+ /// @brief Invokes the corresponding stored procedure in PgSQL.
+ ///
+ /// The @c createAuditRevision stored procedure creates new audit
+ /// revision and initializes several session variables to be used when
+ /// the audit entries will be created for the inserted, updated or
+ /// deleted configuration elements.
+ ///
+ /// @param index query index.
+ /// @param server_selector Server selector.
+ /// @param audit_ts Timestamp to be associated with the audit
+ /// revision.
+ /// @param log_message log message to be used for the audit revision.
+ /// @param cascade_transaction Boolean value indicating whether the
+ /// configuration modification is performed as part of the owning
+ /// element modification, e.g. subnet is modified resulting in
+ /// modification of the DHCP options it owns. In that case only the
+ /// audit entry for the owning element should be created.
+ void createAuditRevision(const int index,
+ const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& audit_ts,
+ const std::string& log_message,
+ const bool cascade_transaction);
+
+ /// @brief Clears the flag blocking creation of the new audit revisions.
+ ///
+ /// This is used by the @c ScopedAuditRevision object.
+ void clearAuditRevision();
+
+ /// @brief Sends query to the database to retrieve most recent audit entries.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param modification_time Timestamp being a lower limit for the returned
+ /// result set, i.e. entries later than specified time are returned.
+ /// @param modification_id Identifier being a lower limit for the returned
+ /// result set, used when two (or more) revisions have the same
+ /// modification_time.
+ /// @param [out] audit_entries Reference to the container where fetched audit
+ /// entries will be inserted.
+ void getRecentAuditEntries(const int index,
+ const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t& modification_id,
+ db::AuditEntryCollection& audit_entries);
+
+ /// @brief Sends query to delete rows from a table.
+ ///
+ /// @param index Index of the statement to be executed.
+ /// @param server_selector Server selector.
+ /// @param operation Operation which results in calling this function. This is
+ /// used for error reporting purposes.
+ /// @return Number of deleted rows.
+ uint64_t deleteFromTable(const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& operation);
+
+ /// @brief Sends query to delete rows from a table.
+ ///
+ /// @param index Index of the statement to be executed.
+ /// @param server_selector Server selector.
+ /// @param operation Operation which results in calling this function. This is
+ /// used for logging purposes.
+ /// @param in_bindings Reference to the PgSQL input bindings. They are modified
+ /// as a result of this function - server tag is inserted into the beginning
+ /// of the bindings collection.
+ /// @return Number of deleted rows.
+ uint64_t deleteFromTable(const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& operation,
+ db::PsqlBindArray& bindings);
+
+ /// @brief Sends query to delete rows from a table.
+ ///
+ /// @tparam KeyType Type of the key used as the second binding. The
+ /// server tag is used as first binding.
+ ///
+ /// @param index Index of the statement to be executed.
+ /// @param server_selector Server selector.
+ /// @param operation Operation which results in calling this function. This is
+ /// used for error reporting purposes.
+ /// @param key Value to be used as input binding to the delete
+ /// statement. The default value is empty which indicates that the
+ /// key should not be used in the query.
+ /// @return Number of deleted rows.
+ /// @throw InvalidOperation if the server selector is unassigned or
+ /// if there are more than one server tags associated with the
+ /// server selector.
+ template<typename KeyType>
+ uint64_t deleteFromTable(const int index,
+ const db::ServerSelector& server_selector,
+ const std::string& operation,
+ KeyType key) {
+ // When deleting by some key, we must use ANY.
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "deleting an unassigned object requires "
+ "an explicit server tag or using ANY server. The UNASSIGNED "
+ "server selector is currently not supported");
+ }
+
+ db::PsqlBindArray in_bindings;
+ in_bindings.add(key);
+ return (deleteFromTable(index, server_selector, operation, in_bindings));
+ }
+
+ /// @brief Returns the last sequence value for the given table and
+ /// column name.
+ ///
+ /// This relies on PostgreSQL's currval() function which will return
+ /// the last value generated for the sequence within the current session.
+ ///
+ /// @param table name of the table
+ /// @param column name of the sequence column
+ /// @return returns the most recently modified value for the given
+ /// sequence
+ uint64_t getLastInsertId(const std::string& table, const std::string& column);
+
+ /// @brief Sends query to retrieve multiple global parameters.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] parameters Reference to the container where fetched parameters
+ /// will be inserted.
+ void getGlobalParameters(const int index,
+ const db::PsqlBindArray& in_bindings,
+ data::StampedValueCollection& parameters);
+
+ /// @brief Sends query to retrieve single option definition by code and
+ /// option space.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option definition or NULL if such
+ /// option definition doesn't exist.
+ OptionDefinitionPtr getOptionDef(const int index,
+ const db::ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Sends query to retrieve all option definitions.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param [out] option_defs Reference to the container where option
+ /// definitions are to be stored.
+ void getAllOptionDefs(const int index,
+ const db::ServerSelector& server_selector,
+ OptionDefContainer& option_defs);
+
+ /// @brief Sends query to retrieve option definitions with modification
+ /// time later than specified timestamp.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param modification_time Lower bound subnet modification time.
+ /// @param [out] option_defs Reference to the container where option
+ /// definitions are to be stored.
+ void getModifiedOptionDefs(const int index,
+ const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ OptionDefContainer& option_defs);
+
+ /// @brief Sends query to the database to retrieve multiple option
+ /// definitions.
+ ///
+ /// Query should order option definitions by id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] option_defs Reference to the container where fetched
+ /// option definitions will be inserted.
+ void getOptionDefs(const int index,
+ const db::PsqlBindArray& in_bindings,
+ OptionDefContainer& option_defs);
+
+ /// @brief Creates or updates an option definition.
+ ///
+ /// @param server_selector Server selector.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param option_def Option definition to be added or updated.
+ /// @param space Default option space
+ /// @param get_option_def_code_space Statement getting option
+ /// definition by code and space.
+ /// @param insert_option_def Statement inserting option definition.
+ /// @param update_option_def Statement updating option definition.
+ /// @param create_audit_revision Statement creating audit revision.
+ /// @param insert_option_def_server Statement associating option
+ /// definition with a server.
+ /// @param client_class_name Optional client class name to which
+ /// the option definition belongs. If this value is not specified,
+ /// it is a global option definition.
+ /// @throw NotImplemented if server selector is "unassigned".
+ void createUpdateOptionDef(const db::ServerSelector& server_selector,
+ const Option::Universe& universe,
+ const OptionDefinitionPtr& option_def,
+ const std::string& space,
+ const int& get_option_def_code_space,
+ const int& insert_option_def,
+ const int& update_option_def,
+ const int& create_audit_revision,
+ const int& insert_option_def_server,
+ const std::string& client_class_name = "");
+
+ /// @brief Sends query to retrieve single global option by code and
+ /// option space.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param server_selector Server selector.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option or NULL if such option
+ /// doesn't exist.
+ OptionDescriptorPtr getOption(const int index,
+ const Option::Universe& universe,
+ const db::ServerSelector& server_selector,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Sends query to retrieve all global options.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param server_selector Server selector.
+ /// @return Container holding returned options.
+ OptionContainer getAllOptions(const int index,
+ const Option::Universe& universe,
+ const db::ServerSelector& server_selector);
+
+ /// @brief Sends query to retrieve global options with modification
+ /// time later than specified timestamp.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param server_selector Server selector.
+ /// @return Container holding returned options.
+ OptionContainer getModifiedOptions(const int index,
+ const Option::Universe& universe,
+ const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time);
+
+ /// @brief Sends query to retrieve single option by code and option space
+ /// for a given subnet id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param server_selector Server selector.
+ /// @param subnet_id Subnet identifier.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option descriptor or NULL if such
+ /// option doesn't exist.
+ OptionDescriptorPtr getOption(const int index,
+ const Option::Universe& universe,
+ const db::ServerSelector& server_selector,
+ const dhcp::SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Sends query to retrieve single option by code and option space
+ /// for a given address or prefix delegation (v6) pool id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param pool_type Pool type (Lease::TYPE_V4, TYPE_NA or TYPE_PD).
+ /// @param pool_id Pool identifier in the database.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option descriptor or NULL if such
+ /// option doesn't exist.
+ OptionDescriptorPtr getOption(const int index,
+ const db::ServerSelector& server_selector,
+ const dhcp::Lease::Type& pool_type,
+ const uint64_t pool_id,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Sends query to retrieve single option by code and option space
+ /// for a given shared network.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Shared network name.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option descriptor or NULL if such
+ /// option doesn't exist.
+ OptionDescriptorPtr getOption(const int index,
+ const Option::Universe& universe,
+ const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space);
+
+ /// @brief Sends query to the database to retrieve multiple options.
+ ///
+ /// Query should order by option_id.
+ ///
+ /// @note The universe is reused to switch between DHCPv4 and DHCPv6
+ /// option layouts.
+ /// @param family Address family (either AF_INET or AF_INET6).
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param [out] options Reference to the container where fetched options
+ /// will be inserted.
+ void getOptions(const int index,
+ const db::PsqlBindArray& in_bindings,
+ const Option::Universe& universe,
+ OptionContainer& options);
+
+ /// @brief Returns DHCP option instance from a set of columns within a
+ /// result set row.
+ ///
+ /// The following is the expected order of columns specified in the SELECT
+ /// query:
+ /// - option_id,
+ /// - code,
+ /// - value,
+ /// - formatted_value,
+ /// - space,
+ /// - persistent,
+ /// - cancelled,
+ /// - dhcp4_subnet_id/dhcp6_subnet_id,
+ /// - scope_id,
+ /// - user_context,
+ /// - shared_network_name,
+ /// - pool_id,
+ /// - [pd_pool_id,]
+ /// - modification_ts
+ ///
+ /// @note The universe is reused to switch between DHCPv4 and DHCPv6
+ /// option layouts.
+ /// @param universe V4 or V6.
+ /// @param worker result set row worker containing the row data
+ /// @param first_col column index of the first column (i.e. option_id)
+ /// in the row.
+ OptionDescriptorPtr processOptionRow(const Option::Universe& universe,
+ db::PgSqlResultRowWorker& worker,
+ const size_t first_col);
+
+ /// @brief Returns DHCP option definition instance from output bindings.
+ ///
+ /// The following is the expected order of columns specified in the SELECT
+ /// query:
+ /// - id,
+ /// - code,
+ /// - name,
+ /// - space,
+ /// - type,
+ /// - modification_ts,
+ /// - is_array,
+ /// - encapsulate,
+ /// - record_types,
+ /// - user_context
+ ///
+ /// @param worker result set row worker containing the row data
+ /// @param first_col column index of the first column (i.e. definition id)
+ /// in the row.
+ /// @return Pointer to the option definition.
+ OptionDefinitionPtr processOptionDefRow(db::PgSqlResultRowWorker& worker,
+ const size_t first_col);
+
+ /// @brief Associates a configuration element with multiple servers.
+ ///
+ /// @param index Query index.
+ /// @param server_selector Server selector, perhaps with multiple server tags.
+ /// @param in_bindings Parameter pack holding bindings for the query. The first
+ /// entry must be the primary key of the element to attach. Note that
+ /// the server tag (or server id) must be the last binding in the prepared
+ /// statement. The caller must not include this binding in the parameter pack.
+ void attachElementToServers(const int index,
+ const db::ServerSelector& server_selector,
+ const db::PsqlBindArray& in_bindings);
+
+ /// @brief Adds network ddns-replace-client-name mode to a bind array.
+ ///
+ /// If network's value of ddns-replace-client-name mode has been specified
+ /// it is added to the binding, otherwise a null is added to the binding.
+ ///
+ /// @param bindings PsqlBindArray to which the mode should be added.
+ /// @param network Pointer to shared network or subnet for which mode binding
+ /// should be created.
+ void addDdnsReplaceClientNameBinding(db::PsqlBindArray& bindings,
+ const NetworkPtr& network);
+
+ /// @brief Adds network relays addresses to a bind array.
+ ///
+ /// Creates an Element tree of relay addresses add adds that to the end
+ /// of the given bind array.
+ ///
+ /// @param bindings PsqlBindArray to which the relay addresses should be added.
+ /// @param network Pointer to a shared network or subnet for which binding
+ /// should be created.
+ void addRelayBinding(db::PsqlBindArray& bindings, const NetworkPtr& network);
+
+ /// @brief Iterates over the relay addresses in a JSON list element at a
+ /// given column, adding each to the given Network's relay list.
+ ///
+ /// Has no effect if the column is null or is an empty list.
+ ///
+ /// @param worker result set row worker containing the row data
+ /// @param col column index of JSON element column
+ /// @param network network to update.
+ ///
+ /// @throw BadValue if the Element is not a list or if any of the
+ /// list's elements are not valid IP addresses in string form.
+ void setRelays(db::PgSqlResultRowWorker& r, size_t col, Network& network);
+
+ /// @brief Adds 'require_client_classes' parameter to a bind array.
+ ///
+ /// Creates an Element tree of required class names and adds that to the end
+ /// of the given bind array.
+ ///
+ /// @tparam T of pointer to objects with getRequiredClasses
+ /// method, e.g. shared network, subnet, pool or prefix delegation pool.
+ /// @param bindings PsqlBindArray to which the classes should be added.
+ /// @param object Pointer to an object with getRequiredClasses method
+ /// @return Pointer to the binding (possibly null binding if there are no
+ /// required classes specified).
+ template<typename T>
+ void addRequiredClassesBinding(db::PsqlBindArray& bindings, const T& object) {
+ // Create JSON list of required classes.
+ data::ElementPtr required_classes_element = data::Element::createList();
+ const auto& required_classes = object->getRequiredClasses();
+ for (auto required_class = required_classes.cbegin();
+ required_class != required_classes.cend();
+ ++required_class) {
+ required_classes_element->add(data::Element::create(*required_class));
+ }
+
+ bindings.add(required_classes_element);
+ }
+
+ /// @brief Iterates over the class names in a JSON list element at a
+ /// given column, invoking a setter function for each one.
+ ///
+ /// Has no effect if the column is null or is an empty list.
+ ///
+ /// @param worker result set row worker containing the row data
+ /// @param col column index of JSON element column
+ /// @param setter function to invoke for each class name in the list
+ ///
+ /// @throw BadValue if the Element is not a list or if any of the
+ /// list's elements are not strings.
+ void setRequiredClasses(db::PgSqlResultRowWorker& worker, size_t col,
+ std::function<void(const std::string&)> setter);
+
+ /// @brief Adds an option value to a bind array.
+ ///
+ /// @param bindings PsqlBindArray to which the option value should be added.
+ /// @param option Option descriptor holding the option who's value should
+ /// added.
+ void addOptionValueBinding(db::PsqlBindArray& bindings,
+ const OptionDescriptorPtr& option);
+
+ /// @brief Retrieves a server.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_tag Server tag of the server to be retrieved.
+ /// @return Pointer to the @c Server object representing the server or
+ /// null if such server doesn't exist.
+ db::ServerPtr getServer(const int index, const data::ServerTag& server_tag);
+
+ /// @brief Retrieves all servers.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param [out] servers Reference to the container where fetched servers
+ /// will be inserted.
+ void getAllServers(const int index, db::ServerCollection& servers);
+
+ /// @brief Sends query to retrieve servers.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param bindings Reference to the PgSQL input bindings.
+ /// @param [out] servers Reference to the container where fetched servers
+ /// will be inserted.
+ void getServers(const int index,
+ const db::PsqlBindArray& bindings,
+ db::ServerCollection& servers);
+
+ /// @brief Creates or updates a server.
+ ///
+ /// This method attempts to insert a new server into the database using
+ /// the query identified by @c create_index. If the insertion fails because
+ /// the server with the given tag already exists in the database, the
+ /// existing server is updated using the query identified by the
+ /// @c update_index.
+ ///
+ /// @param create_audit_revision Index of the query inserting audit
+ /// revision.
+ /// @param create_index Index of the INSERT query to be used.
+ /// @param update_index Index of the UPDATE query to be used.
+ /// @param server Pointer to the server to be inserted or updated.
+ /// @throw InvalidOperation when trying to create a duplicate or
+ /// update the logical server 'all'.
+ void createUpdateServer(const int& create_audit_revision,
+ const int& create_index,
+ const int& update_index,
+ const db::ServerPtr& server);
+
+ /// @brief Executes multiple update and/or delete queries with no input
+ /// bindings.
+ ///
+ /// This is a convenience function which takes multiple query indexes as
+ /// arguments and for each index executes an update or delete query.
+ /// One of the applications of this function is to remove dangling
+ /// configuration elements after the server associated with these elements
+ /// have been deleted.
+ ///
+ /// @tparam T type of the indexes, e.g. @c PgSqlConfigBackendDHCPv4Impl::StatementIndex.
+ /// @tparam R parameter pack holding indexes of type @c T.
+ /// @param first_index first index.
+ /// @param other_indexes remaining indexes.
+ template<typename T, typename... R>
+ void multipleUpdateDeleteQueries(T first_index, R... other_indexes) {
+ std::vector<T> indexes({ first_index, other_indexes... });
+ db::PsqlBindArray in_bindings;
+ for (auto index : indexes) {
+ updateDeleteQuery(index, in_bindings);
+ }
+ }
+
+ /// @brief Removes configuration elements from the index which don't match
+ /// the specified server selector.
+ ///
+ /// This is a generic function which removes configuration elements which
+ /// don't match the specified selector. In order to fetch all server tags
+ /// for the returned configuration element, the query must not limit the
+ /// results to the given server tag. Instead, it must post process the
+ /// result to eliminate those configuration elements for which the desired
+ /// server tag wasn't found.
+ ///
+ /// If the server selector is set to ANY, this method is no-op.
+ ///
+ /// @tparam CollectionIndex Type of the collection to be processed.
+ /// @param server_selector Server selector.
+ /// @param index Reference to the index holding the returned configuration
+ /// elements to be processed.
+ template<typename CollectionIndex>
+ void tossNonMatchingElements(const db::ServerSelector& server_selector,
+ CollectionIndex& index) {
+ // Don't filter the matching server tags if the server selector is
+ // set to ANY.
+ if (server_selector.amAny()) {
+ return;
+ }
+
+ // Go over the collection of elements.
+ for (auto elem = index.begin(); elem != index.end();) {
+
+ // If we're asking for shared networks matching all servers,
+ // we have to make sure that the fetched element has "all"
+ // server tag.
+ if (server_selector.amAll()) {
+ if (!(*elem)->hasAllServerTag()) {
+ // It doesn't so let's remove it.
+ elem = index.erase(elem);
+ continue;
+ }
+
+ } else if (server_selector.amUnassigned()) {
+ // Returned element has server tags but we expect that the
+ // elements are unassigned.
+ if (!(*elem)->getServerTags().empty()) {
+ elem = index.erase(elem);
+ continue;
+ }
+
+ } else {
+ // Server selector contains explicit server tags, so
+ // let's see if the returned elements includes any of
+ // them.
+ auto const& tags = server_selector.getTags();
+ bool tag_found = false;
+ for (auto const& tag : tags) {
+ if ((*elem)->hasServerTag(tag) ||
+ (*elem)->hasAllServerTag()) {
+ tag_found = true;
+ break;
+ }
+ }
+ if (!tag_found) {
+ // Tag not matching, so toss the element.
+ elem = index.erase(elem);
+ continue;
+ }
+ }
+
+ // Go to the next element if we didn't toss the current one.
+ // Otherwise, the erase() function should have already taken
+ // us to the next one.
+ ++elem;
+ }
+ }
+
+ /// @brief Returns backend type in the textual format.
+ ///
+ /// @return "postgresql".
+ std::string getType() const;
+
+ /// @brief Returns backend host.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return host on which the database is located.
+ std::string getHost() const;
+
+ /// @brief Returns backend port number.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return Port number on which database service is available.
+ uint16_t getPort() const;
+
+ /// @brief Return backend parameters
+ ///
+ /// Returns the backend parameters
+ ///
+ /// @return Parameters of the backend.
+ const isc::db::DatabaseConnection::ParameterMap& getParameters() {
+ return (parameters_);
+ }
+
+ /// @brief Sets IO service to be used by the PostgreSQL config backend.
+ ///
+ /// @param IOService object, used for all ASIO operations.
+ static void setIOService(const isc::asiolink::IOServicePtr& io_service) {
+ io_service_ = io_service;
+ }
+
+ /// @brief Returns pointer to the IO service.
+ static isc::asiolink::IOServicePtr& getIOService() {
+ return (io_service_);
+ }
+
+ /// @brief Fetches the SQL statement for a given statement index.
+ ///
+ /// Derivations must override the implementation. The reference
+ /// returned should be non-volatile over the entire lifetime
+ /// of the derivation instance.
+ ///
+ /// @param index index of the desired statement.
+ /// @throw NotImplemented, always
+ virtual db::PgSqlTaggedStatement& getStatement(size_t index) const;
+
+ /// @brief Executes SELECT using the prepared statement specified
+ /// by the given index.
+ ///
+ /// The @c index must refer to an existing prepared statement
+ /// associated with the connection. The @c in_bindings size must match
+ /// the number of placeholders in the prepared statement.
+ ///
+ /// This method executes prepared statement using provided input bindings and
+ /// calls @c process_result_row function for each returned row. The
+ /// @c process_result function is implemented by the caller and should
+ /// gather and store each returned row in an external data structure prior.
+ ///
+ /// @param statement reference to the precompiled tagged statement to execute
+ /// @param in_bindings input bindings holding values to substitue placeholders
+ /// in the query.
+ /// @param process_result_row Pointer to the function to be invoked for each
+ /// retrieved row. This function consumes the retrieved data from the
+ /// result set.
+ void selectQuery(size_t index, const db::PsqlBindArray& in_bindings,
+ db::PgSqlConnection::ConsumeResultRowFun process_result_row);
+
+ /// @brief Executes INSERT using the prepared statement specified
+ /// by the given index.
+ ///
+ /// The @c index must refer to an existing prepared statement
+ /// associated with the connection. The @c in_bindings size must match
+ /// the number of placeholders in the prepared statement.
+ ///
+ /// This method executes prepared statement using provided bindings to
+ /// insert data into the database.
+ ///
+ /// @param statement reference to the precompiled tagged statement to execute
+ /// @param in_bindings input bindings holding values to substitue placeholders
+ /// in the query.
+ void insertQuery(size_t index, const db::PsqlBindArray& in_bindings);
+
+ /// @brief Executes UPDATE or DELETE using the prepared statement
+ /// specified by the given index, and returns the number of affected rows.
+ ///
+ /// The @c index must refer to an existing prepared statement
+ /// associated with the connection. The @c in_bindings size must match
+ /// the number of placeholders in the prepared statement.
+ ///
+ /// @param statement reference to the precompiled tagged statement to execute
+ /// @param in_bindings Input bindings holding values to substitute placeholders
+ /// in the query.
+ ///
+ /// @return Number of affected rows.
+ uint64_t updateDeleteQuery(size_t index, const db::PsqlBindArray& in_bindings);
+
+ /// @brief Represents connection to the PostgreSQL database.
+ db::PgSqlConnection conn_;
+
+protected:
+
+ /// @brief Timer name used to register database reconnect timer.
+ std::string timer_name_;
+
+private:
+
+ /// @brief Reference counter for @ScopedAuditRevision instances.
+ int audit_revision_ref_count_;
+
+ /// @brief Connection parameters
+ isc::db::DatabaseConnection::ParameterMap parameters_;
+
+ /// @brief The IOService object, used for all ASIO operations.
+ static isc::asiolink::IOServicePtr io_service_;
+
+ /// @brief Statement index of the SQL statement to use for fetching
+ /// last inserted id in a given table.
+ size_t last_insert_id_index_;
+};
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc
new file mode 100644
index 0000000..64522d9
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.cc
@@ -0,0 +1,17 @@
+// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <pgsql_cb_log.h>
+
+namespace isc {
+namespace dhcp {
+
+isc::log::Logger pgsql_cb_logger("pgsql-cb-hooks");
+
+} // namespace dhcp
+} // namespace isc
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h
new file mode 100644
index 0000000..6331177
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_log.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef LEASE_CMD_LOG_H
+#define LEASE_CMD_LOG_H
+
+#include <log/logger_support.h>
+#include <log/macros.h>
+#include <pgsql_cb_messages.h>
+
+namespace isc {
+namespace dhcp {
+
+extern isc::log::Logger pgsql_cb_logger;
+
+} // namespace dhcp
+} // namespace isc
+
+#endif
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc
new file mode 100644
index 0000000..2baed5c
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.cc
@@ -0,0 +1,405 @@
+// File created from ../../../../src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
+
+#include <cstddef>
+#include <log/message_types.h>
+#include <log/message_initializer.h>
+
+namespace isc {
+namespace cb {
+
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4 = "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6 = "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6 = "PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4 = "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6 = "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 = "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 = "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 = "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 = "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION4 = "PGSQL_CB_CREATE_UPDATE_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION6 = "PGSQL_CB_CREATE_UPDATE_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF4 = "PGSQL_CB_CREATE_UPDATE_OPTION_DEF4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF6 = "PGSQL_CB_CREATE_UPDATE_OPTION_DEF6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER4 = "PGSQL_CB_CREATE_UPDATE_SERVER4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER6 = "PGSQL_CB_CREATE_UPDATE_SERVER6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6 = "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET4 = "PGSQL_CB_CREATE_UPDATE_SUBNET4";
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET6 = "PGSQL_CB_CREATE_UPDATE_SUBNET6";
+extern const isc::log::MessageID PGSQL_CB_DEINIT_OK = "PGSQL_CB_DEINIT_OK";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4 = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6 = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT = "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT = "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4 = "PGSQL_CB_DELETE_ALL_OPTION_DEFS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT = "PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6 = "PGSQL_CB_DELETE_ALL_OPTION_DEFS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT = "PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4 = "PGSQL_CB_DELETE_ALL_SERVERS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4_RESULT = "PGSQL_CB_DELETE_ALL_SERVERS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6 = "PGSQL_CB_DELETE_ALL_SERVERS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6_RESULT = "PGSQL_CB_DELETE_ALL_SERVERS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4 = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6 = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT = "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4 = "PGSQL_CB_DELETE_ALL_SUBNETS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT = "PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6 = "PGSQL_CB_DELETE_ALL_SUBNETS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT = "PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4 = "PGSQL_CB_DELETE_BY_POOL_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT = "PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6 = "PGSQL_CB_DELETE_BY_POOL_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT = "PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6 = "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT = "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4 = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6 = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT = "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4 = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6 = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4 = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6 = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT = "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4 = "PGSQL_CB_DELETE_CLIENT_CLASS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT = "PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6 = "PGSQL_CB_DELETE_CLIENT_CLASS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT = "PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4 = "PGSQL_CB_DELETE_GLOBAL_PARAMETER4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT = "PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6 = "PGSQL_CB_DELETE_GLOBAL_PARAMETER6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT = "PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4 = "PGSQL_CB_DELETE_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4_RESULT = "PGSQL_CB_DELETE_OPTION4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6 = "PGSQL_CB_DELETE_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6_RESULT = "PGSQL_CB_DELETE_OPTION6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4 = "PGSQL_CB_DELETE_OPTION_DEF4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4_RESULT = "PGSQL_CB_DELETE_OPTION_DEF4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6 = "PGSQL_CB_DELETE_OPTION_DEF6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6_RESULT = "PGSQL_CB_DELETE_OPTION_DEF6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4 = "PGSQL_CB_DELETE_SERVER4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4_RESULT = "PGSQL_CB_DELETE_SERVER4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6 = "PGSQL_CB_DELETE_SERVER6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6_RESULT = "PGSQL_CB_DELETE_SERVER6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4 = "PGSQL_CB_DELETE_SHARED_NETWORK4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6 = "PGSQL_CB_DELETE_SHARED_NETWORK6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4 = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6 = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4 = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6 = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6";
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT = "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4 = "PGSQL_CB_GET_ALL_CLIENT_CLASSES4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT = "PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6 = "PGSQL_CB_GET_ALL_CLIENT_CLASSES6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT = "PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT = "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4 = "PGSQL_CB_GET_ALL_OPTIONS4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4_RESULT = "PGSQL_CB_GET_ALL_OPTIONS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6 = "PGSQL_CB_GET_ALL_OPTIONS6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6_RESULT = "PGSQL_CB_GET_ALL_OPTIONS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4 = "PGSQL_CB_GET_ALL_OPTION_DEFS4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT = "PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6 = "PGSQL_CB_GET_ALL_OPTION_DEFS6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT = "PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4 = "PGSQL_CB_GET_ALL_SERVERS4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4_RESULT = "PGSQL_CB_GET_ALL_SERVERS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6 = "PGSQL_CB_GET_ALL_SERVERS6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6_RESULT = "PGSQL_CB_GET_ALL_SERVERS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4 = "PGSQL_CB_GET_ALL_SHARED_NETWORKS4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT = "PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6 = "PGSQL_CB_GET_ALL_SHARED_NETWORKS6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT = "PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4 = "PGSQL_CB_GET_ALL_SUBNETS4";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4_RESULT = "PGSQL_CB_GET_ALL_SUBNETS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6 = "PGSQL_CB_GET_ALL_SUBNETS6";
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6_RESULT = "PGSQL_CB_GET_ALL_SUBNETS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS4 = "PGSQL_CB_GET_CLIENT_CLASS4";
+extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS6 = "PGSQL_CB_GET_CLIENT_CLASS6";
+extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER4 = "PGSQL_CB_GET_GLOBAL_PARAMETER4";
+extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER6 = "PGSQL_CB_GET_GLOBAL_PARAMETER6";
+extern const isc::log::MessageID PGSQL_CB_GET_HOST4 = "PGSQL_CB_GET_HOST4";
+extern const isc::log::MessageID PGSQL_CB_GET_HOST6 = "PGSQL_CB_GET_HOST6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4 = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT = "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6 = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT = "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4 = "PGSQL_CB_GET_MODIFIED_OPTIONS4";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT = "PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6 = "PGSQL_CB_GET_MODIFIED_OPTIONS6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT = "PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4 = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6 = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT = "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4 = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6 = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT = "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4 = "PGSQL_CB_GET_MODIFIED_SUBNETS4";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT = "PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6 = "PGSQL_CB_GET_MODIFIED_SUBNETS6";
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT = "PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION4 = "PGSQL_CB_GET_OPTION4";
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION6 = "PGSQL_CB_GET_OPTION6";
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF4 = "PGSQL_CB_GET_OPTION_DEF4";
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF6 = "PGSQL_CB_GET_OPTION_DEF6";
+extern const isc::log::MessageID PGSQL_CB_GET_PORT4 = "PGSQL_CB_GET_PORT4";
+extern const isc::log::MessageID PGSQL_CB_GET_PORT6 = "PGSQL_CB_GET_PORT6";
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4 = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4";
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6 = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6";
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT = "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_SERVER4 = "PGSQL_CB_GET_SERVER4";
+extern const isc::log::MessageID PGSQL_CB_GET_SERVER6 = "PGSQL_CB_GET_SERVER6";
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK4 = "PGSQL_CB_GET_SHARED_NETWORK4";
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK6 = "PGSQL_CB_GET_SHARED_NETWORK6";
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4 = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4";
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6 = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6";
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT = "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT";
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_PREFIX = "PGSQL_CB_GET_SUBNET4_BY_PREFIX";
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID = "PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID";
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_PREFIX = "PGSQL_CB_GET_SUBNET6_BY_PREFIX";
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID = "PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID";
+extern const isc::log::MessageID PGSQL_CB_GET_TYPE4 = "PGSQL_CB_GET_TYPE4";
+extern const isc::log::MessageID PGSQL_CB_GET_TYPE6 = "PGSQL_CB_GET_TYPE6";
+extern const isc::log::MessageID PGSQL_CB_INIT_OK = "PGSQL_CB_INIT_OK";
+extern const isc::log::MessageID PGSQL_CB_NO_TLS_SUPPORT = "PGSQL_CB_NO_TLS_SUPPORT";
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED4 = "PGSQL_CB_RECONNECT_ATTEMPT_FAILED4";
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED6 = "PGSQL_CB_RECONNECT_ATTEMPT_FAILED6";
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4 = "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4";
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6 = "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6";
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED4 = "PGSQL_CB_RECONNECT_FAILED4";
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED6 = "PGSQL_CB_RECONNECT_FAILED6";
+extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE4 = "PGSQL_CB_REGISTER_BACKEND_TYPE4";
+extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE6 = "PGSQL_CB_REGISTER_BACKEND_TYPE6";
+extern const isc::log::MessageID PGSQL_CB_TLS_SUPPORT = "PGSQL_CB_TLS_SUPPORT";
+extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE4 = "PGSQL_CB_UNREGISTER_BACKEND_TYPE4";
+extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE6 = "PGSQL_CB_UNREGISTER_BACKEND_TYPE6";
+
+} // namespace cb
+} // namespace isc
+
+namespace {
+
+const char* values[] = {
+ "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4", "create or update option pool start: %1 pool end: %2",
+ "PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6", "create or update option pool start: %1 pool end: %2",
+ "PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6", "create or update option prefix: %1 prefix len: %2",
+ "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4", "create or update option by subnet id: %1",
+ "PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6", "create or update option by subnet id: %1",
+ "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4", "create or update client class: %1",
+ "PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6", "create or update client class: %1",
+ "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4", "create or update global parameter: %1",
+ "PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6", "create or update global parameter: %1",
+ "PGSQL_CB_CREATE_UPDATE_OPTION4", "create or update option",
+ "PGSQL_CB_CREATE_UPDATE_OPTION6", "create or update option",
+ "PGSQL_CB_CREATE_UPDATE_OPTION_DEF4", "create or update option definition: %1 code: %2",
+ "PGSQL_CB_CREATE_UPDATE_OPTION_DEF6", "create or update option definition: %1 code: %2",
+ "PGSQL_CB_CREATE_UPDATE_SERVER4", "create or update server: %1",
+ "PGSQL_CB_CREATE_UPDATE_SERVER6", "create or update server: %1",
+ "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4", "create or update shared network: %1",
+ "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6", "create or update shared network: %1",
+ "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4", "create or update shared network: %1 option",
+ "PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6", "create or update shared network: %1 option",
+ "PGSQL_CB_CREATE_UPDATE_SUBNET4", "create or update subnet: %1",
+ "PGSQL_CB_CREATE_UPDATE_SUBNET6", "create or update subnet: %1",
+ "PGSQL_CB_DEINIT_OK", "unloading Postgres CB hooks library successful",
+ "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4", "delete all client classes",
+ "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6", "delete all client classes",
+ "PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4", "delete all global parameters",
+ "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6", "delete all global parameters",
+ "PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_OPTION_DEFS4", "delete all option definitions",
+ "PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_OPTION_DEFS6", "delete all option definitions",
+ "PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_SERVERS4", "delete all DHCPv4 servers",
+ "PGSQL_CB_DELETE_ALL_SERVERS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_SERVERS6", "delete all DHCPv6 servers",
+ "PGSQL_CB_DELETE_ALL_SERVERS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4", "delete all shared networks",
+ "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6", "delete all shared networks",
+ "PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_SUBNETS4", "delete all subnets",
+ "PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_ALL_SUBNETS6", "delete all subnets",
+ "PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_POOL_OPTION4", "delete pool start: %1 pool end: %2 option code: %3 space: %4",
+ "PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_POOL_OPTION6", "delete pool start: %1 pool end: %2 option code: %3 space: %4",
+ "PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6", "delete prefix: %1 prefix len: %2 option code: %3 space: %4",
+ "PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4", "delete subnet by prefix: %1",
+ "PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6", "delete subnet by prefix: %1",
+ "PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4", "delete by subnet id: %1 option code: %2 space: %3",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6", "delete by subnet id: %1 option code: %2 space: %3",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4", "delete subnet by subnet id: %1",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6", "delete subnet by subnet id: %1",
+ "PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_CLIENT_CLASS4", "delete client class: %1",
+ "PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_CLIENT_CLASS6", "delete client class: %1",
+ "PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_GLOBAL_PARAMETER4", "delete global parameter: %1",
+ "PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_GLOBAL_PARAMETER6", "delete global parameter: %1",
+ "PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_OPTION4", "delete option code: %1 space: %2",
+ "PGSQL_CB_DELETE_OPTION4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_OPTION6", "delete option code: %1 space: %2",
+ "PGSQL_CB_DELETE_OPTION6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_OPTION_DEF4", "delete option definition code: %1 space: %2",
+ "PGSQL_CB_DELETE_OPTION_DEF4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_OPTION_DEF6", "delete option definition code: %1 space: %2",
+ "PGSQL_CB_DELETE_OPTION_DEF6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SERVER4", "delete DHCPv4 server: %1",
+ "PGSQL_CB_DELETE_SERVER4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SERVER6", "delete DHCPv6 server: %1",
+ "PGSQL_CB_DELETE_SERVER6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SHARED_NETWORK4", "delete shared network: %1",
+ "PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SHARED_NETWORK6", "delete shared network: %1",
+ "PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4", "delete shared network: %1 option code: %2 space: %3",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6", "delete shared network: %1 option code: %2 space: %3",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4", "delete shared network: %1 subnets",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6", "delete shared network: %1 subnets",
+ "PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT", "deleted: %1 entries",
+ "PGSQL_CB_GET_ALL_CLIENT_CLASSES4", "retrieving all client classes",
+ "PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_CLIENT_CLASSES6", "retrieving all client classes",
+ "PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4", "retrieving all global parameters",
+ "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6", "retrieving all global parameters",
+ "PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_OPTIONS4", "retrieving all options",
+ "PGSQL_CB_GET_ALL_OPTIONS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_OPTIONS6", "retrieving all options",
+ "PGSQL_CB_GET_ALL_OPTIONS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_OPTION_DEFS4", "retrieving all option definitions",
+ "PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_OPTION_DEFS6", "retrieving all option definitions",
+ "PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_SERVERS4", "retrieving all servers",
+ "PGSQL_CB_GET_ALL_SERVERS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_SERVERS6", "retrieving all DHCPv6 servers",
+ "PGSQL_CB_GET_ALL_SERVERS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_SHARED_NETWORKS4", "retrieving all shared networks",
+ "PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_SHARED_NETWORKS6", "retrieving all shared networks",
+ "PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_SUBNETS4", "retrieving all subnets",
+ "PGSQL_CB_GET_ALL_SUBNETS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_ALL_SUBNETS6", "retrieving all subnets",
+ "PGSQL_CB_GET_ALL_SUBNETS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_CLIENT_CLASS4", "retrieving client class: %1",
+ "PGSQL_CB_GET_CLIENT_CLASS6", "retrieving client class: %1",
+ "PGSQL_CB_GET_GLOBAL_PARAMETER4", "retrieving global parameter: %1",
+ "PGSQL_CB_GET_GLOBAL_PARAMETER6", "retrieving global parameter: %1",
+ "PGSQL_CB_GET_HOST4", "get host",
+ "PGSQL_CB_GET_HOST6", "get host",
+ "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4", "retrieving modified client classes from: %1",
+ "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6", "retrieving modified client classes from: %1",
+ "PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4", "retrieving modified global parameters from: %1",
+ "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6", "retrieving modified global parameters from: %1",
+ "PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_OPTIONS4", "retrieving modified options from: %1",
+ "PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_OPTIONS6", "retrieving modified options from: %1",
+ "PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4", "retrieving modified option definitions from: %1",
+ "PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6", "retrieving modified option definitions from: %1",
+ "PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4", "retrieving modified shared networks from: %1",
+ "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6", "retrieving modified shared networks from: %1",
+ "PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_SUBNETS4", "retrieving modified subnets from: %1",
+ "PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_MODIFIED_SUBNETS6", "retrieving modified subnets from: %1",
+ "PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_OPTION4", "retrieving option code: %1 space: %2",
+ "PGSQL_CB_GET_OPTION6", "retrieving option code: %1 space: %2",
+ "PGSQL_CB_GET_OPTION_DEF4", "retrieving option definition code: %1 space: %2",
+ "PGSQL_CB_GET_OPTION_DEF6", "retrieving option definition code: %1 space: %2",
+ "PGSQL_CB_GET_PORT4", "get port",
+ "PGSQL_CB_GET_PORT6", "get port",
+ "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4", "retrieving audit entries from: %1 %2",
+ "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6", "retrieving audit entries from: %1 %2",
+ "PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_SERVER4", "retrieving DHCPv4 server: %1",
+ "PGSQL_CB_GET_SERVER6", "retrieving DHCPv6 server: %1",
+ "PGSQL_CB_GET_SHARED_NETWORK4", "retrieving shared network: %1",
+ "PGSQL_CB_GET_SHARED_NETWORK6", "retrieving shared network: %1",
+ "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4", "retrieving shared network: %1 subnets",
+ "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6", "retrieving shared network: %1 subnets",
+ "PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT", "retrieving: %1 elements",
+ "PGSQL_CB_GET_SUBNET4_BY_PREFIX", "retrieving subnet by prefix: %1",
+ "PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID", "retrieving subnet by subnet id: %1",
+ "PGSQL_CB_GET_SUBNET6_BY_PREFIX", "retrieving subnet by prefix: %1",
+ "PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID", "retrieving subnet by subnet id: %1",
+ "PGSQL_CB_GET_TYPE4", "get type",
+ "PGSQL_CB_GET_TYPE6", "get type",
+ "PGSQL_CB_INIT_OK", "loading Postgres CB hooks library successful",
+ "PGSQL_CB_NO_TLS_SUPPORT", "Attempt to configure TLS (unsupported for PostgreSQL): %1",
+ "PGSQL_CB_RECONNECT_ATTEMPT_FAILED4", "database reconnect failed: %1",
+ "PGSQL_CB_RECONNECT_ATTEMPT_FAILED6", "database reconnect failed: %1",
+ "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4", "scheduling attempt %1 of %2 in %3 milliseconds",
+ "PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6", "scheduling attempt %1 of %2 in %3 milliseconds",
+ "PGSQL_CB_RECONNECT_FAILED4", "maximum number of database reconnect attempts: %1, has been exhausted without success",
+ "PGSQL_CB_RECONNECT_FAILED6", "maximum number of database reconnect attempts: %1, has been exhausted without success",
+ "PGSQL_CB_REGISTER_BACKEND_TYPE4", "register backend",
+ "PGSQL_CB_REGISTER_BACKEND_TYPE6", "register backend",
+ "PGSQL_CB_TLS_SUPPORT", "Attempt to configure TLS: %1",
+ "PGSQL_CB_UNREGISTER_BACKEND_TYPE4", "unregister backend",
+ "PGSQL_CB_UNREGISTER_BACKEND_TYPE6", "unregister backend",
+ NULL
+};
+
+const isc::log::MessageInitializer initializer(values);
+
+} // Anonymous namespace
+
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h
new file mode 100644
index 0000000..57a41d3
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.h
@@ -0,0 +1,206 @@
+// File created from ../../../../src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
+
+#ifndef PGSQL_CB_MESSAGES_H
+#define PGSQL_CB_MESSAGES_H
+
+#include <log/message_types.h>
+
+namespace isc {
+namespace cb {
+
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_OPTION_DEF6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SERVER6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET4;
+extern const isc::log::MessageID PGSQL_CB_CREATE_UPDATE_SUBNET6;
+extern const isc::log::MessageID PGSQL_CB_DEINIT_OK;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SERVERS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_OPTION_DEF6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SERVER6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6;
+extern const isc::log::MessageID PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTIONS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SERVERS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6;
+extern const isc::log::MessageID PGSQL_CB_GET_ALL_SUBNETS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS4;
+extern const isc::log::MessageID PGSQL_CB_GET_CLIENT_CLASS6;
+extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER4;
+extern const isc::log::MessageID PGSQL_CB_GET_GLOBAL_PARAMETER6;
+extern const isc::log::MessageID PGSQL_CB_GET_HOST4;
+extern const isc::log::MessageID PGSQL_CB_GET_HOST6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6;
+extern const isc::log::MessageID PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION4;
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION6;
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF4;
+extern const isc::log::MessageID PGSQL_CB_GET_OPTION_DEF6;
+extern const isc::log::MessageID PGSQL_CB_GET_PORT4;
+extern const isc::log::MessageID PGSQL_CB_GET_PORT6;
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4;
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6;
+extern const isc::log::MessageID PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_SERVER4;
+extern const isc::log::MessageID PGSQL_CB_GET_SERVER6;
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK4;
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK6;
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4;
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6;
+extern const isc::log::MessageID PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT;
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_PREFIX;
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID;
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_PREFIX;
+extern const isc::log::MessageID PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID;
+extern const isc::log::MessageID PGSQL_CB_GET_TYPE4;
+extern const isc::log::MessageID PGSQL_CB_GET_TYPE6;
+extern const isc::log::MessageID PGSQL_CB_INIT_OK;
+extern const isc::log::MessageID PGSQL_CB_NO_TLS_SUPPORT;
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED4;
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_FAILED6;
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4;
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6;
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED4;
+extern const isc::log::MessageID PGSQL_CB_RECONNECT_FAILED6;
+extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE4;
+extern const isc::log::MessageID PGSQL_CB_REGISTER_BACKEND_TYPE6;
+extern const isc::log::MessageID PGSQL_CB_TLS_SUPPORT;
+extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE4;
+extern const isc::log::MessageID PGSQL_CB_UNREGISTER_BACKEND_TYPE6;
+
+} // namespace cb
+} // namespace isc
+
+#endif // PGSQL_CB_MESSAGES_H
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
new file mode 100644
index 0000000..8855ece
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
@@ -0,0 +1,595 @@
+# Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC")
+
+$NAMESPACE isc::cb
+
+% PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION4 create or update option pool start: %1 pool end: %2
+Debug message issued when triggered an action to create or update option by pool
+
+% PGSQL_CB_CREATE_UPDATE_BY_POOL_OPTION6 create or update option pool start: %1 pool end: %2
+Debug message issued when triggered an action to create or update option by pool
+
+% PGSQL_CB_CREATE_UPDATE_BY_PREFIX_OPTION6 create or update option prefix: %1 prefix len: %2
+Debug message issued when triggered an action to create or update option by prefix
+
+% PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4 create or update option by subnet id: %1
+Debug message issued when triggered an action to create or update option by subnet id
+
+% PGSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6 create or update option by subnet id: %1
+Debug message issued when triggered an action to create or update option by subnet id
+
+% PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 create or update client class: %1
+Debug message issued when triggered an action to create or update client class
+
+% PGSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 create or update client class: %1
+Debug message issued when triggered an action to create or update client class
+
+% PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 create or update global parameter: %1
+Debug message issued when triggered an action to create or update global parameter
+
+% PGSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 create or update global parameter: %1
+Debug message issued when triggered an action to create or update global parameter
+
+% PGSQL_CB_CREATE_UPDATE_OPTION4 create or update option
+Debug message issued when triggered an action to create or update option
+
+% PGSQL_CB_CREATE_UPDATE_OPTION6 create or update option
+Debug message issued when triggered an action to create or update option
+
+% PGSQL_CB_CREATE_UPDATE_OPTION_DEF4 create or update option definition: %1 code: %2
+Debug message issued when triggered an action to create or update option definition
+
+% PGSQL_CB_CREATE_UPDATE_OPTION_DEF6 create or update option definition: %1 code: %2
+Debug message issued when triggered an action to create or update option definition
+
+% PGSQL_CB_CREATE_UPDATE_SERVER4 create or update server: %1
+Debug message issued when triggered an action to create or update a DHCPv4
+server information.
+
+% PGSQL_CB_CREATE_UPDATE_SERVER6 create or update server: %1
+Debug message issued when triggered an action to create or update a DHCPv6
+server information.
+
+% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK4 create or update shared network: %1
+Debug message issued when triggered an action to create or update shared network
+
+% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK6 create or update shared network: %1
+Debug message issued when triggered an action to create or update shared network
+
+% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION4 create or update shared network: %1 option
+Debug message issued when triggered an action to create or update shared network option
+
+% PGSQL_CB_CREATE_UPDATE_SHARED_NETWORK_OPTION6 create or update shared network: %1 option
+Debug message issued when triggered an action to create or update shared network option
+
+% PGSQL_CB_CREATE_UPDATE_SUBNET4 create or update subnet: %1
+Debug message issued when triggered an action to create or update subnet
+
+% PGSQL_CB_CREATE_UPDATE_SUBNET6 create or update subnet: %1
+Debug message issued when triggered an action to create or update subnet
+
+% PGSQL_CB_DEINIT_OK unloading Postgres CB hooks library successful
+This informational message indicates that the Postgres Configuration Backend hooks
+library has been unloaded successfully.
+
+% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4 delete all client classes
+Debug message issued when triggered an action to delete all client classes
+
+% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all client classes
+
+% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6 delete all client classes
+Debug message issued when triggered an action to delete all client classes
+
+% PGSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all client classes
+
+% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 delete all global parameters
+Debug message issued when triggered an action to delete all global parameters
+
+% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all global parameters
+
+% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 delete all global parameters
+Debug message issued when triggered an action to delete all global parameters
+
+% PGSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all global parameters
+
+% PGSQL_CB_DELETE_ALL_OPTION_DEFS4 delete all option definitions
+Debug message issued when triggered an action to delete all option definitions
+
+% PGSQL_CB_DELETE_ALL_OPTION_DEFS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all option definitions
+
+% PGSQL_CB_DELETE_ALL_OPTION_DEFS6 delete all option definitions
+Debug message issued when triggered an action to delete all option definitions
+
+% PGSQL_CB_DELETE_ALL_OPTION_DEFS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all option definitions
+
+% PGSQL_CB_DELETE_ALL_SERVERS4 delete all DHCPv4 servers
+Debug message issued when triggered an action to delete all servers.
+
+% PGSQL_CB_DELETE_ALL_SERVERS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all servers.
+
+% PGSQL_CB_DELETE_ALL_SERVERS6 delete all DHCPv6 servers
+Debug message issued when triggered an action to delete all servers.
+
+% PGSQL_CB_DELETE_ALL_SERVERS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all servers.
+
+% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4 delete all shared networks
+Debug message issued when triggered an action to delete all shared networks
+
+% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all shared networks
+
+% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6 delete all shared networks
+Debug message issued when triggered an action to delete all shared networks
+
+% PGSQL_CB_DELETE_ALL_SHARED_NETWORKS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all shared networks
+
+% PGSQL_CB_DELETE_ALL_SUBNETS4 delete all subnets
+Debug message issued when triggered an action to delete all subnets
+
+% PGSQL_CB_DELETE_ALL_SUBNETS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all subnets
+
+% PGSQL_CB_DELETE_ALL_SUBNETS6 delete all subnets
+Debug message issued when triggered an action to delete all subnets
+
+% PGSQL_CB_DELETE_ALL_SUBNETS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all subnets
+
+% PGSQL_CB_DELETE_BY_POOL_OPTION4 delete pool start: %1 pool end: %2 option code: %3 space: %4
+Debug message issued when triggered an action to delete option by pool
+
+% PGSQL_CB_DELETE_BY_POOL_OPTION4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option by pool
+
+% PGSQL_CB_DELETE_BY_POOL_OPTION6 delete pool start: %1 pool end: %2 option code: %3 space: %4
+Debug message issued when triggered an action to delete option by pool
+
+% PGSQL_CB_DELETE_BY_POOL_OPTION6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option by pool
+
+% PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6 delete prefix: %1 prefix len: %2 option code: %3 space: %4
+Debug message issued when triggered an action to delete option by prefix
+
+% PGSQL_CB_DELETE_BY_POOL_PREFIX_OPTION6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option by prefix
+
+% PGSQL_CB_DELETE_BY_PREFIX_SUBNET4 delete subnet by prefix: %1
+Debug message issued when triggered an action to delete subnet by prefix
+
+% PGSQL_CB_DELETE_BY_PREFIX_SUBNET4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete subnet by prefix
+
+% PGSQL_CB_DELETE_BY_PREFIX_SUBNET6 delete subnet by prefix: %1
+Debug message issued when triggered an action to delete subnet by prefix
+
+% PGSQL_CB_DELETE_BY_PREFIX_SUBNET6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete subnet by prefix
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4 delete by subnet id: %1 option code: %2 space: %3
+Debug message issued when triggered an action to delete option by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6 delete by subnet id: %1 option code: %2 space: %3
+Debug message issued when triggered an action to delete option by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_OPTION6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4 delete subnet by subnet id: %1
+Debug message issued when triggered an action to delete subnet by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete subnet by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6 delete subnet by subnet id: %1
+Debug message issued when triggered an action to delete subnet by subnet id
+
+% PGSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete subnet by subnet id
+
+% PGSQL_CB_DELETE_CLIENT_CLASS4 delete client class: %1
+Debug message issued when triggered an action to delete client class
+
+% PGSQL_CB_DELETE_CLIENT_CLASS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete client class
+
+% PGSQL_CB_DELETE_CLIENT_CLASS6 delete client class: %1
+Debug message issued when triggered an action to delete client class
+
+% PGSQL_CB_DELETE_CLIENT_CLASS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete client class
+
+% PGSQL_CB_DELETE_GLOBAL_PARAMETER4 delete global parameter: %1
+Debug message issued when triggered an action to delete global parameter
+
+% PGSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete global parameter
+
+% PGSQL_CB_DELETE_GLOBAL_PARAMETER6 delete global parameter: %1
+Debug message issued when triggered an action to delete global parameter
+
+% PGSQL_CB_DELETE_GLOBAL_PARAMETER6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete global parameter
+
+% PGSQL_CB_DELETE_OPTION4 delete option code: %1 space: %2
+Debug message issued when triggered an action to delete option
+
+% PGSQL_CB_DELETE_OPTION4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option
+
+% PGSQL_CB_DELETE_OPTION6 delete option code: %1 space: %2
+Debug message issued when triggered an action to delete option
+
+% PGSQL_CB_DELETE_OPTION6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option
+
+% PGSQL_CB_DELETE_OPTION_DEF4 delete option definition code: %1 space: %2
+Debug message issued when triggered an action to delete option definition
+
+% PGSQL_CB_DELETE_OPTION_DEF4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option definition
+
+% PGSQL_CB_DELETE_OPTION_DEF6 delete option definition code: %1 space: %2
+Debug message issued when triggered an action to delete option definition
+
+% PGSQL_CB_DELETE_OPTION_DEF6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete option definition
+
+% PGSQL_CB_DELETE_SERVER4 delete DHCPv4 server: %1
+Debug message issued when triggered an action to delete a server.
+
+% PGSQL_CB_DELETE_SERVER4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete a server.
+
+% PGSQL_CB_DELETE_SERVER6 delete DHCPv6 server: %1
+Debug message issued when triggered an action to delete a server.
+
+% PGSQL_CB_DELETE_SERVER6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete a server.
+
+% PGSQL_CB_DELETE_SHARED_NETWORK4 delete shared network: %1
+Debug message issued when triggered an action to delete shared network
+
+% PGSQL_CB_DELETE_SHARED_NETWORK4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete shared network
+
+% PGSQL_CB_DELETE_SHARED_NETWORK6 delete shared network: %1
+Debug message issued when triggered an action to delete shared network
+
+% PGSQL_CB_DELETE_SHARED_NETWORK6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete shared network
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4 delete shared network: %1 option code: %2 space: %3
+Debug message issued when triggered an action to delete shared network option
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete shared network option
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6 delete shared network: %1 option code: %2 space: %3
+Debug message issued when triggered an action to delete shared network option
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_OPTION6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete shared network option
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4 delete shared network: %1 subnets
+Debug message issued when triggered an action to delete shared network subnets
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS4_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete shared network subnets
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6 delete shared network: %1 subnets
+Debug message issued when triggered an action to delete shared network subnets
+
+% PGSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete shared network subnets
+
+% PGSQL_CB_GET_ALL_CLIENT_CLASSES4 retrieving all client classes
+Debug message issued when triggered an action to retrieve all client classes
+
+% PGSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all client classes
+
+% PGSQL_CB_GET_ALL_CLIENT_CLASSES6 retrieving all client classes
+Debug message issued when triggered an action to retrieve all client classes
+
+% PGSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all client classes
+
+% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 retrieving all global parameters
+Debug message issued when triggered an action to retrieve all global parameters
+
+% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all global parameters
+
+% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 retrieving all global parameters
+Debug message issued when triggered an action to retrieve all global parameters
+
+% PGSQL_CB_GET_ALL_GLOBAL_PARAMETERS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all global parameters
+
+% PGSQL_CB_GET_ALL_OPTIONS4 retrieving all options
+Debug message issued when triggered an action to retrieve all options
+
+% PGSQL_CB_GET_ALL_OPTIONS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all options
+
+% PGSQL_CB_GET_ALL_OPTIONS6 retrieving all options
+Debug message issued when triggered an action to retrieve all options
+
+% PGSQL_CB_GET_ALL_OPTIONS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all options
+
+% PGSQL_CB_GET_ALL_OPTION_DEFS4 retrieving all option definitions
+Debug message issued when triggered an action to retrieve all option definitions
+
+% PGSQL_CB_GET_ALL_OPTION_DEFS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all option definitions
+
+% PGSQL_CB_GET_ALL_OPTION_DEFS6 retrieving all option definitions
+Debug message issued when triggered an action to retrieve all option definitions
+
+% PGSQL_CB_GET_ALL_OPTION_DEFS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all option definitions
+
+% PGSQL_CB_GET_ALL_SERVERS4 retrieving all servers
+Debug message issued when triggered an action to retrieve all DHCPv4
+servers
+
+% PGSQL_CB_GET_ALL_SERVERS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all DHCPv4
+servers
+
+% PGSQL_CB_GET_ALL_SERVERS6 retrieving all DHCPv6 servers
+Debug message issued when triggered an action to retrieve all DHCPv6
+servers
+
+% PGSQL_CB_GET_ALL_SERVERS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all DHCPv6
+servers
+
+% PGSQL_CB_GET_ALL_SHARED_NETWORKS4 retrieving all shared networks
+Debug message issued when triggered an action to retrieve all shared networks
+
+% PGSQL_CB_GET_ALL_SHARED_NETWORKS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all shared networks
+
+% PGSQL_CB_GET_ALL_SHARED_NETWORKS6 retrieving all shared networks
+Debug message issued when triggered an action to retrieve all shared networks
+
+% PGSQL_CB_GET_ALL_SHARED_NETWORKS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all shared networks
+
+% PGSQL_CB_GET_ALL_SUBNETS4 retrieving all subnets
+Debug message issued when triggered an action to retrieve all subnets
+
+% PGSQL_CB_GET_ALL_SUBNETS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all subnets
+
+% PGSQL_CB_GET_ALL_SUBNETS6 retrieving all subnets
+Debug message issued when triggered an action to retrieve all subnets
+
+% PGSQL_CB_GET_ALL_SUBNETS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all subnets
+
+% PGSQL_CB_GET_CLIENT_CLASS4 retrieving client class: %1
+Debug message issued when triggered an action to retrieve a client class
+
+% PGSQL_CB_GET_CLIENT_CLASS6 retrieving client class: %1
+Debug message issued when triggered an action to retrieve a client class
+
+% PGSQL_CB_GET_GLOBAL_PARAMETER4 retrieving global parameter: %1
+Debug message issued when triggered an action to retrieve global parameter
+
+% PGSQL_CB_GET_GLOBAL_PARAMETER6 retrieving global parameter: %1
+Debug message issued when triggered an action to retrieve global parameter
+
+% PGSQL_CB_GET_HOST4 get host
+Debug message issued when triggered an action to retrieve host
+
+% PGSQL_CB_GET_HOST6 get host
+Debug message issued when triggered an action to retrieve host
+
+% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4 retrieving modified client classes from: %1
+Debug message issued when triggered an action to retrieve modified client classes from specified time
+
+% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified client classes from specified time
+
+% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 retrieving modified client classes from: %1
+Debug message issued when triggered an action to retrieve modified client classes from specified time
+
+% PGSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified client classes from specified time
+
+% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 retrieving modified global parameters from: %1
+Debug message issued when triggered an action to retrieve modified global parameters from specified time
+
+% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified global parameters from specified time
+
+% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6 retrieving modified global parameters from: %1
+Debug message issued when triggered an action to retrieve modified global parameters from specified time
+
+% PGSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified global parameters from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTIONS4 retrieving modified options from: %1
+Debug message issued when triggered an action to retrieve modified options from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTIONS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified options from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTIONS6 retrieving modified options from: %1
+Debug message issued when triggered an action to retrieve modified options from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTIONS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified options from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTION_DEFS4 retrieving modified option definitions from: %1
+Debug message issued when triggered an action to retrieve modified option definitions from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTION_DEFS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified option definitions from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTION_DEFS6 retrieving modified option definitions from: %1
+Debug message issued when triggered an action to retrieve modified option definitions from specified time
+
+% PGSQL_CB_GET_MODIFIED_OPTION_DEFS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified option definitions from specified time
+
+% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4 retrieving modified shared networks from: %1
+Debug message issued when triggered an action to retrieve modified shared networks from specified time
+
+% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified shared networks from specified time
+
+% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6 retrieving modified shared networks from: %1
+Debug message issued when triggered an action to retrieve modified shared networks from specified time
+
+% PGSQL_CB_GET_MODIFIED_SHARED_NETWORKS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified shared networks from specified time
+
+% PGSQL_CB_GET_MODIFIED_SUBNETS4 retrieving modified subnets from: %1
+Debug message issued when triggered an action to retrieve modified subnets from specified time
+
+% PGSQL_CB_GET_MODIFIED_SUBNETS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified subnets from specified time
+
+% PGSQL_CB_GET_MODIFIED_SUBNETS6 retrieving modified subnets from: %1
+Debug message issued when triggered an action to retrieve modified subnets from specified time
+
+% PGSQL_CB_GET_MODIFIED_SUBNETS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified subnets from specified time
+
+% PGSQL_CB_GET_OPTION4 retrieving option code: %1 space: %2
+Debug message issued when triggered an action to retrieve option
+
+% PGSQL_CB_GET_OPTION6 retrieving option code: %1 space: %2
+Debug message issued when triggered an action to retrieve option
+
+% PGSQL_CB_GET_OPTION_DEF4 retrieving option definition code: %1 space: %2
+Debug message issued when triggered an action to retrieve option definition
+
+% PGSQL_CB_GET_OPTION_DEF6 retrieving option definition code: %1 space: %2
+Debug message issued when triggered an action to retrieve option definition
+
+% PGSQL_CB_GET_PORT4 get port
+Debug message issued when triggered an action to retrieve port
+
+% PGSQL_CB_GET_PORT6 get port
+Debug message issued when triggered an action to retrieve port
+
+% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4 retrieving audit entries from: %1 %2
+Debug message issued when triggered an action to retrieve audit entries from specified time and id.
+
+% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve audit entries from specified time
+
+% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6 retrieving audit entries from: %1 %2
+Debug message issued when triggered an action to retrieve audit entries from specified time and id
+
+% PGSQL_CB_GET_RECENT_AUDIT_ENTRIES6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve audit entries from specified time
+
+% PGSQL_CB_GET_SERVER4 retrieving DHCPv4 server: %1
+Debug message issued when triggered an action to retrieve a DHCPv4 server information.
+
+% PGSQL_CB_GET_SERVER6 retrieving DHCPv6 server: %1
+Debug message issued when triggered an action to retrieve a DHCPv6 server information.
+
+% PGSQL_CB_GET_SHARED_NETWORK4 retrieving shared network: %1
+Debug message issued when triggered an action to retrieve shared network
+
+% PGSQL_CB_GET_SHARED_NETWORK6 retrieving shared network: %1
+Debug message issued when triggered an action to retrieve shared network
+
+% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4 retrieving shared network: %1 subnets
+Debug message issued when triggered an action to retrieve shared network subnets
+
+% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS4_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve shared network subnets
+
+% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6 retrieving shared network: %1 subnets
+Debug message issued when triggered an action to retrieve shared network subnets
+
+% PGSQL_CB_GET_SHARED_NETWORK_SUBNETS6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve shared network subnets
+
+% PGSQL_CB_GET_SUBNET4_BY_PREFIX retrieving subnet by prefix: %1
+Debug message issued when triggered an action to retrieve subnet by prefix
+
+% PGSQL_CB_GET_SUBNET4_BY_SUBNET_ID retrieving subnet by subnet id: %1
+Debug message issued when triggered an action to retrieve subnet by subnet id
+
+% PGSQL_CB_GET_SUBNET6_BY_PREFIX retrieving subnet by prefix: %1
+Debug message issued when triggered an action to retrieve subnet by prefix
+
+% PGSQL_CB_GET_SUBNET6_BY_SUBNET_ID retrieving subnet by subnet id: %1
+Debug message issued when triggered an action to retrieve subnet by subnet id
+
+% PGSQL_CB_GET_TYPE4 get type
+Debug message issued when triggered an action to retrieve type
+
+% PGSQL_CB_GET_TYPE6 get type
+Debug message issued when triggered an action to retrieve type
+
+% PGSQL_CB_INIT_OK loading Postgres CB hooks library successful
+This informational message indicates that the Postgres Configuration Backend hooks
+library has been loaded successfully. Enjoy!
+
+% PGSQL_CB_NO_TLS_SUPPORT Attempt to configure TLS (unsupported for PostgreSQL): %1
+This error message is printed when TLS support was required in the Kea
+configuration: Kea was built with this feature disabled for PostgreSQL.
+The parameters of the connection are logged.
+
+% PGSQL_CB_RECONNECT_ATTEMPT_FAILED4 database reconnect failed: %1
+Error message issued when an attempt to reconnect has failed.
+
+% PGSQL_CB_RECONNECT_ATTEMPT_FAILED6 database reconnect failed: %1
+Error message issued when an attempt to reconnect has failed.
+
+% PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE4 scheduling attempt %1 of %2 in %3 milliseconds
+Info message issued when the server is scheduling the next attempt to reconnect
+to the database. This occurs when the server has lost database connectivity and
+is attempting to reconnect automatically.
+
+% PGSQL_CB_RECONNECT_ATTEMPT_SCHEDULE6 scheduling attempt %1 of %2 in %3 milliseconds
+Info message issued when the server is scheduling the next attempt to reconnect
+to the database. This occurs when the server has lost database connectivity and
+is attempting to reconnect automatically.
+
+% PGSQL_CB_RECONNECT_FAILED4 maximum number of database reconnect attempts: %1, has been exhausted without success
+Error message issued when the server failed to reconnect. Loss of connectivity
+is typically a network or database server issue.
+
+% PGSQL_CB_RECONNECT_FAILED6 maximum number of database reconnect attempts: %1, has been exhausted without success
+Error message issued when the server failed to reconnect. Loss of connectivity
+is typically a network or database server issue.
+
+% PGSQL_CB_REGISTER_BACKEND_TYPE4 register backend
+Debug message issued when triggered an action to register backend
+
+% PGSQL_CB_REGISTER_BACKEND_TYPE6 register backend
+Debug message issued when triggered an action to register backend
+
+% PGSQL_CB_TLS_SUPPORT Attempt to configure TLS: %1
+This informational message is printed when TLS support was required in
+the Kea configuration: The TLS support in PostgreSQL will be initialized but
+its configuration is fully managed outside the C API.
+The parameters of the connection are logged.
+
+% PGSQL_CB_UNREGISTER_BACKEND_TYPE4 unregister backend
+Debug message issued when triggered an action to unregister backend
+
+% PGSQL_CB_UNREGISTER_BACKEND_TYPE6 unregister backend
+Debug message issued when triggered an action to unregister backend
diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h b/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h
new file mode 100644
index 0000000..f30187c
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/pgsql_query_macros_dhcp.h
@@ -0,0 +1,1391 @@
+// Copyright (C) 2021-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PGSQL_QUERY_MACROS_DHCP_H
+#define PGSQL_QUERY_MACROS_DHCP_H
+
+/// @file pgsql_query_macros_dhcp.h
+/// Collection of common macros defining PgSQL prepared statements used
+/// to manage Kea DHCP configuration in the database.
+///
+/// Some of the macros are DHCPv4 specific, other are DHCPv6 specific.
+/// Some macros are common for both DHCP server types. The first
+/// parameter @c table_prefix should be set to @c dhcp4 or @c dhcp6,
+/// depending which DHCP server type it relates to. Provided value
+/// is used as a prefix for PgSQL table names. For example, if the
+/// prefix is set to @c dhcp4, the table name referred to in the
+/// query may be dhcp4_subnet etc. The second argument in the variadic
+/// macro is a part of the WHERE clause in the PgSQL query. The fixed
+/// part of the WHERE clause is included in the macro.
+namespace isc {
+namespace dhcp {
+
+namespace {
+
+#ifndef PGSQL_GET_GLOBAL_PARAMETER
+#define PGSQL_GET_GLOBAL_PARAMETER(table_prefix, ...) \
+ "SELECT" \
+ " g.id," \
+ " g.name," \
+ " g.value," \
+ " g.parameter_type," \
+ " gmt_epoch(g.modification_ts) as modification_ts, " \
+ " s.tag " \
+ "FROM " #table_prefix "_global_parameter AS g " \
+ "INNER JOIN " #table_prefix "_global_parameter_server AS a " \
+ " ON g.id = a.parameter_id " \
+ "INNER JOIN " #table_prefix "_server AS s " \
+ " ON (a.server_id = s.id) " \
+ "WHERE (s.tag = $1 OR s.id = 1) " #__VA_ARGS__ \
+ " ORDER BY g.id, s.id"
+#endif
+
+#ifndef PGSQL_GET_SUBNET4
+#define PGSQL_GET_SUBNET4_COMMON(server_join, ...) \
+ "SELECT" \
+ " s.subnet_id," \
+ " s.subnet_prefix," \
+ " s.interface_4o6," \
+ " s.interface_id_4o6," \
+ " s.subnet_4o6," \
+ " s.boot_file_name," \
+ " s.client_class," \
+ " s.interface," \
+ " s.match_client_id," \
+ " gmt_epoch(s.modification_ts) as modification_ts, " \
+ " s.next_server," \
+ " s.rebind_timer," \
+ " s.relay," \
+ " s.renew_timer," \
+ " s.require_client_classes," \
+ " s.reservations_global," \
+ " s.server_hostname," \
+ " s.shared_network_name," \
+ " s.user_context," \
+ " s.valid_lifetime," \
+ " p.id," \
+ " p.start_address," \
+ " p.end_address," \
+ " p.subnet_id," \
+ " gmt_epoch(p.modification_ts) as modification_ts, " \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp4_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts, " \
+ " o.option_id," \
+ " o.code," \
+ " o.value," \
+ " o.formatted_value," \
+ " o.space," \
+ " o.persistent," \
+ " o.cancelled," \
+ " o.dhcp4_subnet_id," \
+ " o.scope_id," \
+ " o.user_context," \
+ " o.shared_network_name," \
+ " o.pool_id," \
+ " gmt_epoch(o.modification_ts) as modification_ts, " \
+ " s.calculate_tee_times," \
+ " s.t1_percent," \
+ " s.t2_percent," \
+ " s.authoritative," \
+ " s.min_valid_lifetime," \
+ " s.max_valid_lifetime," \
+ " p.client_class," \
+ " p.require_client_classes," \
+ " p.user_context," \
+ " s.ddns_send_updates," \
+ " s.ddns_override_no_update," \
+ " s.ddns_override_client_update," \
+ " s.ddns_replace_client_name," \
+ " s.ddns_generated_prefix," \
+ " s.ddns_qualifying_suffix," \
+ " s.reservations_in_subnet," \
+ " s.reservations_out_of_pool," \
+ " s.cache_threshold," \
+ " s.cache_max_age," \
+ " s.offer_lifetime," \
+ " s.allocator," \
+ " srv.tag " \
+ "FROM dhcp4_subnet AS s " \
+ server_join \
+ "LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id " \
+ "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id " \
+ #__VA_ARGS__ \
+ " ORDER BY s.subnet_id, p.id, x.option_id, o.option_id"
+
+#define PGSQL_GET_SUBNET4_NO_TAG(...) \
+ PGSQL_GET_SUBNET4_COMMON( \
+ "INNER JOIN dhcp4_subnet_server AS a " \
+ " ON s.subnet_id = a.subnet_id " \
+ "INNER JOIN dhcp4_server AS srv " \
+ " ON (a.server_id = srv.id) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SUBNET4_ANY(...) \
+ PGSQL_GET_SUBNET4_COMMON( \
+ "LEFT JOIN dhcp4_subnet_server AS a "\
+ " ON s.subnet_id = a.subnet_id " \
+ "LEFT JOIN dhcp4_server AS srv " \
+ " ON a.server_id = srv.id ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SUBNET4_UNASSIGNED(...) \
+ PGSQL_GET_SUBNET4_COMMON( \
+ "LEFT JOIN dhcp4_subnet_server AS a "\
+ " ON s.subnet_id = a.subnet_id " \
+ "LEFT JOIN dhcp4_server AS srv " \
+ " ON a.server_id = srv.id ", \
+ WHERE a.subnet_id IS NULL __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_SUBNET6
+#define PGSQL_GET_SUBNET6_COMMON(server_join, ...) \
+ "SELECT" \
+ " s.subnet_id," \
+ " s.subnet_prefix," \
+ " s.client_class," \
+ " s.interface," \
+ " gmt_epoch(s.modification_ts) as modification_ts, " \
+ " s.preferred_lifetime," \
+ " s.rapid_commit," \
+ " s.rebind_timer," \
+ " s.relay," \
+ " s.renew_timer," \
+ " s.require_client_classes," \
+ " s.reservations_global," \
+ " s.shared_network_name," \
+ " s.user_context," \
+ " s.valid_lifetime," \
+ " p.id," \
+ " p.start_address," \
+ " p.end_address," \
+ " p.subnet_id," \
+ " gmt_epoch(p.modification_ts) as modification_ts, " \
+ " d.id," \
+ " d.prefix," \
+ " d.prefix_length," \
+ " d.delegated_prefix_length," \
+ " d.subnet_id," \
+ " gmt_epoch(d.modification_ts) as modification_ts, " \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp6_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts, " \
+ " x.pd_pool_id," \
+ " y.option_id," \
+ " y.code," \
+ " y.value," \
+ " y.formatted_value," \
+ " y.space," \
+ " y.persistent," \
+ " y.cancelled," \
+ " y.dhcp6_subnet_id," \
+ " y.scope_id," \
+ " y.user_context," \
+ " y.shared_network_name," \
+ " y.pool_id," \
+ " gmt_epoch(y.modification_ts) as modification_ts, " \
+ " y.pd_pool_id," \
+ " o.option_id," \
+ " o.code," \
+ " o.value," \
+ " o.formatted_value," \
+ " o.space," \
+ " o.persistent," \
+ " o.cancelled," \
+ " o.dhcp6_subnet_id," \
+ " o.scope_id," \
+ " o.user_context," \
+ " o.shared_network_name," \
+ " o.pool_id," \
+ " gmt_epoch(o.modification_ts) as modification_ts, " \
+ " o.pd_pool_id, " \
+ " s.calculate_tee_times," \
+ " s.t1_percent," \
+ " s.t2_percent," \
+ " s.interface_id," \
+ " s.min_preferred_lifetime," \
+ " s.max_preferred_lifetime," \
+ " s.min_valid_lifetime," \
+ " s.max_valid_lifetime," \
+ " p.client_class," \
+ " p.require_client_classes," \
+ " p.user_context," \
+ " d.excluded_prefix," \
+ " d.excluded_prefix_length," \
+ " d.client_class," \
+ " d.require_client_classes," \
+ " d.user_context," \
+ " s.ddns_send_updates," \
+ " s.ddns_override_no_update," \
+ " s.ddns_override_client_update," \
+ " s.ddns_replace_client_name," \
+ " s.ddns_generated_prefix," \
+ " s.ddns_qualifying_suffix," \
+ " s.reservations_in_subnet," \
+ " s.reservations_out_of_pool," \
+ " s.cache_threshold," \
+ " s.cache_max_age," \
+ " s.allocator," \
+ " s.pd_allocator," \
+ " srv.tag " \
+ "FROM dhcp6_subnet AS s " \
+ server_join \
+ "LEFT JOIN dhcp6_pool AS p ON s.subnet_id = p.subnet_id " \
+ "LEFT JOIN dhcp6_pd_pool AS d ON s.subnet_id = d.subnet_id " \
+ "LEFT JOIN dhcp6_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \
+ "LEFT JOIN dhcp6_options AS y ON y.scope_id = 6 AND d.id = y.pd_pool_id " \
+ "LEFT JOIN dhcp6_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp6_subnet_id " \
+ #__VA_ARGS__ \
+ " ORDER BY s.subnet_id, p.id, d.id, x.option_id, y.option_id, o.option_id"
+
+#define PGSQL_GET_SUBNET6_NO_TAG(...) \
+ PGSQL_GET_SUBNET6_COMMON( \
+ "INNER JOIN dhcp6_subnet_server AS a " \
+ " ON s.subnet_id = a.subnet_id " \
+ "INNER JOIN dhcp6_server AS srv " \
+ " ON (a.server_id = srv.id) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SUBNET6_ANY(...) \
+ PGSQL_GET_SUBNET6_COMMON( \
+ "LEFT JOIN dhcp6_subnet_server AS a "\
+ " ON s.subnet_id = a.subnet_id " \
+ "LEFT JOIN dhcp6_server AS srv " \
+ " ON a.server_id = srv.id ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SUBNET6_UNASSIGNED(...) \
+ PGSQL_GET_SUBNET6_COMMON( \
+ "LEFT JOIN dhcp6_subnet_server AS a "\
+ " ON s.subnet_id = a.subnet_id " \
+ "LEFT JOIN dhcp6_server AS srv " \
+ " ON a.server_id = srv.id ", \
+ WHERE a.subnet_id IS NULL __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_POOL4_COMMON
+#define PGSQL_GET_POOL4_COMMON(server_join, ...) \
+ "SELECT" \
+ " p.id," \
+ " p.start_address," \
+ " p.end_address," \
+ " p.subnet_id," \
+ " p.client_class," \
+ " p.require_client_classes," \
+ " p.user_context," \
+ " gmt_epoch(p.modification_ts) as modification_ts, " \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp4_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts " \
+ "FROM dhcp4_pool AS p " \
+ server_join \
+ "LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \
+ #__VA_ARGS__ \
+ " ORDER BY p.id, x.option_id"
+
+#define PGSQL_GET_POOL4_RANGE_WITH_TAG(...) \
+ PGSQL_GET_POOL4_COMMON( \
+ "INNER JOIN dhcp4_subnet_server AS s ON p.subnet_id = s.subnet_id " \
+ "INNER JOIN dhcp4_server AS srv " \
+ " ON (s.server_id = srv.id) OR (s.server_id = 1) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_POOL4_RANGE_NO_TAG(...) \
+ PGSQL_GET_POOL4_COMMON("", __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_POOL6_COMMON
+#define PGSQL_GET_POOL6_COMMON(server_join, ...) \
+ "SELECT" \
+ " p.id," \
+ " p.start_address," \
+ " p.end_address," \
+ " p.subnet_id," \
+ " p.client_class," \
+ " p.require_client_classes," \
+ " p.user_context," \
+ " gmt_epoch(p.modification_ts) as modification_ts, " \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp6_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts, " \
+ " x.pd_pool_id " \
+ "FROM dhcp6_pool AS p " \
+ server_join \
+ "LEFT JOIN dhcp6_options AS x ON x.scope_id = 5 AND p.id = x.pool_id " \
+ #__VA_ARGS__ \
+ " ORDER BY p.id, x.option_id"
+
+#define PGSQL_GET_POOL6_RANGE_WITH_TAG(...) \
+ PGSQL_GET_POOL6_COMMON( \
+ "INNER JOIN dhcp6_subnet_server AS s ON p.subnet_id = s.subnet_id " \
+ "INNER JOIN dhcp6_server AS srv " \
+ " ON (s.server_id = srv.id) OR (s.server_id = 1) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_POOL6_RANGE_NO_TAG(...) \
+ PGSQL_GET_POOL6_COMMON("", __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_PD_POOL_COMMON
+#define PGSQL_GET_PD_POOL_COMMON(server_join, ...) \
+ "SELECT" \
+ " p.id," \
+ " p.prefix," \
+ " p.prefix_length," \
+ " p.delegated_prefix_length," \
+ " p.subnet_id," \
+ " p.excluded_prefix," \
+ " p.excluded_prefix_length," \
+ " p.client_class," \
+ " p.require_client_classes," \
+ " p.user_context," \
+ " gmt_epoch(p.modification_ts) as modification_ts, " \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp6_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts, " \
+ " x.pd_pool_id " \
+ "FROM dhcp6_pd_pool AS p " \
+ server_join \
+ "LEFT JOIN dhcp6_options AS x ON x.scope_id = 6 AND p.id = x.pd_pool_id " \
+ #__VA_ARGS__ \
+ " ORDER BY p.id, x.option_id" \
+
+#define PGSQL_GET_PD_POOL_WITH_TAG(...) \
+ PGSQL_GET_PD_POOL_COMMON( \
+ "INNER JOIN dhcp6_subnet_server AS s ON p.subnet_id = s.subnet_id " \
+ "INNER JOIN dhcp6_server AS srv " \
+ " ON (s.server_id = srv.id) OR (s.server_id = 1) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_PD_POOL_NO_TAG(...) \
+ PGSQL_GET_PD_POOL_COMMON("", __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_SHARED_NETWORK4
+#define PGSQL_GET_SHARED_NETWORK4_COMMON(server_join, ...) \
+ "SELECT" \
+ " n.id," \
+ " n.name," \
+ " n.client_class," \
+ " n.interface," \
+ " n.match_client_id," \
+ " gmt_epoch(n.modification_ts) as modification_ts, " \
+ " n.rebind_timer," \
+ " n.relay," \
+ " n.renew_timer," \
+ " n.require_client_classes," \
+ " n.reservations_global," \
+ " n.user_context," \
+ " n.valid_lifetime," \
+ " o.option_id," \
+ " o.code," \
+ " o.value," \
+ " o.formatted_value," \
+ " o.space," \
+ " o.persistent," \
+ " o.cancelled," \
+ " o.dhcp4_subnet_id," \
+ " o.scope_id," \
+ " o.user_context," \
+ " o.shared_network_name," \
+ " o.pool_id," \
+ " gmt_epoch(o.modification_ts) as modification_ts, " \
+ " n.calculate_tee_times," \
+ " n.t1_percent," \
+ " n.t2_percent," \
+ " n.authoritative," \
+ " n.boot_file_name," \
+ " n.next_server," \
+ " n.server_hostname," \
+ " n.min_valid_lifetime," \
+ " n.max_valid_lifetime," \
+ " n.ddns_send_updates," \
+ " n.ddns_override_no_update," \
+ " n.ddns_override_client_update," \
+ " n.ddns_replace_client_name," \
+ " n.ddns_generated_prefix," \
+ " n.ddns_qualifying_suffix," \
+ " n.reservations_in_subnet," \
+ " n.reservations_out_of_pool," \
+ " n.cache_threshold," \
+ " n.cache_max_age," \
+ " n.offer_lifetime," \
+ " n.allocator," \
+ " s.tag " \
+ "FROM dhcp4_shared_network AS n " \
+ server_join \
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name " \
+ #__VA_ARGS__ \
+ " ORDER BY n.id, s.id, o.option_id"
+
+#define PGSQL_GET_SHARED_NETWORK4_NO_TAG(...) \
+ PGSQL_GET_SHARED_NETWORK4_COMMON( \
+ "INNER JOIN dhcp4_shared_network_server AS a " \
+ " ON n.id = a.shared_network_id " \
+ "INNER JOIN dhcp4_server AS s " \
+ " ON (a.server_id = s.id) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SHARED_NETWORK4_ANY(...) \
+ PGSQL_GET_SHARED_NETWORK4_COMMON( \
+ "LEFT JOIN dhcp4_shared_network_server AS a " \
+ " ON n.id = a.shared_network_id " \
+ "LEFT JOIN dhcp4_server AS s " \
+ " ON a.server_id = s.id ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SHARED_NETWORK4_UNASSIGNED(...) \
+ PGSQL_GET_SHARED_NETWORK4_COMMON( \
+ "LEFT JOIN dhcp4_shared_network_server AS a " \
+ " ON n.id = a.shared_network_id " \
+ "LEFT JOIN dhcp4_server AS s " \
+ " ON a.server_id = s.id ", \
+ WHERE a.shared_network_id IS NULL __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_SHARED_NETWORK6
+#define PGSQL_GET_SHARED_NETWORK6_COMMON(server_join, ...) \
+ "SELECT" \
+ " n.id," \
+ " n.name," \
+ " n.client_class," \
+ " n.interface," \
+ " gmt_epoch(n.modification_ts) as modification_ts, " \
+ " n.preferred_lifetime," \
+ " n.rapid_commit," \
+ " n.rebind_timer," \
+ " n.relay," \
+ " n.renew_timer," \
+ " n.require_client_classes," \
+ " n.reservations_global," \
+ " n.user_context," \
+ " n.valid_lifetime," \
+ " o.option_id," \
+ " o.code," \
+ " o.value," \
+ " o.formatted_value," \
+ " o.space," \
+ " o.persistent," \
+ " o.cancelled," \
+ " o.dhcp6_subnet_id," \
+ " o.scope_id," \
+ " o.user_context," \
+ " o.shared_network_name," \
+ " o.pool_id," \
+ " gmt_epoch(o.modification_ts) as modification_ts, " \
+ " o.pd_pool_id, " \
+ " n.calculate_tee_times," \
+ " n.t1_percent," \
+ " n.t2_percent," \
+ " n.interface_id," \
+ " n.min_preferred_lifetime," \
+ " n.max_preferred_lifetime," \
+ " n.min_valid_lifetime," \
+ " n.max_valid_lifetime," \
+ " n.ddns_send_updates," \
+ " n.ddns_override_no_update," \
+ " n.ddns_override_client_update," \
+ " n.ddns_replace_client_name," \
+ " n.ddns_generated_prefix," \
+ " n.ddns_qualifying_suffix," \
+ " n.reservations_in_subnet," \
+ " n.reservations_out_of_pool," \
+ " n.cache_threshold," \
+ " n.cache_max_age," \
+ " n.allocator," \
+ " n.pd_allocator," \
+ " s.tag " \
+ "FROM dhcp6_shared_network AS n " \
+ server_join \
+ "LEFT JOIN dhcp6_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name " \
+ #__VA_ARGS__ \
+ " ORDER BY n.id, s.id, o.option_id"
+
+#define PGSQL_GET_SHARED_NETWORK6_NO_TAG(...) \
+ PGSQL_GET_SHARED_NETWORK6_COMMON( \
+ "INNER JOIN dhcp6_shared_network_server AS a " \
+ " ON n.id = a.shared_network_id " \
+ "INNER JOIN dhcp6_server AS s " \
+ " ON (a.server_id = s.id) ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SHARED_NETWORK6_ANY(...) \
+ PGSQL_GET_SHARED_NETWORK6_COMMON( \
+ "LEFT JOIN dhcp6_shared_network_server AS a " \
+ " ON n.id = a.shared_network_id " \
+ "LEFT JOIN dhcp6_server AS s " \
+ " ON a.server_id = s.id ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_SHARED_NETWORK6_UNASSIGNED(...) \
+ PGSQL_GET_SHARED_NETWORK6_COMMON( \
+ "LEFT JOIN dhcp6_shared_network_server AS a " \
+ " ON n.id = a.shared_network_id " \
+ "LEFT JOIN dhcp6_server AS s " \
+ " ON a.server_id = s.id ", \
+ WHERE a.shared_network_id IS NULL __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_OPTION_DEF
+#define PGSQL_GET_OPTION_DEF(table_prefix, ...) \
+ "SELECT" \
+ " d.id," \
+ " d.code," \
+ " d.name," \
+ " d.space," \
+ " d.type," \
+ " gmt_epoch(d.modification_ts) as modification_ts, " \
+ " d.is_array," \
+ " d.encapsulate," \
+ " d.record_types," \
+ " d.user_context," \
+ " s.tag " \
+ "FROM " #table_prefix "_option_def AS d " \
+ "INNER JOIN " #table_prefix "_option_def_server AS a" \
+ " ON d.id = a.option_def_id " \
+ "INNER JOIN " #table_prefix "_server AS s " \
+ " ON a.server_id = s.id " \
+ "WHERE (s.tag = $1 OR s.id = 1) " #__VA_ARGS__ \
+ " ORDER BY d.id"
+#endif
+
+#ifndef PGSQL_GET_OPTION_COMMON
+#define PGSQL_GET_OPTION_COMMON(table_prefix, pd_pool_id, ...) \
+ "SELECT" \
+ " o.option_id," \
+ " o.code," \
+ " o.value," \
+ " o.formatted_value," \
+ " o.space," \
+ " o.persistent," \
+ " o.cancelled," \
+ " o." #table_prefix "_subnet_id," \
+ " o.scope_id," \
+ " o.user_context," \
+ " o.shared_network_name," \
+ " o.pool_id," \
+ " gmt_epoch(o.modification_ts) as modification_ts, " \
+ " s.tag " \
+ pd_pool_id \
+ "FROM " #table_prefix "_options AS o " \
+ "INNER JOIN " #table_prefix "_options_server AS a" \
+ " ON o.option_id = a.option_id " \
+ "INNER JOIN " #table_prefix "_server AS s" \
+ " ON a.server_id = s.id " \
+ "WHERE (s.tag = $1 OR s.id = 1) " #__VA_ARGS__ \
+ " ORDER BY o.option_id, s.id"
+
+#define PGSQL_GET_OPTION4(...) \
+ PGSQL_GET_OPTION_COMMON(dhcp4, "", __VA_ARGS__)
+
+#define PGSQL_GET_OPTION6(...) \
+ PGSQL_GET_OPTION_COMMON(dhcp6, ", o.pd_pool_id ", __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_AUDIT_ENTRIES_TIME
+#define PGSQL_GET_AUDIT_ENTRIES_TIME(table_prefix) \
+ "SELECT" \
+ " a.id," \
+ " a.object_type," \
+ " a.object_id," \
+ " a.modification_type," \
+ " gmt_epoch(r.modification_ts) as modification_ts, " \
+ " r.id, " \
+ " r.log_message " \
+ "FROM " #table_prefix "_audit AS a " \
+ "INNER JOIN " #table_prefix "_audit_revision AS r " \
+ " ON a.revision_id = r.id " \
+ "INNER JOIN " #table_prefix "_server AS s" \
+ " ON r.server_id = s.id " \
+ "WHERE (s.tag = $1 OR s.id = 1) AND ((r.modification_ts, r.id) > (cast($2 as timestamp), $3))" \
+ " ORDER BY r.modification_ts, r.id, a.id"
+#endif
+
+#ifndef PGSQL_GET_SERVERS_COMMON
+#define PGSQL_GET_SERVERS_COMMON(table_prefix, ...) \
+ "SELECT" \
+ " s.id," \
+ " s.tag," \
+ " s.description," \
+ " gmt_epoch(s.modification_ts) as modification_ts " \
+ "FROM " #table_prefix "_server AS s " \
+ "WHERE s.id > 1 " \
+ __VA_ARGS__ \
+ " ORDER BY s.id"
+
+#define PGSQL_GET_ALL_SERVERS(table_prefix) \
+ PGSQL_GET_SERVERS_COMMON(table_prefix, "")
+
+#define PGSQL_GET_SERVER(table_prefix) \
+ PGSQL_GET_SERVERS_COMMON(table_prefix, " AND s.tag = $1")
+#endif
+
+#ifndef PGSQL_GET_CLIENT_CLASS4_COMMON
+#define PGSQL_GET_CLIENT_CLASS4_COMMON(server_join, ...) \
+ "SELECT " \
+ " c.id," \
+ " c.name," \
+ " c.test," \
+ " c.next_server," \
+ " c.server_hostname," \
+ " c.boot_file_name," \
+ " c.only_if_required," \
+ " c.valid_lifetime," \
+ " c.min_valid_lifetime," \
+ " c.max_valid_lifetime," \
+ " c.depend_on_known_directly," \
+ " o.depend_on_known_indirectly, " \
+ " gmt_epoch(c.modification_ts) as modification_ts, " \
+ " c.user_context," \
+ " c.offer_lifetime," \
+ " d.id," \
+ " d.code," \
+ " d.name," \
+ " d.space," \
+ " d.type," \
+ " gmt_epoch(d.modification_ts) as modification_ts, " \
+ " d.is_array," \
+ " d.encapsulate," \
+ " d.record_types," \
+ " d.user_context," \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp4_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts, " \
+ " s.tag " \
+ "FROM dhcp4_client_class AS c " \
+ "INNER JOIN dhcp4_client_class_order AS o " \
+ " ON c.id = o.class_id " \
+ server_join \
+ "LEFT JOIN dhcp4_option_def AS d ON c.id = d.class_id " \
+ "LEFT JOIN dhcp4_options AS x ON x.scope_id = 2 AND c.name = x.dhcp_client_class " \
+ #__VA_ARGS__ \
+ " ORDER BY o.order_index, d.id, x.option_id"
+
+#define PGSQL_GET_CLIENT_CLASS4_WITH_TAG(...) \
+ PGSQL_GET_CLIENT_CLASS4_COMMON( \
+ "INNER JOIN dhcp4_client_class_server AS a " \
+ " ON c.id = a.class_id " \
+ "INNER JOIN dhcp4_server AS s " \
+ " ON a.server_id = s.id ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_CLIENT_CLASS4_UNASSIGNED(...) \
+ PGSQL_GET_CLIENT_CLASS4_COMMON( \
+ "LEFT JOIN dhcp4_client_class_server AS a " \
+ " ON c.id = a.class_id " \
+ "LEFT JOIN dhcp4_server AS s " \
+ " ON a.server_id = s.id ", \
+ WHERE a.class_id IS NULL __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_GET_CLIENT_CLASS6_COMMON
+#define PGSQL_GET_CLIENT_CLASS6_COMMON(server_join, ...) \
+ "SELECT " \
+ " c.id," \
+ " c.name," \
+ " c.test," \
+ " c.only_if_required," \
+ " c.valid_lifetime," \
+ " c.min_valid_lifetime," \
+ " c.max_valid_lifetime," \
+ " c.depend_on_known_directly," \
+ " o.depend_on_known_indirectly, " \
+ " gmt_epoch(c.modification_ts) as modification_ts, " \
+ " c.user_context, " \
+ " d.id," \
+ " d.code," \
+ " d.name," \
+ " d.space," \
+ " d.type," \
+ " gmt_epoch(d.modification_ts) as modification_ts, " \
+ " d.is_array," \
+ " d.encapsulate," \
+ " d.record_types," \
+ " d.user_context," \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.cancelled," \
+ " x.dhcp6_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " gmt_epoch(x.modification_ts) as modification_ts, " \
+ " s.tag, " \
+ " c.preferred_lifetime," \
+ " c.min_preferred_lifetime, " \
+ " c.max_preferred_lifetime " \
+ "FROM dhcp6_client_class AS c " \
+ "INNER JOIN dhcp6_client_class_order AS o " \
+ " ON c.id = o.class_id " \
+ server_join \
+ "LEFT JOIN dhcp6_option_def AS d ON c.id = d.class_id " \
+ "LEFT JOIN dhcp6_options AS x ON x.scope_id = 2 AND c.name = x.dhcp_client_class " \
+ #__VA_ARGS__ \
+ " ORDER BY o.order_index, d.id, x.option_id"
+
+#define PGSQL_GET_CLIENT_CLASS6_WITH_TAG(...) \
+ PGSQL_GET_CLIENT_CLASS6_COMMON( \
+ "INNER JOIN dhcp6_client_class_server AS a " \
+ " ON c.id = a.class_id " \
+ "INNER JOIN dhcp6_server AS s " \
+ " ON a.server_id = s.id ", \
+ __VA_ARGS__)
+
+#define PGSQL_GET_CLIENT_CLASS6_UNASSIGNED(...) \
+ PGSQL_GET_CLIENT_CLASS6_COMMON( \
+ "LEFT JOIN dhcp6_client_class_server AS a " \
+ " ON c.id = a.class_id " \
+ "LEFT JOIN dhcp6_server AS s " \
+ " ON a.server_id = s.id ", \
+ WHERE a.class_id IS NULL __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_INSERT_GLOBAL_PARAMETER
+#define PGSQL_INSERT_GLOBAL_PARAMETER(table_prefix) \
+ "INSERT INTO " #table_prefix "_global_parameter(" \
+ " name," \
+ " value," \
+ " parameter_type," \
+ " modification_ts" \
+ ") VALUES ($1, $2, $3, $4)"
+#endif
+
+#ifndef PGSQL_INSERT_GLOBAL_PARAMETER_SERVER
+#define PGSQL_INSERT_GLOBAL_PARAMETER_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_global_parameter_server(" \
+ " parameter_id," \
+ " modification_ts," \
+ " server_id" \
+ ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))"
+#endif
+
+#ifndef PGSQL_INSERT_SUBNET_SERVER
+#define PGSQL_INSERT_SUBNET_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_subnet_server(" \
+ " subnet_id," \
+ " modification_ts," \
+ " server_id" \
+ ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))"
+#endif
+
+#ifndef PGSQL_INSERT_POOL
+#define PGSQL_INSERT_POOL(table_prefix) \
+ "INSERT INTO " #table_prefix "_pool(" \
+ " start_address," \
+ " end_address," \
+ " subnet_id," \
+ " client_class," \
+ " require_client_classes," \
+ " user_context," \
+ " modification_ts" \
+ ") VALUES (cast($1 as inet), cast($2 as inet), $3, $4, $5, cast($6 as json), $7)"
+#endif
+
+#ifndef PGSQL_INSERT_PD_POOL
+#define PGSQL_INSERT_PD_POOL() \
+ "INSERT INTO dhcp6_pd_pool(" \
+ " prefix," \
+ " prefix_length," \
+ " delegated_prefix_length," \
+ " subnet_id," \
+ " excluded_prefix," \
+ " excluded_prefix_length," \
+ " client_class," \
+ " require_client_classes," \
+ " user_context," \
+ " modification_ts" \
+ ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), $10)"
+#endif
+
+#ifndef PGSQL_INSERT_SHARED_NETWORK_SERVER
+#define PGSQL_INSERT_SHARED_NETWORK_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_shared_network_server(" \
+ " shared_network_id," \
+ " modification_ts," \
+ " server_id" \
+ ") VALUES (" \
+ " (SELECT id FROM " #table_prefix "_shared_network WHERE name = $1), $2," \
+ " (SELECT id FROM " #table_prefix "_server WHERE tag = $3)" \
+ ")"
+#endif
+
+#ifndef PGSQL_INSERT_OPTION_DEF
+#define PGSQL_INSERT_OPTION_DEF(table_prefix) \
+ "INSERT INTO " #table_prefix "_option_def (" \
+ " code," \
+ " name," \
+ " space," \
+ " type," \
+ " modification_ts," \
+ " is_array," \
+ " encapsulate," \
+ " record_types," \
+ " user_context," \
+ " class_id" \
+ ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), $10)"
+#endif
+
+#ifndef PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS
+#define PGSQL_INSERT_OPTION_DEF_CLIENT_CLASS(table_prefix) \
+ "INSERT INTO " #table_prefix "_option_def (" \
+ " code," \
+ " name," \
+ " space," \
+ " type," \
+ " modification_ts," \
+ " is_array," \
+ " encapsulate," \
+ " record_types," \
+ " user_context," \
+ " class_id" \
+ ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, cast($9 as json), " \
+ " (SELECT id FROM " #table_prefix "_client_class WHERE name = $10))"
+#endif
+
+#ifndef PGSQL_INSERT_OPTION_DEF_SERVER
+#define PGSQL_INSERT_OPTION_DEF_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_option_def_server(" \
+ " option_def_id," \
+ " modification_ts," \
+ " server_id" \
+ ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))"
+#endif
+
+#ifndef PGSQL_INSERT_OPTION_COMMON
+#define PGSQL_INSERT_OPTION_COMMON(table_prefix, pd_pool_id, last) \
+ "INSERT INTO " #table_prefix "_options (" \
+ " code," \
+ " value," \
+ " formatted_value," \
+ " space," \
+ " persistent," \
+ " cancelled," \
+ " dhcp_client_class," \
+ " " #table_prefix "_subnet_id," \
+ " scope_id," \
+ " user_context," \
+ " shared_network_name," \
+ " pool_id," \
+ " modification_ts" \
+ pd_pool_id \
+ ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, cast($10 as json), $11, $12, $13" last ")"
+
+#define PGSQL_INSERT_OPTION4() \
+ PGSQL_INSERT_OPTION_COMMON(dhcp4, "", "")
+
+#define PGSQL_INSERT_OPTION6() \
+ PGSQL_INSERT_OPTION_COMMON(dhcp6, ", pd_pool_id ", ", $14")
+#endif
+
+#ifndef PGSQL_INSERT_OPTION_SERVER
+#define PGSQL_INSERT_OPTION_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_options_server (" \
+ " option_id," \
+ " modification_ts," \
+ " server_id" \
+ ") VALUES ($1, $2, (SELECT id FROM " #table_prefix "_server WHERE tag = $3))"
+#endif
+
+#ifndef PGSQL_INSERT_CLIENT_CLASS_SERVER
+#define PGSQL_INSERT_CLIENT_CLASS_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_client_class_server (" \
+ " class_id," \
+ " modification_ts," \
+ " server_id" \
+ ") VALUES ((SELECT id FROM " #table_prefix "_client_class WHERE name = $1), $2," \
+ " (SELECT id FROM " #table_prefix "_server WHERE tag = $3))"
+#endif
+
+#ifndef PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY
+#define PGSQL_INSERT_CLIENT_CLASS_DEPENDENCY(table_prefix) \
+ "INSERT INTO " #table_prefix "_client_class_dependency (" \
+ " class_id," \
+ " dependency_id" \
+ ") VALUES ((SELECT id FROM " #table_prefix "_client_class WHERE name = $1), " \
+ " (SELECT id FROM " #table_prefix "_client_class WHERE name = $2))"
+#endif
+
+#ifndef PGSQL_INSERT_SERVER
+#define PGSQL_INSERT_SERVER(table_prefix) \
+ "INSERT INTO " #table_prefix "_server (" \
+ " tag," \
+ " description," \
+ " modification_ts" \
+ ") VALUES ($1, $2, $3)"
+#endif
+
+#ifndef PGSQL_UPDATE_GLOBAL_PARAMETER
+#define PGSQL_UPDATE_GLOBAL_PARAMETER(table_prefix) \
+ "UPDATE " #table_prefix "_global_parameter AS g " \
+ "SET " \
+ " name = $1, " \
+ " value = $2, " \
+ " parameter_type = $3, " \
+ " modification_ts = $4 " \
+ "FROM " #table_prefix "_global_parameter_server as a, " \
+ " " #table_prefix "_server as s " \
+ "WHERE g.id = a.parameter_id AND " \
+ " a.server_id = s.id AND " \
+ " s.tag = $5 AND g.name = $6"
+#endif
+
+#ifndef PGSQL_UPDATE_OPTION_DEF
+#define PGSQL_UPDATE_OPTION_DEF(table_prefix) \
+ "UPDATE " #table_prefix "_option_def AS d " \
+ "SET" \
+ " code = $1," \
+ " name = $2," \
+ " space = $3," \
+ " type = $4," \
+ " modification_ts = $5," \
+ " is_array = $6," \
+ " encapsulate = $7," \
+ " record_types = $8," \
+ " user_context = cast($9 as json), " \
+ " class_id = $10 " \
+ "FROM " #table_prefix "_option_def_server as a, " \
+ " " #table_prefix "_server as s " \
+ "WHERE d.id = a.option_def_id AND" \
+ " a.server_id = s.id AND " \
+ " s.tag = $11 AND d.code = $12 AND d.space = $13"
+#endif
+
+#ifndef PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS
+#define PGSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(table_prefix) \
+ "UPDATE " #table_prefix "_option_def AS d " \
+ "SET" \
+ " code = $1," \
+ " name = $2," \
+ " space = $3," \
+ " type = $4," \
+ " modification_ts = $5," \
+ " is_array = $6," \
+ " encapsulate = $7," \
+ " record_types = $8," \
+ " user_context = cast($9 as json) " \
+ "FROM " #table_prefix "_option_def_server as a, " \
+ " " #table_prefix "_server as s " \
+ "WHERE d.id = a.option_def_id AND " \
+ " a.server_id = s.id AND " \
+ " d.class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = $10) " \
+ " AND s.tag = $11 AND d.code = $12 AND d.space = $13"
+#endif
+
+#ifndef PGSQL_UPDATE_OPTION_NO_TAG
+#define PGSQL_UPDATE_OPTION_NO_TAG(table_prefix, pd_pool_id, ...) \
+ "UPDATE " #table_prefix "_options AS o " \
+ "SET" \
+ " code = $1," \
+ " value = $2," \
+ " formatted_value = $3," \
+ " space = $4," \
+ " persistent = $5," \
+ " cancelled = $6," \
+ " dhcp_client_class = $7," \
+ " " #table_prefix "_subnet_id = $8," \
+ " scope_id = $9," \
+ " user_context = cast($10 as json)," \
+ " shared_network_name = $11," \
+ " pool_id = $12," \
+ " modification_ts = $13 " \
+ pd_pool_id \
+ "WHERE " #__VA_ARGS__
+
+#define PGSQL_UPDATE_OPTION4_NO_TAG(...) \
+ PGSQL_UPDATE_OPTION_NO_TAG(dhcp4, "", __VA_ARGS__)
+
+#define PGSQL_UPDATE_OPTION6_NO_TAG(...) \
+ PGSQL_UPDATE_OPTION_NO_TAG(dhcp6, ", pd_pool_id = $14 ", __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_UPDATE_OPTION_WITH_TAG
+#define PGSQL_UPDATE_OPTION_WITH_TAG(table_prefix, pd_pool_id, ...) \
+ "UPDATE " #table_prefix "_options AS o " \
+ "SET" \
+ " code = $1," \
+ " value = $2," \
+ " formatted_value = $3," \
+ " space = $4," \
+ " persistent = $5," \
+ " cancelled = $6," \
+ " dhcp_client_class = $7," \
+ " " #table_prefix "_subnet_id = $8," \
+ " scope_id = $9," \
+ " user_context = cast($10 as json)," \
+ " shared_network_name = $11," \
+ " pool_id = $12," \
+ " modification_ts = $13 " \
+ pd_pool_id \
+ "FROM " #table_prefix "_options_server as a, " \
+ " " #table_prefix "_server as s " \
+ "WHERE o.option_id = a.option_id AND " \
+ " a.server_id = s.id " \
+ #__VA_ARGS__
+
+#define PGSQL_UPDATE_OPTION4_WITH_TAG(...) \
+ PGSQL_UPDATE_OPTION_WITH_TAG(dhcp4, "", AND s.tag = $14 __VA_ARGS__)
+
+#define PGSQL_UPDATE_OPTION6_WITH_TAG(...) \
+ PGSQL_UPDATE_OPTION_WITH_TAG(dhcp6, \
+ ", pd_pool_id = $14 ", AND s.tag = $15 __VA_ARGS__)
+#endif
+
+#ifndef PGSQL_UPDATE_CLIENT_CLASS4
+#define PGSQL_UPDATE_CLIENT_CLASS4(follow_class_name_set) \
+ "UPDATE dhcp4_client_class SET" \
+ " name = $1," \
+ " test = $2," \
+ " next_server = cast($3 as inet)," \
+ " server_hostname = $4," \
+ " boot_file_name = $5," \
+ " only_if_required = $6," \
+ " valid_lifetime = $7," \
+ " min_valid_lifetime = $8," \
+ " max_valid_lifetime = $9," \
+ " depend_on_known_directly = $10," \
+ follow_class_name_set \
+ " modification_ts = $12, " \
+ " user_context = cast($13 as json), " \
+ " offer_lifetime = $14 " \
+ "WHERE name = $15"
+#endif
+
+#ifndef PGSQL_UPDATE_CLIENT_CLASS6
+#define PGSQL_UPDATE_CLIENT_CLASS6(follow_class_name_set) \
+ "UPDATE dhcp6_client_class SET" \
+ " name = $1," \
+ " test = $2," \
+ " only_if_required = $3," \
+ " valid_lifetime = $4," \
+ " min_valid_lifetime = $5," \
+ " max_valid_lifetime = $6," \
+ " depend_on_known_directly = $7," \
+ follow_class_name_set \
+ " preferred_lifetime = $9, " \
+ " min_preferred_lifetime = $10, " \
+ " max_preferred_lifetime = $11, " \
+ " modification_ts = $12, " \
+ " user_context = cast($13 as json) " \
+ "WHERE name = $14"
+#endif
+
+#ifndef PGSQL_UPDATE_SERVER
+#define PGSQL_UPDATE_SERVER(table_prefix) \
+ "UPDATE " #table_prefix "_server " \
+ "SET" \
+ " tag = $1," \
+ " description = $2," \
+ " modification_ts = $3 " \
+ "WHERE tag = $4"
+#endif
+
+#ifndef PGSQL_DELETE_GLOBAL_PARAMETER
+#define PGSQL_DELETE_GLOBAL_PARAMETER(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_global_parameter AS g " \
+ "USING " \
+ " " #table_prefix "_global_parameter_server AS a, " \
+ " " #table_prefix "_server AS s " \
+ "WHERE " \
+ " g.id = a.parameter_id AND " \
+ " a.server_id = s.id AND " \
+ " s.tag = $1 " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED
+#define PGSQL_DELETE_GLOBAL_PARAMETER_UNASSIGNED(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_global_parameter AS g " \
+ "WHERE g.id in ( " \
+ " SELECT g.id FROM " #table_prefix "_global_parameter AS g " \
+ " LEFT JOIN " #table_prefix "_global_parameter_server AS a ON g.id = a.parameter_id " \
+ " WHERE a.parameter_id IS NULL) " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_SUBNET_COMMON
+#define PGSQL_DELETE_SUBNET_COMMON(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_subnet AS s " \
+ "USING " \
+ " " #table_prefix "_subnet_server AS a, " \
+ " " #table_prefix "_server AS srv " \
+ "WHERE " \
+ " s.subnet_id = a.subnet_id AND " \
+ " a.server_id = srv.id " \
+ #__VA_ARGS__
+
+#define PGSQL_DELETE_SUBNET_WITH_TAG(table_prefix, ...) \
+ PGSQL_DELETE_SUBNET_COMMON(table_prefix, AND srv.tag = $1 __VA_ARGS__)
+
+#define PGSQL_DELETE_SUBNET_ANY(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_subnet AS s " \
+ #__VA_ARGS__
+
+#define PGSQL_DELETE_SUBNET_UNASSIGNED(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_subnet AS s " \
+ "WHERE s.subnet_id in ( " \
+ " SELECT s.subnet_id FROM " #table_prefix "_subnet AS s " \
+ " LEFT JOIN " #table_prefix "_subnet_server AS a ON s.subnet_id = a.subnet_id " \
+ " WHERE a.subnet_id IS NULL) " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_SUBNET_SERVER
+#define PGSQL_DELETE_SUBNET_SERVER(table_prefix) \
+ "DELETE FROM " #table_prefix "_subnet_server " \
+ "WHERE subnet_id = $1"
+#endif
+
+#ifndef PGSQL_DELETE_POOLS
+#define PGSQL_DELETE_POOLS(table_prefix) \
+ "DELETE FROM " #table_prefix "_pool " \
+ "WHERE subnet_id = $1 OR subnet_id = " \
+ "(SELECT subnet_id FROM " #table_prefix "_subnet" \
+ " WHERE subnet_prefix = $2)"
+#endif
+
+#ifndef PGSQL_DELETE_PD_POOLS
+#define PGSQL_DELETE_PD_POOLS() \
+ "DELETE FROM dhcp6_pd_pool " \
+ "WHERE subnet_id = $1 OR subnet_id = " \
+ "(SELECT subnet_id FROM dhcp6_subnet" \
+ " WHERE subnet_prefix = $2)"
+#endif
+
+#ifndef PGSQL_DELETE_SHARED_NETWORK_COMMON
+#define PGSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_shared_network AS n " \
+ "USING " \
+ " " #table_prefix "_shared_network_server AS a, " \
+ " " #table_prefix "_server AS s " \
+ "WHERE " \
+ " n.id = a.shared_network_id AND " \
+ " a.server_id = s.id " \
+ #__VA_ARGS__
+
+#define PGSQL_DELETE_SHARED_NETWORK_WITH_TAG(table_prefix, ...) \
+ PGSQL_DELETE_SHARED_NETWORK_COMMON(table_prefix, AND s.tag = $1 __VA_ARGS__)
+
+#define PGSQL_DELETE_SHARED_NETWORK_ANY(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_shared_network AS n " \
+ #__VA_ARGS__
+
+#define PGSQL_DELETE_SHARED_NETWORK_UNASSIGNED(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_shared_network AS n " \
+ "WHERE n.id in ( " \
+ " SELECT n.id FROM " #table_prefix "_shared_network AS n " \
+ " LEFT JOIN " #table_prefix "_shared_network_server AS a ON n.id = a.shared_network_id " \
+ " WHERE a.shared_network_id IS NULL) " \
+ #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_SHARED_NETWORK_SERVER
+#define PGSQL_DELETE_SHARED_NETWORK_SERVER(table_prefix) \
+ "DELETE FROM " #table_prefix "_shared_network_server " \
+ "WHERE shared_network_id = " \
+ "(SELECT id FROM " #table_prefix "_shared_network WHERE name = $1)"
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_DEF
+#define PGSQL_DELETE_OPTION_DEF(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_option_def AS d " \
+ "USING " \
+ " " #table_prefix "_option_def_server AS a, " \
+ " " #table_prefix "_server AS s " \
+ "WHERE " \
+ " d.id = a.option_def_id AND " \
+ " a.server_id = s.id AND " \
+ " s.tag = $1 " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_DEF_UNASSIGNED
+#define PGSQL_DELETE_OPTION_DEF_UNASSIGNED(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_option_def AS d " \
+ "WHERE d.id in ( " \
+ " SELECT d.id FROM " #table_prefix "_option_def AS d " \
+ " LEFT JOIN " #table_prefix "_option_def_server AS a ON d.id = a.option_def_id " \
+ " WHERE a.option_def_id IS NULL) " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS
+#define PGSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(table_prefix) \
+ "DELETE FROM " #table_prefix "_option_def " \
+ "WHERE class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = $1)"
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_WITH_TAG
+#define PGSQL_DELETE_OPTION_WITH_TAG(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_options AS o " \
+ "USING " \
+ " " #table_prefix "_options_server AS a, " \
+ " " #table_prefix "_server AS s " \
+ "WHERE " \
+ " o.option_id = a.option_id AND " \
+ " a.server_id = s.id AND " \
+ " s.tag = $1 " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_NO_TAG
+#define PGSQL_DELETE_OPTION_NO_TAG(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_options AS o " \
+ #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX
+#define PGSQL_DELETE_OPTION_SUBNET_ID_PREFIX(table_prefix) \
+ "DELETE FROM " #table_prefix "_options AS o " \
+ "USING " \
+ " " #table_prefix "_subnet AS s " \
+ "WHERE " \
+ " s.subnet_id = o." #table_prefix "_subnet_id AND " \
+ " o.scope_id = 1 AND (s.subnet_id = $1 OR s.subnet_prefix = $2)"
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_UNASSIGNED
+#define PGSQL_DELETE_OPTION_UNASSIGNED(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_options AS o " \
+ "WHERE o.option_id in ( " \
+ " SELECT o.option_id FROM " #table_prefix "_options AS o " \
+ " LEFT JOIN " #table_prefix "_options_server AS a ON o.option_id = a.option_id " \
+ " WHERE a.option_id IS NULL) " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_POOL_RANGE
+#define PGSQL_DELETE_OPTION_POOL_RANGE(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_options AS o " \
+ "WHERE " #__VA_ARGS__ \
+ " AND o.pool_id = " \
+ " (SELECT id FROM " #table_prefix "_pool" \
+ " WHERE start_address = cast($1 as inet) AND end_address = cast($2 as inet))"
+#endif
+
+#ifndef PGSQL_DELETE_OPTION_PD_POOL
+#define PGSQL_DELETE_OPTION_PD_POOL(...) \
+ "DELETE FROM dhcp6_options AS o " \
+ "WHERE " #__VA_ARGS__ \
+ " AND o.pd_pool_id = " \
+ " (SELECT id FROM dhcp6_pd_pool" \
+ " WHERE prefix = $1 AND prefix_length = $2)"
+#endif
+
+#ifndef PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY
+#define PGSQL_DELETE_CLIENT_CLASS_DEPENDENCY(table_prefix) \
+ "DELETE FROM " #table_prefix "_client_class_dependency " \
+ "WHERE class_id = (SELECT id FROM " #table_prefix "_client_class WHERE name = $1)"
+#endif
+
+#ifndef PGSQL_DELETE_CLIENT_CLASS_SERVER
+#define PGSQL_DELETE_CLIENT_CLASS_SERVER(table_prefix) \
+ "DELETE FROM " #table_prefix "_client_class_server " \
+ "WHERE class_id = " \
+ "(SELECT id FROM " #table_prefix "_client_class WHERE name = $1)"
+#endif
+
+#ifndef PGSQL_DELETE_CLIENT_CLASS_COMMON
+#define PGSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_client_class AS c " \
+ "USING " \
+ " " #table_prefix "_client_class_server AS a, " \
+ " " #table_prefix "_server AS s " \
+ "WHERE " \
+ " c.id = a.class_id AND " \
+ " a.server_id = s.id " \
+ #__VA_ARGS__
+
+#define PGSQL_DELETE_CLIENT_CLASS_WITH_TAG(table_prefix, ...) \
+ PGSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, AND s.tag = $1 __VA_ARGS__)
+
+#define PGSQL_DELETE_CLIENT_CLASS_ANY(table_prefix, ...) \
+ PGSQL_DELETE_CLIENT_CLASS_COMMON(table_prefix, __VA_ARGS__)
+
+#define PGSQL_DELETE_CLIENT_CLASS_UNASSIGNED(table_prefix, ...) \
+ "DELETE FROM " #table_prefix "_client_class AS c " \
+ "WHERE c.id in (" \
+ " SELECT c.id FROM " #table_prefix "_client_class AS c " \
+ " LEFT JOIN " #table_prefix "_client_class_server AS a ON c.id = a.class_id " \
+ " WHERE a.class_id IS NULL) " #__VA_ARGS__
+#endif
+
+#ifndef PGSQL_DELETE_SERVER
+#define PGSQL_DELETE_SERVER(table_prefix) \
+ "DELETE FROM " #table_prefix "_server " \
+ "WHERE tag = $1"
+#endif
+
+#ifndef PGSQL_DELETE_ALL_SERVERS
+#define PGSQL_DELETE_ALL_SERVERS(table_prefix) \
+ "DELETE FROM " #table_prefix "_server " \
+ "WHERE id > 1"
+#endif
+
+} // end of anonymous namespace
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif
diff --git a/src/hooks/dhcp/pgsql_cb/tests/Makefile.am b/src/hooks/dhcp/pgsql_cb/tests/Makefile.am
new file mode 100644
index 0000000..f285cfd
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/Makefile.am
@@ -0,0 +1,64 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/pgsql_cb -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(PGSQL_CPPFLAGS)
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+# Unit test data files need to get installed.
+EXTRA_DIST =
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+TESTS += pgsql_cb_unittests
+
+pgsql_cb_unittests_SOURCES = pgsql_cb_impl_unittest.cc
+pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp4_unittest.cc
+pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp4_mgr_unittest.cc
+pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp6_unittest.cc
+pgsql_cb_unittests_SOURCES += pgsql_cb_dhcp6_mgr_unittest.cc
+pgsql_cb_unittests_SOURCES += run_unittests.cc
+
+pgsql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+
+pgsql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
+
+pgsql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+
+pgsql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/pgsql_cb/libpgsqlcb.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/pgsql/testutils/libpgsqltest.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/pgsql/libkea-pgsql.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
+pgsql_cb_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+pgsql_cb_unittests_LDADD += $(LOG4CPLUS_LIBS)
+pgsql_cb_unittests_LDADD += $(CRYPTO_LIBS)
+pgsql_cb_unittests_LDADD += $(BOOST_LIBS)
+pgsql_cb_unittests_LDADD += $(GTEST_LDADD)
+endif
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/hooks/dhcp/pgsql_cb/tests/Makefile.in b/src/hooks/dhcp/pgsql_cb/tests/Makefile.in
new file mode 100644
index 0000000..256f305
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/Makefile.in
@@ -0,0 +1,1124 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+TESTS = $(am__EXEEXT_1)
+@HAVE_GTEST_TRUE@am__append_1 = pgsql_cb_unittests
+noinst_PROGRAMS = $(am__EXEEXT_2)
+subdir = src/hooks/dhcp/pgsql_cb/tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_cpp20.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_netconf.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_GTEST_TRUE@am__EXEEXT_1 = pgsql_cb_unittests$(EXEEXT)
+am__EXEEXT_2 = $(am__EXEEXT_1)
+PROGRAMS = $(noinst_PROGRAMS)
+am__pgsql_cb_unittests_SOURCES_DIST = pgsql_cb_impl_unittest.cc \
+ pgsql_cb_dhcp4_unittest.cc pgsql_cb_dhcp4_mgr_unittest.cc \
+ pgsql_cb_dhcp6_unittest.cc pgsql_cb_dhcp6_mgr_unittest.cc \
+ run_unittests.cc
+@HAVE_GTEST_TRUE@am_pgsql_cb_unittests_OBJECTS = pgsql_cb_unittests-pgsql_cb_impl_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ pgsql_cb_unittests-run_unittests.$(OBJEXT)
+pgsql_cb_unittests_OBJECTS = $(am_pgsql_cb_unittests_OBJECTS)
+am__DEPENDENCIES_1 =
+@HAVE_GTEST_TRUE@pgsql_cb_unittests_DEPENDENCIES = $(top_builddir)/src/hooks/dhcp/pgsql_cb/libpgsqlcb.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/testutils/libpgsqltest.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+pgsql_cb_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) \
+ $(pgsql_cb_unittests_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = \
+ ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po \
+ ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po \
+ ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po \
+ ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po \
+ ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po \
+ ./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(pgsql_cb_unittests_SOURCES)
+DIST_SOURCES = $(am__pgsql_cb_unittests_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@
+DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@
+DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_NETCONF = @HAVE_NETCONF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@
+LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@
+LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@
+LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@
+LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@
+LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@
+LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@
+LIBYANG_LIBS = @LIBYANG_LIBS@
+LIBYANG_PREFIX = @LIBYANG_PREFIX@
+LIBYANG_VERSION = @LIBYANG_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_PLUGINS_PATH = @SR_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@
+SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@
+SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@
+SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_PREFIX = @SYSREPO_PREFIX@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = .
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \
+ -I$(top_builddir)/src/hooks/dhcp/pgsql_cb \
+ -I$(top_srcdir)/src/hooks/dhcp/pgsql_cb $(BOOST_INCLUDES) \
+ $(PGSQL_CPPFLAGS) \
+ -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static
+
+# Unit test data files need to get installed.
+EXTRA_DIST =
+CLEANFILES = *.gcno *.gcda
+TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+@HAVE_GTEST_TRUE@pgsql_cb_unittests_SOURCES = \
+@HAVE_GTEST_TRUE@ pgsql_cb_impl_unittest.cc \
+@HAVE_GTEST_TRUE@ pgsql_cb_dhcp4_unittest.cc \
+@HAVE_GTEST_TRUE@ pgsql_cb_dhcp4_mgr_unittest.cc \
+@HAVE_GTEST_TRUE@ pgsql_cb_dhcp6_unittest.cc \
+@HAVE_GTEST_TRUE@ pgsql_cb_dhcp6_mgr_unittest.cc \
+@HAVE_GTEST_TRUE@ run_unittests.cc
+@HAVE_GTEST_TRUE@pgsql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+@HAVE_GTEST_TRUE@pgsql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
+@HAVE_GTEST_TRUE@pgsql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@pgsql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/pgsql_cb/libpgsqlcb.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/eval/libkea-eval.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/stats/libkea-stats.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/testutils/libpgsqltest.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/pgsql/libkea-pgsql.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/database/libkea-database.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \
+@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/hooks/dhcp/pgsql_cb/tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+pgsql_cb_unittests$(EXEEXT): $(pgsql_cb_unittests_OBJECTS) $(pgsql_cb_unittests_DEPENDENCIES) $(EXTRA_pgsql_cb_unittests_DEPENDENCIES)
+ @rm -f pgsql_cb_unittests$(EXEEXT)
+ $(AM_V_CXXLD)$(pgsql_cb_unittests_LINK) $(pgsql_cb_unittests_OBJECTS) $(pgsql_cb_unittests_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+pgsql_cb_unittests-pgsql_cb_impl_unittest.o: pgsql_cb_impl_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_impl_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.o `test -f 'pgsql_cb_impl_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_impl_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_impl_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_impl_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.o `test -f 'pgsql_cb_impl_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_impl_unittest.cc
+
+pgsql_cb_unittests-pgsql_cb_impl_unittest.obj: pgsql_cb_impl_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_impl_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.obj `if test -f 'pgsql_cb_impl_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_impl_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_impl_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_impl_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_impl_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_impl_unittest.obj `if test -f 'pgsql_cb_impl_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_impl_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_impl_unittest.cc'; fi`
+
+pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o: pgsql_cb_dhcp4_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o `test -f 'pgsql_cb_dhcp4_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.o `test -f 'pgsql_cb_dhcp4_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_unittest.cc
+
+pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj: pgsql_cb_dhcp4_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj `if test -f 'pgsql_cb_dhcp4_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.obj `if test -f 'pgsql_cb_dhcp4_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_unittest.cc'; fi`
+
+pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o: pgsql_cb_dhcp4_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o `test -f 'pgsql_cb_dhcp4_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.o `test -f 'pgsql_cb_dhcp4_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp4_mgr_unittest.cc
+
+pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj: pgsql_cb_dhcp4_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp4_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_mgr_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp4_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp4_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp4_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp4_mgr_unittest.cc'; fi`
+
+pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o: pgsql_cb_dhcp6_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o `test -f 'pgsql_cb_dhcp6_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.o `test -f 'pgsql_cb_dhcp6_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_unittest.cc
+
+pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj: pgsql_cb_dhcp6_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj `if test -f 'pgsql_cb_dhcp6_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.obj `if test -f 'pgsql_cb_dhcp6_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_unittest.cc'; fi`
+
+pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o: pgsql_cb_dhcp6_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o `test -f 'pgsql_cb_dhcp6_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.o `test -f 'pgsql_cb_dhcp6_mgr_unittest.cc' || echo '$(srcdir)/'`pgsql_cb_dhcp6_mgr_unittest.cc
+
+pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj: pgsql_cb_dhcp6_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp6_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_mgr_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Tpo $(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pgsql_cb_dhcp6_mgr_unittest.cc' object='pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.obj `if test -f 'pgsql_cb_dhcp6_mgr_unittest.cc'; then $(CYGPATH_W) 'pgsql_cb_dhcp6_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pgsql_cb_dhcp6_mgr_unittest.cc'; fi`
+
+pgsql_cb_unittests-run_unittests.o: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo -c -o pgsql_cb_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo $(DEPDIR)/pgsql_cb_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='pgsql_cb_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+
+pgsql_cb_unittests-run_unittests.obj: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -MT pgsql_cb_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo -c -o pgsql_cb_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pgsql_cb_unittests-run_unittests.Tpo $(DEPDIR)/pgsql_cb_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='pgsql_cb_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pgsql_cb_unittests_CPPFLAGS) $(CPPFLAGS) $(pgsql_cb_unittests_CXXFLAGS) $(CXXFLAGS) -c -o pgsql_cb_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_mgr_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp4_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_mgr_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_dhcp6_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-pgsql_cb_impl_unittest.Po
+ -rm -f ./$(DEPDIR)/pgsql_cb_unittests-run_unittests.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-TESTS check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc
new file mode 100644
index 0000000..5eb0df5
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_mgr_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <cc/stamped_value.h>
+#include <dhcpsrv/config_backend_dhcp4_mgr.h>
+#include <pgsql_cb_dhcp4.h>
+#include <pgsql/testutils/pgsql_schema.h>
+#include <dhcpsrv/testutils/generic_backend_unittest.h>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::db;
+using namespace isc::db::test;
+
+namespace {
+
+/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv4Mgr.
+class PgSqlConfigBackendDHCPv4MgrTest : public GenericBackendTest {
+public:
+ /// @brief Constructor.
+ PgSqlConfigBackendDHCPv4MgrTest() {
+ // Recreate a fresh mgr.
+ ConfigBackendDHCPv4Mgr::create();
+
+ // Ensure we have the proper schema with no transient data.
+ createPgSQLSchema();
+ }
+
+ /// @brief Destructor.
+ virtual ~PgSqlConfigBackendDHCPv4MgrTest() {
+ // Destroy the mgr.
+ ConfigBackendDHCPv4Mgr::destroy();
+
+ // If data wipe enabled, delete transient data otherwise destroy the schema.
+ destroyPgSQLSchema();
+ }
+};
+
+// This test verifies that PgSQL backend can be registered with and
+// unregistered from the Config Backend Manager.
+TEST_F(PgSqlConfigBackendDHCPv4MgrTest, factoryRegistration) {
+
+ // Get the mgr singleton.
+ ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
+
+ // With no factory registered, attempting to add a PgSQL db should fail.
+ ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType);
+
+ // Now we'll register the PgSQL factory.
+ ASSERT_NO_THROW(PgSqlConfigBackendDHCPv4::registerBackendType());
+
+ // With the factory registered, attempting to add a PgSQL db should succeed.
+ ASSERT_NO_THROW(mgr.addBackend(validPgSQLConnectionString()));
+
+ // Create a PgSQL backend selector for convenience.
+ BackendSelector pgsql(BackendSelector::Type::POSTGRESQL);
+
+ // Should be able to create a global parameter.
+ StampedValuePtr server_tag = StampedValue::create("server-tag", "whale");
+ ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter4(pgsql, ServerSelector::ALL(),
+ server_tag));
+ // Verify parameter can be fetched.
+ server_tag.reset();
+ ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter4(pgsql, ServerSelector::ALL(),
+ "server-tag"));
+ ASSERT_TRUE(server_tag);
+ EXPECT_EQ("server-tag", server_tag->getName());
+ EXPECT_EQ("whale", server_tag->getValue());
+
+ // Now we'll unregister PgSQL.
+ ASSERT_NO_THROW(PgSqlConfigBackendDHCPv4::unregisterBackendType());
+
+ // With no factory registered, attempting to add a PgSQL db should fail.
+ ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType);
+
+ // Attempting to read the global parameter should fail.
+ ASSERT_THROW(mgr.getPool()->getGlobalParameter4(pgsql, ServerSelector::ALL(), "server-tag"),
+ NoSuchDatabase);
+}
+
+}
diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc
new file mode 100644
index 0000000..fdd11e8
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp4_unittest.cc
@@ -0,0 +1,513 @@
+// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <database/db_exceptions.h>
+#include <database/server.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/config_backend_dhcp4_mgr.h>
+#include <dhcpsrv/testutils/generic_cb_dhcp4_unittest.h>
+#include <dhcpsrv/testutils/generic_cb_recovery_unittest.h>
+#include <dhcpsrv/testutils/pgsql_generic_backend_unittest.h>
+#include <dhcpsrv/testutils/test_utils.h>
+#include <pgsql_cb_dhcp4.h>
+#include <pgsql/testutils/pgsql_schema.h>
+#include <testutils/multi_threading_utils.h>
+#include <testutils/gtest_utils.h>
+
+#include <boost/make_shared.hpp>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+#include <map>
+#include <sstream>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::db;
+using namespace isc::db::test;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::process;
+using namespace isc::test;
+using namespace isc::util;
+namespace ph = std::placeholders;
+
+namespace {
+
+/// @brief Test implementation of the PostgreSQL configuration backend.
+///
+/// It exposes protected members of the @c PgSqlConfigBackendDHCPv4.
+class TestPgSqlConfigBackendDHCPv4 : public PgSqlConfigBackendDHCPv4 {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ explicit TestPgSqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters)
+ : PgSqlConfigBackendDHCPv4(parameters) {
+ }
+
+ using PgSqlConfigBackendDHCPv4::base_impl_;
+};
+
+/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv4.
+class PgSqlConfigBackendDHCPv4Test : public GenericConfigBackendDHCPv4Test {
+public:
+ /// @brief Constructor.
+ PgSqlConfigBackendDHCPv4Test() {}
+
+ /// @brief Destructor.
+ virtual ~PgSqlConfigBackendDHCPv4Test() {}
+
+ /// @brief Creates the PostgreSQL back end schema
+ virtual void createSchema() {
+ createPgSQLSchema();
+ }
+
+ /// @brief Destroys the PostgreSQL back end schema
+ virtual void destroySchema() {
+ destroyPgSQLSchema();
+ }
+
+ /// @brief Returns a valid PostgreSQL back end specific connection
+ /// string
+ std::string validConnectionString() {
+ return (validPgSQLConnectionString());
+ }
+
+ /// @brief Instantiates an instance of a PostgreSQL DHCPv4 configuration
+ /// back end.
+ ///
+ /// @params Connection parameters describing the back end to create.
+ ///
+ /// @return Pointer to the newly created back end instance.
+ ConfigBackendDHCPv4Ptr backendFactory(db::DatabaseConnection::ParameterMap&
+ params) {
+
+ return (ConfigBackendDHCPv4Ptr(new TestPgSqlConfigBackendDHCPv4(params)));
+ }
+
+ /// @brief Counts rows in a selected table in PostgreSQL database.
+ ///
+ /// This method can be used to verify that some configuration elements were
+ /// deleted from a selected table as a result of cascade delete or a trigger.
+ /// For example, deleting a subnet should trigger deletion of its address
+ /// pools and options. By counting the rows on each table we can determine
+ /// whether the deletion took place on all tables for which it was expected.
+ ///
+ /// @param table Table name.
+ /// @return Number of rows in the specified table.
+ size_t countRows(const std::string& table) const {
+ auto p = boost::dynamic_pointer_cast<TestPgSqlConfigBackendDHCPv4>(cbptr_);
+ if (!p) {
+ ADD_FAILURE() << "cbptr_ does not cast to TestPgSqlConfigBackendDHCPv4";
+ return (0);
+ }
+
+ // Reuse the existing connection of the backend.
+ auto impl = boost::dynamic_pointer_cast<PgSqlConfigBackendImpl>(p->base_impl_);
+ auto& conn = impl->conn_;
+
+ return (PgSqlGenericBackendTest::countRows(conn, table));
+ }
+};
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getType) {
+ getTypeTest("postgresql");
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getHost) {
+ getHostTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getPort) {
+ getPortTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteServerTest) {
+ createUpdateDeleteServerTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAndDeleteAllServersTest) {
+ getAndDeleteAllServersTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4Test) {
+ createUpdateDeleteGlobalParameter4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, globalParameters4WithServerTagsTest) {
+ globalParameters4WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllGlobalParameters4Test) {
+ getAllGlobalParameters4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedGlobalParameters4Test) {
+ getModifiedGlobalParameters4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, nullKeyErrorTest) {
+ nullKeyErrorTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateSubnet4SelectorsTest) {
+ createUpdateSubnet4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4Test) {
+ getSubnet4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4byIdSelectorsTest) {
+ getSubnet4byIdSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4WithOptionalUnspecifiedTest) {
+ getSubnet4WithOptionalUnspecifiedTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4SharedNetworkTest) {
+ getSubnet4SharedNetworkTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4ByPrefixTest) {
+ getSubnet4ByPrefixTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSubnet4byPrefixSelectorsTest) {
+ getSubnet4byPrefixSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSubnets4Test) {
+ getAllSubnets4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSubnets4SelectorsTest) {
+ getAllSubnets4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSubnets4WithServerTagsTest) {
+ getAllSubnets4WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSubnets4SelectorsTest) {
+ getModifiedSubnets4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSubnet4Test) {
+ deleteSubnet4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSubnet4ByIdSelectorsTest) {
+ deleteSubnet4ByIdSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSubnet4ByPrefixSelectorsTest) {
+ deleteSubnet4ByPrefixSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteAllSubnets4SelectorsTest) {
+ deleteAllSubnets4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, unassignedSubnet4Test) {
+ unassignedSubnet4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSubnets4Test) {
+ getModifiedSubnets4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, subnetLifetimeTest) {
+ subnetLifetimeTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetworkSubnets4Test) {
+ getSharedNetworkSubnets4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, subnetUpdatePoolsTest) {
+ subnetUpdatePoolsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, subnetOptionsTest) {
+ subnetOptionsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetwork4Test) {
+ getSharedNetwork4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetwork4SelectorsTest) {
+ getSharedNetwork4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4Test) {
+ createUpdateSharedNetwork4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4SelectorsTest) {
+ createUpdateSharedNetwork4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getSharedNetwork4WithOptionalUnspecifiedTest) {
+ getSharedNetwork4WithOptionalUnspecifiedTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSharedNetworkSubnets4Test) {
+ deleteSharedNetworkSubnets4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSharedNetworks4Test) {
+ getAllSharedNetworks4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSharedNetworks4SelectorsTest) {
+ getAllSharedNetworks4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllSharedNetworks4WithServerTagsTest) {
+ getAllSharedNetworks4WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4Test) {
+ getModifiedSharedNetworks4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedSharedNetworks4SelectorsTest) {
+ getModifiedSharedNetworks4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSharedNetwork4Test) {
+ deleteSharedNetwork4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteSharedNetwork4SelectorsTest) {
+ deleteSharedNetwork4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteAllSharedNetworks4SelectorsTest) {
+ deleteAllSharedNetworks4SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, unassignedSharedNetworkTest) {
+ unassignedSharedNetworkTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, sharedNetworkLifetimeTest) {
+ sharedNetworkLifetimeTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, sharedNetworkOptionsTest) {
+ sharedNetworkOptionsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getOptionDef4Test) {
+ getOptionDef4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, optionDefs4WithServerTagsTest) {
+ optionDefs4WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllOptionDefs4Test) {
+ getAllOptionDefs4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedOptionDefs4Test) {
+ getModifiedOptionDefs4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteOption4Test) {
+ createUpdateDeleteOption4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, globalOptions4WithServerTagsTest) {
+ globalOptions4WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getAllOptions4Test) {
+ getAllOptions4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedOptions4Test) {
+ getModifiedOptions4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteSubnetOption4Test) {
+ createUpdateDeleteSubnetOption4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeletePoolOption4Test) {
+ createUpdateDeletePoolOption4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateDeleteSharedNetworkOption4Test) {
+ createUpdateDeleteSharedNetworkOption4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, subnetOptionIdOrderTest) {
+ subnetOptionIdOrderTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, sharedNetworkOptionIdOrderTest) {
+ sharedNetworkOptionIdOrderTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, setAndGetAllClientClasses4Test) {
+ setAndGetAllClientClasses4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getClientClass4Test) {
+ getClientClass4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, createUpdateClientClass4OptionsTest) {
+ createUpdateClientClass4OptionsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, getModifiedClientClasses4Test) {
+ getModifiedClientClasses4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteClientClass4Test) {
+ deleteClientClass4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, deleteAllClientClasses4Test) {
+ deleteAllClientClasses4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, clientClassDependencies4Test) {
+ clientClassDependencies4Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4Test, multipleAuditEntriesTest) {
+ multipleAuditEntriesTest();
+}
+
+/// @brief Test fixture for verifying database connection loss-recovery
+/// behavior.
+class PgSqlConfigBackendDHCPv4DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest {
+public:
+ /// @brief Constructor
+ PgSqlConfigBackendDHCPv4DbLostCallbackTest() {};
+
+ /// @brief Destructor
+ virtual ~PgSqlConfigBackendDHCPv4DbLostCallbackTest() {};
+
+ /// @brief Creates the PostgreSQL CB schema.
+ virtual void createSchema() {
+ createPgSQLSchema();
+ }
+
+ /// @brief Destroys the PostgreSQL CB schema.
+ virtual void destroySchema() {
+ destroyPgSQLSchema();
+ }
+
+ /// @brief Method which returns a valid back end specific connection
+ /// string
+ virtual std::string validConnectionString() {
+ return (validPgSQLConnectionString());
+ }
+
+ /// @brief Method which returns an invalid back end specific connection
+ /// string.
+ virtual std::string invalidConnectionString() {
+ return (connectionString(PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
+ VALID_USER, VALID_PASSWORD));
+ }
+
+ /// @brief Registers PostgreSQL as a CB backend type.
+ virtual void registerBackendType() {
+ isc::dhcp::PgSqlConfigBackendDHCPv4::registerBackendType();
+ }
+
+ /// @brief Unregisters PostgreSQL as a CB backend type.
+ virtual void unregisterBackendType() {
+ isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType();
+ }
+
+ /// @brief Sets the IOService instance in the CB implementation object.
+ ///
+ /// @param io_service pointer to the IOService instance to use. It may be
+ /// an empty pointer.
+ virtual void setConfigBackendImplIOService(isc::asiolink::IOServicePtr io_service) {
+ isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service);
+ }
+
+ /// @brief Attempts to add a backend instance to the CB manager.
+ ///
+ /// @param access Connection access string containing the database
+ /// connection parameters.
+ virtual void addBackend(const std::string& access) {
+ ConfigBackendDHCPv4Mgr::instance().addBackend(access);
+ }
+
+ /// @brief Fetches a collection of all the servers currently in
+ /// the CB database. This function is used to check the operability
+ /// of the CB backend.
+ ServerCollection getAllServers() {
+ return (ConfigBackendDHCPv4Mgr::instance().getPool()->getAllServers4(BackendSelector()));
+ }
+};
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testNoCallbackOnOpenFailure) {
+ MultiThreadingTest mt(false);
+ testNoCallbackOnOpenFailure();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
+ MultiThreadingTest mt(true);
+ testNoCallbackOnOpenFailure();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv4DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+}
diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc
new file mode 100644
index 0000000..cb2b699
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_mgr_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <cc/stamped_value.h>
+#include <dhcpsrv/config_backend_dhcp6_mgr.h>
+#include <pgsql_cb_dhcp6.h>
+#include <pgsql/testutils/pgsql_schema.h>
+#include <dhcpsrv/testutils/generic_backend_unittest.h>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::db;
+using namespace isc::db::test;
+
+namespace {
+
+/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv6Mgr.
+class PgSqlConfigBackendDHCPv6MgrTest : public GenericBackendTest {
+public:
+ /// @brief Constructor.
+ PgSqlConfigBackendDHCPv6MgrTest() {
+ // Recreate a fresh mgr.
+ ConfigBackendDHCPv6Mgr::create();
+
+ // Ensure we have the proper schema with no transient data.
+ createPgSQLSchema();
+ }
+
+ /// @brief Destructor.
+ virtual ~PgSqlConfigBackendDHCPv6MgrTest() {
+ // Destroy the mgr.
+ ConfigBackendDHCPv6Mgr::destroy();
+
+ // If data wipe enabled, delete transient data otherwise destroy the schema.
+ destroyPgSQLSchema();
+ }
+};
+
+// This test verifies that PgSQL backend can be registered with and
+// unregistered from the Config Backend Manager.
+TEST_F(PgSqlConfigBackendDHCPv6MgrTest, factoryRegistration) {
+
+ // Get the mgr singleton.
+ ConfigBackendDHCPv6Mgr& mgr = ConfigBackendDHCPv6Mgr::instance();
+
+ // With no factory registered, attempting to add a PgSQL db should fail.
+ ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType);
+
+ // Now we'll register the PgSQL factory.
+ ASSERT_NO_THROW(PgSqlConfigBackendDHCPv6::registerBackendType());
+
+ // With the factory registered, attempting to add a PgSQL db should succeed.
+ ASSERT_NO_THROW(mgr.addBackend(validPgSQLConnectionString()));
+
+ // Create a PgSQL backend selector for convenience.
+ BackendSelector pgsql(BackendSelector::Type::POSTGRESQL);
+
+ // Should be able to create a global parameter.
+ StampedValuePtr server_tag = StampedValue::create("server-tag", "whale");
+ ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(pgsql, ServerSelector::ALL(),
+ server_tag));
+ // Verify parameter can be fetched.
+ server_tag.reset();
+ ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter6(pgsql, ServerSelector::ALL(),
+ "server-tag"));
+ ASSERT_TRUE(server_tag);
+ EXPECT_EQ("server-tag", server_tag->getName());
+ EXPECT_EQ("whale", server_tag->getValue());
+
+ // Now we'll unregister PgSQL.
+ ASSERT_NO_THROW(PgSqlConfigBackendDHCPv6::unregisterBackendType());
+
+ // With no factory registered, attempting to add a PgSQL db should fail.
+ ASSERT_THROW(mgr.addBackend(validPgSQLConnectionString()), InvalidType);
+
+ // Attempting to read the global parameter should fail.
+ ASSERT_THROW(mgr.getPool()->getGlobalParameter6(pgsql, ServerSelector::ALL(), "server-tag"),
+ NoSuchDatabase);
+}
+
+}
diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc
new file mode 100644
index 0000000..b6bdacc
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_dhcp6_unittest.cc
@@ -0,0 +1,517 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <database/db_exceptions.h>
+#include <database/server.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/config_backend_dhcp6_mgr.h>
+#include <dhcpsrv/testutils/generic_cb_dhcp6_unittest.h>
+#include <dhcpsrv/testutils/generic_cb_recovery_unittest.h>
+#include <dhcpsrv/testutils/pgsql_generic_backend_unittest.h>
+#include <dhcpsrv/testutils/test_utils.h>
+#include <pgsql_cb_dhcp6.h>
+#include <pgsql/testutils/pgsql_schema.h>
+#include <testutils/multi_threading_utils.h>
+#include <testutils/gtest_utils.h>
+
+#include <boost/make_shared.hpp>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+#include <map>
+#include <sstream>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::db;
+using namespace isc::db::test;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::process;
+using namespace isc::test;
+using namespace isc::util;
+namespace ph = std::placeholders;
+
+namespace {
+
+/// @brief Test implementation of the PostgreSQL configuration backend.
+///
+/// It exposes protected members of the @c PgSqlConfigBackendDHCPv6.
+class TestPgSqlConfigBackendDHCPv6 : public PgSqlConfigBackendDHCPv6 {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ explicit TestPgSqlConfigBackendDHCPv6(const DatabaseConnection::ParameterMap& parameters)
+ : PgSqlConfigBackendDHCPv6(parameters) {
+ }
+
+ using PgSqlConfigBackendDHCPv6::base_impl_;
+};
+
+/// @brief Test fixture class for @c PgSqlConfigBackendDHCPv6.
+class PgSqlConfigBackendDHCPv6Test : public GenericConfigBackendDHCPv6Test {
+public:
+ /// @brief Constructor.
+ PgSqlConfigBackendDHCPv6Test() {}
+
+ /// @brief Destructor.
+ virtual ~PgSqlConfigBackendDHCPv6Test() {}
+
+ /// @brief Creates the PostgreSQL back end schema
+ virtual void createSchema() {
+ createPgSQLSchema();
+ }
+
+ /// @brief Destroys the PostgreSQL back end schema
+ virtual void destroySchema() {
+ destroyPgSQLSchema();
+ }
+
+ /// @brief Returns a valid PostgreSQL back end specific connection
+ /// string
+ std::string validConnectionString() {
+ return (validPgSQLConnectionString());
+ }
+
+ /// @brief Instantiates an instance of a PostgreSQL DHCPv6 configuration
+ /// back end.
+ ///
+ /// @params Connection parameters describing the back end to create.
+ ///
+ /// @return Pointer to the newly created back end instance.
+ ConfigBackendDHCPv6Ptr backendFactory(db::DatabaseConnection::ParameterMap&
+ params) {
+
+ return (ConfigBackendDHCPv6Ptr(new TestPgSqlConfigBackendDHCPv6(params)));
+ }
+
+ /// @brief Counts rows in a selected table in PostgreSQL database.
+ ///
+ /// This method can be used to verify that some configuration elements were
+ /// deleted from a selected table as a result of cascade delete or a trigger.
+ /// For example, deleting a subnet should trigger deletion of its address
+ /// pools and options. By counting the rows on each table we can determine
+ /// whether the deletion took place on all tables for which it was expected.
+ ///
+ /// @param table Table name.
+ /// @return Number of rows in the specified table.
+ size_t countRows(const std::string& table) const {
+ auto p = boost::dynamic_pointer_cast<TestPgSqlConfigBackendDHCPv6>(cbptr_);
+ if (!p) {
+ ADD_FAILURE() << "cbptr_ does not cast to TestPgSqlConfigBackendDHCPv6";
+ return (0);
+ }
+
+ // Reuse the existing connection of the backend.
+ auto impl = boost::dynamic_pointer_cast<PgSqlConfigBackendImpl>(p->base_impl_);
+ auto& conn = impl->conn_;
+
+ return (PgSqlGenericBackendTest::countRows(conn, table));
+ }
+};
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getType) {
+ getTypeTest("postgresql");
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getHost) {
+ getHostTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getPort) {
+ getPortTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteServerTest) {
+ createUpdateDeleteServerTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAndDeleteAllServersTest) {
+ getAndDeleteAllServersTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteGlobalParameter6Test) {
+ createUpdateDeleteGlobalParameter6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, globalParameters6WithServerTagsTest) {
+ globalParameters6WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllGlobalParameters6Test) {
+ getAllGlobalParameters6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedGlobalParameters6Test) {
+ getModifiedGlobalParameters6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, nullKeyErrorTest) {
+ nullKeyErrorTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateSubnet6SelectorsTest) {
+ createUpdateSubnet6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6Test) {
+ getSubnet6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6byIdSelectorsTest) {
+ getSubnet6byIdSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6WithOptionalUnspecifiedTest) {
+ getSubnet6WithOptionalUnspecifiedTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6SharedNetworkTest) {
+ getSubnet6SharedNetworkTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6ByPrefixTest) {
+ getSubnet6ByPrefixTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSubnet6byPrefixSelectorsTest) {
+ getSubnet6byPrefixSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSubnets6Test) {
+ getAllSubnets6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSubnets6SelectorsTest) {
+ getAllSubnets6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSubnets6WithServerTagsTest) {
+ getAllSubnets6WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSubnets6SelectorsTest) {
+ getModifiedSubnets6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSubnet6Test) {
+ deleteSubnet6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSubnet6ByIdSelectorsTest) {
+ deleteSubnet6ByIdSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSubnet6ByPrefixSelectorsTest) {
+ deleteSubnet6ByPrefixSelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteAllSubnets6SelectorsTest) {
+ deleteAllSubnets6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, unassignedSubnet6Test) {
+ unassignedSubnet6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSubnets6Test) {
+ getModifiedSubnets6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, subnetLifetimeTest) {
+ subnetLifetimeTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetworkSubnets6Test) {
+ getSharedNetworkSubnets6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, subnetUpdatePoolsTest) {
+ subnetUpdatePoolsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, subnetOptionsTest) {
+ subnetOptionsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetwork6Test) {
+ getSharedNetwork6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetwork6SelectorsTest) {
+ getSharedNetwork6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6Test) {
+ createUpdateSharedNetwork6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6SelectorsTest) {
+ createUpdateSharedNetwork6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getSharedNetwork6WithOptionalUnspecifiedTest) {
+ getSharedNetwork6WithOptionalUnspecifiedTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSharedNetworkSubnets6Test) {
+ deleteSharedNetworkSubnets6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSharedNetworks6Test) {
+ getAllSharedNetworks6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSharedNetworks6SelectorsTest) {
+ getAllSharedNetworks6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllSharedNetworks6WithServerTagsTest) {
+ getAllSharedNetworks6WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6Test) {
+ getModifiedSharedNetworks6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedSharedNetworks6SelectorsTest) {
+ getModifiedSharedNetworks6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSharedNetwork6Test) {
+ deleteSharedNetwork6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteSharedNetwork6SelectorsTest) {
+ deleteSharedNetwork6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteAllSharedNetworks6SelectorsTest) {
+ deleteAllSharedNetworks6SelectorsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, unassignedSharedNetworkTest) {
+ unassignedSharedNetworkTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkLifetimeTest) {
+ sharedNetworkLifetimeTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkOptionsTest) {
+ sharedNetworkOptionsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getOptionDef6Test) {
+ getOptionDef6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, optionDefs6WithServerTagsTest) {
+ optionDefs6WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllOptionDefs6Test) {
+ getAllOptionDefs6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedOptionDefs6Test) {
+ getModifiedOptionDefs6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteOption6Test) {
+ createUpdateDeleteOption6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, globalOptions6WithServerTagsTest) {
+ globalOptions6WithServerTagsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getAllOptions6Test) {
+ getAllOptions6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedOptions6Test) {
+ getModifiedOptions6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteSubnetOption6Test) {
+ createUpdateDeleteSubnetOption6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeletePoolOption6Test) {
+ createUpdateDeletePoolOption6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeletePdPoolOption6Test) {
+ createUpdateDeletePdPoolOption6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateDeleteSharedNetworkOption6Test) {
+ createUpdateDeleteSharedNetworkOption6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, subnetOptionIdOrderTest) {
+ subnetOptionIdOrderTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, sharedNetworkOptionIdOrderTest) {
+ sharedNetworkOptionIdOrderTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, setAndGetAllClientClasses6Test) {
+ setAndGetAllClientClasses6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getClientClass6Test) {
+ getClientClass6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, createUpdateClientClass6OptionsTest) {
+ createUpdateClientClass6OptionsTest();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, getModifiedClientClasses6Test) {
+ getModifiedClientClasses6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteClientClass6Test) {
+ deleteClientClass6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, deleteAllClientClasses6Test) {
+ deleteAllClientClasses6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, clientClassDependencies6Test) {
+ clientClassDependencies6Test();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6Test, multipleAuditEntriesTest) {
+ multipleAuditEntriesTest();
+}
+
+/// @brief Test fixture for verifying database connection loss-recovery
+/// behavior.
+class PgSqlConfigBackendDHCPv6DbLostCallbackTest : public GenericConfigBackendDbLostCallbackTest {
+public:
+ /// @brief Constructor
+ PgSqlConfigBackendDHCPv6DbLostCallbackTest() {};
+
+ /// @brief Destructor
+ virtual ~PgSqlConfigBackendDHCPv6DbLostCallbackTest() {};
+
+ /// @brief Creates the PostgreSQL CB schema.
+ virtual void createSchema() {
+ createPgSQLSchema();
+ }
+
+ /// @brief Destroys the PostgreSQL CB schema.
+ virtual void destroySchema() {
+ destroyPgSQLSchema();
+ }
+
+ /// @brief Method which returns a valid back end specific connection
+ /// string
+ virtual std::string validConnectionString() {
+ return (validPgSQLConnectionString());
+ }
+
+ /// @brief Method which returns an invalid back end specific connection
+ /// string.
+ virtual std::string invalidConnectionString() {
+ return (connectionString(PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
+ VALID_USER, VALID_PASSWORD));
+ }
+
+ /// @brief Registers PostgreSQL as a CB backend type.
+ virtual void registerBackendType() {
+ isc::dhcp::PgSqlConfigBackendDHCPv6::registerBackendType();
+ }
+
+ /// @brief Unregisters PostgreSQL as a CB backend type.
+ virtual void unregisterBackendType() {
+ isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType();
+ }
+
+ /// @brief Sets the IOService instance in the CB implementation object.
+ ///
+ /// @param io_service pointer to the IOService instance to use. It may be
+ /// an empty pointer.
+ virtual void setConfigBackendImplIOService(isc::asiolink::IOServicePtr io_service) {
+ isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service);
+ }
+
+ /// @brief Attempts to add a backend instance to the CB manager.
+ ///
+ /// @param access Connection access string containing the database
+ /// connection parameters.
+ virtual void addBackend(const std::string& access) {
+ ConfigBackendDHCPv6Mgr::instance().addBackend(access);
+ }
+
+ /// @brief Fetches a collection of all the servers currently in
+ /// the CB database. This function is used to check the operability
+ /// of the CB backend.
+ ServerCollection getAllServers() {
+ return (ConfigBackendDHCPv6Mgr::instance().getPool()->getAllServers6(BackendSelector()));
+ }
+};
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailure) {
+ MultiThreadingTest mt(false);
+ testNoCallbackOnOpenFailure();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
+ MultiThreadingTest mt(true);
+ testNoCallbackOnOpenFailure();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+TEST_F(PgSqlConfigBackendDHCPv6DbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+}
diff --git a/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc
new file mode 100644
index 0000000..025eb33
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/pgsql_cb_impl_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dhcpsrv/testutils/pgsql_generic_backend_unittest.h>
+#include <pgsql/testutils/pgsql_schema.h>
+#include <testutils/gtest_utils.h>
+
+#include <gtest/gtest.h>
+#include <pgsql_cb_impl.h>
+#include <vector>
+
+using namespace isc::db;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::util;
+
+namespace {
+
+class PgSqlConfigBackendTest : public PgSqlGenericBackendTest {
+public:
+ PgSqlConfigBackendTest() : PgSqlGenericBackendTest() {
+ createFullSchema();
+ }
+
+ /// @brief Setup for each test.
+ ///
+ /// Creates the configuration backend impl.
+ virtual void SetUp() {
+ DatabaseConnection::ParameterMap params;
+ params["name"] = "keatest";
+ params["password"] = "keatest";
+ params["user"] = "keatest";
+ ASSERT_NO_THROW_LOG(cbptr_.reset(new PgSqlConfigBackendImpl(params, 0, 0)));
+ }
+
+ /// @brief Cleans up after each test.
+ ///
+ /// Destroys the configuration backend impl.
+ virtual void TearDown() {
+ ASSERT_NO_THROW_LOG(cbptr_.reset());
+ }
+
+ ~PgSqlConfigBackendTest() {
+ destroyFullSchema();
+ }
+
+ /// @brief creates full schema (slow!)
+ ///
+ /// If possible, use simpler, faster alternative: @ref createDummySchema();
+ /// Don't forget to tear it down with @ref destroyFullSchema();
+ void createFullSchema() {
+ // Create the actual full Kea schema.
+ isc::db::test::createPgSQLSchema();
+ }
+
+ /// @brief destroys the full schema (slow!)
+ ///
+ /// Don't forget to call this method once you're done, if you used @ref createFullSchema().
+ void destroyFullSchema() {
+ // Clean up after ourselves.
+ isc::db::test::destroyPgSQLSchema();
+ }
+
+ boost::shared_ptr<PgSqlConfigBackendImpl> cbptr_;
+};
+
+// Let's start with absolute basics. This should construct a backend instance
+// connected to the unit test schema. The backend instance is created in
+// Setup() and which will ASSERT on failures.
+TEST_F(PgSqlConfigBackendTest, constructor) {
+ // Is this the right config backend type?
+ EXPECT_EQ("postgresql", cbptr_->getType());
+}
+
+} // namespace
diff --git a/src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc b/src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc
new file mode 100644
index 0000000..74904a3
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/tests/run_unittests.cc
@@ -0,0 +1,20 @@
+// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <log/logger_support.h>
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+ int result = RUN_ALL_TESTS();
+
+ return (result);
+}
diff --git a/src/hooks/dhcp/pgsql_cb/version.cc b/src/hooks/dhcp/pgsql_cb/version.cc
new file mode 100644
index 0000000..f232709
--- /dev/null
+++ b/src/hooks/dhcp/pgsql_cb/version.cc
@@ -0,0 +1,18 @@
+// Copyright (C) 2021-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <hooks/hooks.h>
+
+extern "C" {
+
+/// @brief returns Kea hooks version.
+int version() {
+ return (KEA_HOOKS_VERSION);
+}
+
+}