#!/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="/usr"

# 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}" = "/build/kea/src/build/src/share/database/scripts/mysql"; then
    # shellcheck source=./src/bin/admin/admin-utils.sh.in
    . "/build/kea/src/build/src/bin/admin/admin-utils.sh"
else
    # shellcheck source=./src/bin/admin/admin-utils.sh.in
    . "${prefix}/share/kea/scripts/admin-utils.sh"
fi

# Check only major version to allow for intermediary backported schema changes.
version=$(mysql_version "${@}" | cut -d '.' -f 1)
if test "${version}" != '29'; then
    printf 'This script upgrades 29.* 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
