]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3763] Add precautionary continue handlers to lease AUPD triggers
authorAndrei Pavel <andrei@isc.org>
Thu, 13 Feb 2025 14:02:04 +0000 (16:02 +0200)
committerAndrei Pavel <andrei@isc.org>
Mon, 28 Apr 2025 14:53:19 +0000 (14:53 +0000)
configure.ac
src/bin/admin/tests/mysql_tests.sh.in
src/bin/admin/tests/pgsql_tests.sh.in
src/lib/mysql/mysql_constants.h
src/share/database/scripts/mysql/.gitignore
src/share/database/scripts/mysql/Makefile.am
src/share/database/scripts/mysql/dhcpdb_create.mysql
src/share/database/scripts/mysql/meson.build
src/share/database/scripts/mysql/upgrade_029_to_030.sh.in [new file with mode: 0755]

index 94fbd535f957e2f4fc56ecbc5a030f10d5e6af6b..54f3bb36ee0685eb5592289f67ea4260ffe426f7 100644 (file)
@@ -1868,6 +1868,8 @@ AC_CONFIG_FILES([src/share/database/scripts/mysql/upgrade_027_to_028.sh],
                 [chmod +x src/share/database/scripts/mysql/upgrade_027_to_028.sh])
 AC_CONFIG_FILES([src/share/database/scripts/mysql/upgrade_028_to_029.sh],
                 [chmod +x src/share/database/scripts/mysql/upgrade_028_to_029.sh])
+AC_CONFIG_FILES([src/share/database/scripts/mysql/upgrade_029_to_030.sh],
+                [chmod +x src/share/database/scripts/mysql/upgrade_029_to_030.sh])
 AC_CONFIG_FILES([src/share/database/scripts/mysql/wipe_data.sh],
                 [chmod +x src/share/database/scripts/mysql/wipe_data.sh])
 AC_CONFIG_FILES([src/share/database/scripts/pgsql/Makefile])
index 3c6513da32a49e6dcb9a731b1395893865fc235a..faaa11b7a17c27837947ed7805831275049d0514 100755 (executable)
@@ -157,7 +157,7 @@ mysql_db_version_test() {
     run_command \
         "${kea_admin}" db-version mysql -u "${db_user}" -p "${db_password}" -n "${db_name}"
     version="${OUTPUT}"
-    assert_str_eq "29.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
+    assert_str_eq "30.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
 
     # Let's wipe the whole database
     mysql_wipe
@@ -840,106 +840,106 @@ mysql_upgrade_23_to_24_test() {
     assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
     assert_str_eq '18' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 0"
+    query="select name from option_def_data_type where id = 0"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'empty' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 1"
+    query="select name from option_def_data_type where id = 1"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'binary' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 2"
+    query="select name from option_def_data_type where id = 2"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'boolean' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 4"
+    query="select name from option_def_data_type where id = 4"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'int16' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 5"
+    query="select name from option_def_data_type where id = 5"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'int32' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 6"
+    query="select name from option_def_data_type where id = 6"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'uint8' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 7"
+    query="select name from option_def_data_type where id = 7"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'uint16' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 8"
+    query="select name from option_def_data_type where id = 8"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'uint32' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 10"
+    query="select name from option_def_data_type where id = 10"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'ipv4-address' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 11"
+    query="select name from option_def_data_type where id = 11"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'ipv6-address' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 12"
+    query="select name from option_def_data_type where id = 12"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'ipv6-prefix' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 13"
+    query="select name from option_def_data_type where id = 13"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'psid' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 14"
+    query="select name from option_def_data_type where id = 14"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'string' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 15"
+    query="select name from option_def_data_type where id = 15"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'tuple' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 16"
+    query="select name from option_def_data_type where id = 16"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'fqdn' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 17"
+    query="select name from option_def_data_type where id = 17"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'internal' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 254"
+    query="select name from option_def_data_type where id = 254"
     run_command \
-        mysql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'record' "${OUTPUT}" "${query}: expected output %s, returned %s"
 }
 
@@ -1033,6 +1033,130 @@ mysql_upgrade_28_to_29_test() {
     assert_str_eq 'registered' "${OUTPUT}" "${qry}: expected output %s, returned %s"
 }
 
+mysql_upgrade_29_to_30_test() {
+    # Test the amendment of the lease AUPD triggers used to populate stat_by_client_class tables.
+    # Blind test to a blind fix. The test probably passes prior to this schema change.
+
+    # Clear leases.
+    query='DELETE FROM lease4; DELETE FROM lease6;'
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Insert a null user context.
+    query="INSERT INTO lease4 VALUES(10,20,30,40,(SELECT FROM_UNIXTIME(1678900000)),50,1,1,'one,example,com',0,NULL,NULL,NULL,0)"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease4"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq 'NULL' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Update the user context explcitly to a valid JSON.
+    query="UPDATE lease4 SET user_context='{}'"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease4"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '{}' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Update the expiry time.
+    query="UPDATE lease4 SET expire=FROM_UNIXTIME(1789000000)"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease4"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '{}' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Update the user context explcitly to NULL.
+    query="UPDATE lease4 SET user_context=NULL"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease4"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq 'NULL' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Insert a null user context.
+    query="INSERT INTO lease6 VALUES(inet6_aton('::10'),20,30,(SELECT FROM_UNIXTIME(1678900000)),40,50,1,60,70,1,1,'one,example,com',80,90,16,0,NULL,0)"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" 'INSERT INTO lease6 failed, expected exit code %d, actual %d'
+    assert_str_eq '' "${OUTPUT}"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease6"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq 'NULL' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Update the user context explcitly to a valid JSON.
+    query="UPDATE lease6 SET user_context='{}'"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease6"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '{}' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Update the expiry time.
+    query="UPDATE lease6 SET expire=FROM_UNIXTIME(1789000000)"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease6"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '{}' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Update the user context explcitly to NULL.
+    query="UPDATE lease6 SET user_context=NULL"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq '' "${OUTPUT}" "${query}: expected output %s, returned %s"
+
+    # Check the user context.
+    query="SELECT user_context FROM lease6"
+    run_command \
+        mysql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
+    assert_str_eq 'NULL' "${OUTPUT}" "${query}: expected output %s, returned %s"
+}
+
 mysql_upgrade_test() {
 
     test_start "mysql.upgrade"
@@ -1054,7 +1178,7 @@ mysql_upgrade_test() {
 
     # Verify that the upgraded schema reports the latest version.
     version=$("${kea_admin}" db-version mysql -u "${db_user}" -p "${db_password}" -n "${db_name}" -d "${db_scripts_dir}")
-    assert_str_eq "29.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
+    assert_str_eq "30.0" "${version}" "Expected kea-admin to return %s, returned value was %s"
 
     # Let's check that the new tables are indeed there.
 
@@ -1738,6 +1862,9 @@ SET @disable_audit = 0"
     # Check upgrade from 28.0 to 29.0.
     mysql_upgrade_28_to_29_test
 
+    # Check upgrade from 29.0 to 30.0.
+    mysql_upgrade_29_to_30_test
+
     # Let's wipe the whole database
     mysql_wipe
 
index f90638ec0b6ba65711c3c937bbb28fdb2e352d50..c3b9a9a2ce413ab4d274f17719920f38ad5b9f63 100755 (executable)
@@ -906,10 +906,10 @@ pgsql_upgrade_18_to_19_test() {
 pgsql_upgrade_19_to_20_test() {
     # Verify that lease6_by_subnet_id_address index on lease6 is keyed by
     # attributes number 5 and 1 (i.e. subnet-id and address)
-    qry="select ix.indkey as keys from pg_class t, pg_class i, pg_index ix \
+    query="select ix.indkey as keys from pg_class t, pg_class i, pg_index ix \
         where t.oid = ix.indrelid and i.oid = ix.indexrelid and \
         i.relname = 'lease6_by_subnet_id_address' and t.relname = 'lease6';"
-    run_statement "verify lease6_by_subnet_id_address" "$qry"
+    run_statement "verify lease6_by_subnet_id_address" "${query}"
     assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
     assert_str_eq '5 1' "${OUTPUT}" "${query}: expected output %s, returned %s"
 }
@@ -917,10 +917,10 @@ pgsql_upgrade_19_to_20_test() {
 pgsql_upgrade_20_to_21_test() {
     # Verify that dhcp4_server_modification_ts index on dhcp4_server is keyed by
     # attribute number 4, modification_ts
-    qry="select ix.indkey as keys from pg_class t, pg_class i, pg_index ix \
+    query="select ix.indkey as keys from pg_class t, pg_class i, pg_index ix \
         where t.oid = ix.indrelid and i.oid = ix.indexrelid and \
         i.relname = 'dhcp4_server_modification_ts' and t.relname = 'dhcp4_server';"
-    run_statement "verify lease6_by_subnet_id_address" "$qry"
+    run_statement "verify lease6_by_subnet_id_address" "${query}"
     assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
     assert_str_eq '4' "${OUTPUT}" "${query}: expected output %s, returned %s"
 }
@@ -940,106 +940,106 @@ pgsql_upgrade_23_to_24_test() {
     assert_eq 0 "${EXIT_CODE}" "${query}: expected %d, returned %d"
     assert_str_eq '18' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 0"
+    query="select name from option_def_data_type where id = 0"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'empty' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 1"
+    query="select name from option_def_data_type where id = 1"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'binary' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 2"
+    query="select name from option_def_data_type where id = 2"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'boolean' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 4"
+    query="select name from option_def_data_type where id = 4"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'int16' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 5"
+    query="select name from option_def_data_type where id = 5"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'int32' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 6"
+    query="select name from option_def_data_type where id = 6"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'uint8' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 7"
+    query="select name from option_def_data_type where id = 7"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'uint16' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 8"
+    query="select name from option_def_data_type where id = 8"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'uint32' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 10"
+    query="select name from option_def_data_type where id = 10"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'ipv4-address' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 11"
+    query="select name from option_def_data_type where id = 11"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'ipv6-address' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 12"
+    query="select name from option_def_data_type where id = 12"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'ipv6-prefix' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 13"
+    query="select name from option_def_data_type where id = 13"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'psid' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 14"
+    query="select name from option_def_data_type where id = 14"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'string' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 15"
+    query="select name from option_def_data_type where id = 15"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'tuple' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 16"
+    query="select name from option_def_data_type where id = 16"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'fqdn' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 17"
+    query="select name from option_def_data_type where id = 17"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'internal' "${OUTPUT}" "${query}: expected output %s, returned %s"
 
-    qry="select name from option_def_data_type where id = 254"
+    query="select name from option_def_data_type where id = 254"
     run_command \
-        pgsql_execute "${qry}"
-    assert_eq 0 "${EXIT_CODE}" "${qry}. (expected status code %d, returned %d)"
+        pgsql_execute "${query}"
+    assert_eq 0 "${EXIT_CODE}" "${query}. (expected status code %d, returned %d)"
     assert_str_eq 'record' "${OUTPUT}" "${query}: expected output %s, returned %s"
 }
 
index bb787bbec737039eba82aae146a6fec18a98fa1f..c741819be291f9f03e32f206a6d25f78cb1214da 100644 (file)
@@ -52,7 +52,7 @@ const int MLM_MYSQL_FETCH_FAILURE = 0;
 
 /// @name Current database schema version values.
 //@{
-const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 29;
+const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 30;
 const uint32_t MYSQL_SCHEMA_VERSION_MINOR = 0;
 
 //@}
index b74e05b3df8d76a33bfd1c4bcd6c31db2929787e..11f94eb07ad4cad70a6c6a6dd37441f86e319ea0 100644 (file)
@@ -37,4 +37,5 @@
 /upgrade_026_to_027.sh
 /upgrade_027_to_028.sh
 /upgrade_028_to_029.sh
+/upgrade_029_to_030.sh
 /wipe_data.sh
index 38cbe66c66428414bd4e90d3825c57f3c3a6211e..117d87b122c38408ff36712c8a02d0aaa7ce4292 100644 (file)
@@ -48,6 +48,7 @@ mysql_SCRIPTS += upgrade_025_to_026.sh
 mysql_SCRIPTS += upgrade_026_to_027.sh
 mysql_SCRIPTS += upgrade_027_to_028.sh
 mysql_SCRIPTS += upgrade_028_to_029.sh
+mysql_SCRIPTS += upgrade_029_to_030.sh
 mysql_SCRIPTS += wipe_data.sh
 
 DISTCLEANFILES = ${mysql_SCRIPTS}
index 0f001bc9b9eedfb53cf199b35c946d368f399bf5..a38bb32bd6d29b89088d5f2bf32131705eecf662 100644 (file)
@@ -6297,6 +6297,145 @@ UPDATE schema_version
 
 -- This line concludes the schema upgrade to version 29.0.
 
+-- This line starts the schema upgrade to version 30.0.
+
+-- Add continue handlers to the lease*_AUPD_lease*_stat_by_client_class.
+-- The same continue handlers existed in the AINS and ADEL triggers.
+
+DROP PROCEDURE IF EXISTS lease4_AUPD_lease4_stat_by_client_class;
+DELIMITER $$
+CREATE PROCEDURE lease4_AUPD_lease4_stat_by_client_class(IN old_state TINYINT,
+                                                         IN old_user_context TEXT,
+                                                         IN new_state TINYINT,
+                                                         IN new_user_context TEXT)
+BEGIN
+    -- Declarations
+    DECLARE old_client_classes TEXT;
+    DECLARE new_client_classes TEXT;
+    DECLARE class VARCHAR(255);
+    DECLARE length INT;
+    DECLARE i INT;
+
+    -- Ignore ERROR 3141 (22032) at line 1: Invalid JSON text in argument 1 to
+    --      function json_extract: "The document is empty." at position 0.
+    -- Ignore ERROR 4037 (HY000): Unexpected end of JSON text in argument 1 to function 'json_extract'
+    -- These situations are handled with a propagating NULL result from JSON_EXTRACT.
+    DECLARE CONTINUE HANDLER FOR 3141 BEGIN END;
+    DECLARE CONTINUE HANDLER FOR 4037 BEGIN END;
+
+    SET old_client_classes = JSON_EXTRACT(old_user_context, '$."ISC"."client-classes"');
+    SET new_client_classes = JSON_EXTRACT(new_user_context, '$."ISC"."client-classes"');
+
+    IF old_state != new_state OR old_client_classes != new_client_classes THEN
+        -- Check if it's moving away from a counted state.
+        IF old_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(old_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(old_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Decrement the lease count if the record exists.
+                UPDATE lease4_stat_by_client_class SET leases = IF(leases > 0, leases - 1, 0)
+                    WHERE client_class = class;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+
+        -- Check if it's moving into a counted state.
+        IF new_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(new_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(new_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Upsert to increment the lease count.
+                UPDATE lease4_stat_by_client_class SET leases = leases + 1
+                    WHERE client_class = class;
+                IF ROW_COUNT() <= 0 THEN
+                    INSERT INTO lease4_stat_by_client_class VALUES (class, 1);
+                END IF;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+    END IF;
+END $$
+DELIMITER ;
+
+DROP PROCEDURE IF EXISTS lease6_AUPD_lease6_stat_by_client_class;
+DELIMITER $$
+CREATE PROCEDURE lease6_AUPD_lease6_stat_by_client_class(IN old_state TINYINT,
+                                                         IN old_user_context TEXT,
+                                                         IN old_lease_type TINYINT,
+                                                         IN new_state TINYINT,
+                                                         IN new_user_context TEXT,
+                                                         IN new_lease_type TINYINT)
+BEGIN
+    -- Declarations
+    DECLARE old_client_classes TEXT;
+    DECLARE new_client_classes TEXT;
+    DECLARE class VARCHAR(255);
+    DECLARE length INT;
+    DECLARE i INT;
+
+    -- Ignore ERROR 3141 (22032) at line 1: Invalid JSON text in argument 1 to
+    --      function json_extract: "The document is empty." at position 0.
+    -- Ignore ERROR 4037 (HY000): Unexpected end of JSON text in argument 1 to function 'json_extract'
+    -- These situations are handled with a propagating NULL result from JSON_EXTRACT.
+    DECLARE CONTINUE HANDLER FOR 3141 BEGIN END;
+    DECLARE CONTINUE HANDLER FOR 4037 BEGIN END;
+
+    SET old_client_classes = JSON_EXTRACT(old_user_context, '$."ISC"."client-classes"');
+    SET new_client_classes = JSON_EXTRACT(new_user_context, '$."ISC"."client-classes"');
+
+    IF old_state != new_state OR old_client_classes != new_client_classes OR old_lease_type != new_lease_type THEN
+        -- Check if it's moving away from a counted state.
+        IF old_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(old_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(old_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Decrement the lease count if the record exists.
+                UPDATE lease6_stat_by_client_class SET leases = IF(leases > 0, leases - 1, 0)
+                    WHERE client_class = class AND lease_type = old_lease_type;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+
+        -- Check if it's moving into a counted state.
+        IF new_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(new_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(new_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Upsert to increment the lease count.
+                UPDATE lease6_stat_by_client_class SET leases = leases + 1
+                    WHERE client_class = class AND lease_type = new_lease_type;
+                IF ROW_COUNT() <= 0 THEN
+                    INSERT INTO lease6_stat_by_client_class VALUES (class, new_lease_type, 1);
+                END IF;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+    END IF;
+END $$
+DELIMITER ;
+
+-- Update the schema version number.
+UPDATE schema_version
+    SET version = '30', minor = '0';
+
+-- This line concludes the schema upgrade to version 30.0.
+
 # Notes:
 #
 # Indexes
index d8cc25d57d8e9202d740d52d6c241855a5d58fea..a4298f284b4f3bfd56612fb9c6782e68629b1e90 100644 (file)
@@ -66,6 +66,7 @@ upgrade_scripts = [
     'upgrade_026_to_027.sh',
     'upgrade_027_to_028.sh',
     'upgrade_028_to_029.sh',
+    'upgrade_029_to_030.sh',
 ]
 list = run_command(
     GRABBER,
diff --git a/src/share/database/scripts/mysql/upgrade_029_to_030.sh.in b/src/share/database/scripts/mysql/upgrade_029_to_030.sh.in
new file mode 100755 (executable)
index 0000000..e5675cd
--- /dev/null
@@ -0,0 +1,196 @@
+#!/bin/sh
+
+# Copyright (C) 2025 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/.
+
+# Exit with error if commands exit with non-zero and if undefined variables are
+# used.
+set -eu
+
+# shellcheck disable=SC2034
+# SC2034: ... appears unused. Verify use (or export if used externally).
+prefix="@prefix@"
+
+# Include utilities based on location of this script. Check for sources first,
+# so that the unexpected situations with weird paths fall on the default
+# case of installed.
+script_path=$(cd "$(dirname "${0}")" && pwd)
+if test "${script_path}" = "@abs_top_builddir@/src/share/database/scripts/mysql"; then
+    # shellcheck source=./src/bin/admin/admin-utils.sh.in
+    . "@abs_top_builddir@/src/bin/admin/admin-utils.sh"
+else
+    # shellcheck source=./src/bin/admin/admin-utils.sh.in
+    . "@datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh"
+fi
+
+# Check version.
+version=$(mysql_version "${@}")
+if test "${version}" != "29.0"; then
+    printf 'This script upgrades 29.0 to 30.0. '
+    printf 'Reported version is %s. Skipping upgrade.\n' "${version}"
+    exit 0
+fi
+
+# Get the schema name from database argument. We need this to
+# query information_schema for the right database.
+for arg in "${@}"
+do
+    if ! printf '%s' "${arg}" | grep -Eq -- '^--'
+    then
+        schema="$arg"
+        break
+    fi
+done
+
+# Make sure we have the schema.
+if [ -z "$schema" ]
+then
+    printf "Could not find database schema name in cmd line args: %s\n" "${*}"
+    exit 255
+fi
+
+mysql "$@" <<EOF
+
+-- This line starts the schema upgrade to version 30.0.
+
+-- Add continue handlers to the lease*_AUPD_lease*_stat_by_client_class.
+-- The same continue handlers existed in the AINS and ADEL triggers.
+
+DROP PROCEDURE IF EXISTS lease4_AUPD_lease4_stat_by_client_class;
+DELIMITER $$
+CREATE PROCEDURE lease4_AUPD_lease4_stat_by_client_class(IN old_state TINYINT,
+                                                         IN old_user_context TEXT,
+                                                         IN new_state TINYINT,
+                                                         IN new_user_context TEXT)
+BEGIN
+    -- Declarations
+    DECLARE old_client_classes TEXT;
+    DECLARE new_client_classes TEXT;
+    DECLARE class VARCHAR(255);
+    DECLARE length INT;
+    DECLARE i INT;
+
+    -- Ignore ERROR 3141 (22032) at line 1: Invalid JSON text in argument 1 to
+    --      function json_extract: "The document is empty." at position 0.
+    -- Ignore ERROR 4037 (HY000): Unexpected end of JSON text in argument 1 to function 'json_extract'
+    -- These situations are handled with a propagating NULL result from JSON_EXTRACT.
+    DECLARE CONTINUE HANDLER FOR 3141 BEGIN END;
+    DECLARE CONTINUE HANDLER FOR 4037 BEGIN END;
+
+    SET old_client_classes = JSON_EXTRACT(old_user_context, '$."ISC"."client-classes"');
+    SET new_client_classes = JSON_EXTRACT(new_user_context, '$."ISC"."client-classes"');
+
+    IF old_state != new_state OR old_client_classes != new_client_classes THEN
+        -- Check if it's moving away from a counted state.
+        IF old_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(old_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(old_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Decrement the lease count if the record exists.
+                UPDATE lease4_stat_by_client_class SET leases = IF(leases > 0, leases - 1, 0)
+                    WHERE client_class = class;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+
+        -- Check if it's moving into a counted state.
+        IF new_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(new_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(new_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Upsert to increment the lease count.
+                UPDATE lease4_stat_by_client_class SET leases = leases + 1
+                    WHERE client_class = class;
+                IF ROW_COUNT() <= 0 THEN
+                    INSERT INTO lease4_stat_by_client_class VALUES (class, 1);
+                END IF;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+    END IF;
+END $$
+DELIMITER ;
+
+DROP PROCEDURE IF EXISTS lease6_AUPD_lease6_stat_by_client_class;
+DELIMITER $$
+CREATE PROCEDURE lease6_AUPD_lease6_stat_by_client_class(IN old_state TINYINT,
+                                                         IN old_user_context TEXT,
+                                                         IN old_lease_type TINYINT,
+                                                         IN new_state TINYINT,
+                                                         IN new_user_context TEXT,
+                                                         IN new_lease_type TINYINT)
+BEGIN
+    -- Declarations
+    DECLARE old_client_classes TEXT;
+    DECLARE new_client_classes TEXT;
+    DECLARE class VARCHAR(255);
+    DECLARE length INT;
+    DECLARE i INT;
+
+    -- Ignore ERROR 3141 (22032) at line 1: Invalid JSON text in argument 1 to
+    --      function json_extract: "The document is empty." at position 0.
+    -- Ignore ERROR 4037 (HY000): Unexpected end of JSON text in argument 1 to function 'json_extract'
+    -- These situations are handled with a propagating NULL result from JSON_EXTRACT.
+    DECLARE CONTINUE HANDLER FOR 3141 BEGIN END;
+    DECLARE CONTINUE HANDLER FOR 4037 BEGIN END;
+
+    SET old_client_classes = JSON_EXTRACT(old_user_context, '$."ISC"."client-classes"');
+    SET new_client_classes = JSON_EXTRACT(new_user_context, '$."ISC"."client-classes"');
+
+    IF old_state != new_state OR old_client_classes != new_client_classes OR old_lease_type != new_lease_type THEN
+        -- Check if it's moving away from a counted state.
+        IF old_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(old_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(old_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Decrement the lease count if the record exists.
+                UPDATE lease6_stat_by_client_class SET leases = IF(leases > 0, leases - 1, 0)
+                    WHERE client_class = class AND lease_type = old_lease_type;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+
+        -- Check if it's moving into a counted state.
+        IF new_state = 0 THEN
+            -- Dive into client classes.
+            SET length = JSON_LENGTH(new_client_classes);
+            SET i = 0;
+            label: WHILE i < length DO
+                SET class = JSON_UNQUOTE(JSON_EXTRACT(new_client_classes, CONCAT('\$[', i, ']')));
+
+                -- Upsert to increment the lease count.
+                UPDATE lease6_stat_by_client_class SET leases = leases + 1
+                    WHERE client_class = class AND lease_type = new_lease_type;
+                IF ROW_COUNT() <= 0 THEN
+                    INSERT INTO lease6_stat_by_client_class VALUES (class, new_lease_type, 1);
+                END IF;
+
+                SET i = i + 1;
+            END WHILE label;
+        END IF;
+    END IF;
+END $$
+DELIMITER ;
+
+-- Update the schema version number.
+UPDATE schema_version
+    SET version = '30', minor = '0';
+
+-- This line concludes the schema upgrade to version 30.0.
+
+EOF