diff --git a/.github/workflows/liquibase-upgrade.yml b/.github/workflows/liquibase-upgrade.yml
index 72f96bb..ee90c12 100644
--- a/.github/workflows/liquibase-upgrade.yml
+++ b/.github/workflows/liquibase-upgrade.yml
@@ -9,6 +9,7 @@ on:
- 'tools/tests/test_liquibase_1.2.7_to_head_upgrade.sh'
- 'tools/tests/test_liquibase_codelist_auth_mode_swap.sh'
- 'tools/tests/test_prepare_extracted_liquibase.py'
+ - 'tools/tests/test_service_check_observed_rebuild_order.py'
- 'tools/bin/prepare_extracted_liquibase.py'
- '.github/workflows/liquibase-upgrade.yml'
workflow_dispatch:
@@ -29,6 +30,9 @@ jobs:
- name: Extracted-tree helper unit tests
run: python3 tools/tests/test_prepare_extracted_liquibase.py
+ - name: Service-check observed rebuild order
+ run: python3 tools/tests/test_service_check_observed_rebuild_order.py
+
postgres-1-2-7-to-head:
runs-on: ubuntu-latest
timeout-minutes: 20
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e40f96b..e5e89e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -101,6 +101,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
#### Profile-level
- **Liquibase**: Development changelog 89, and PostgreSQL and Oracle changelog 33, alter `STM_SERVICE_CHECK.SEC_OBSERVED` and `STM_SERVICE_CHECK_SAMPLE.SCS_OBSERVED` to `TIMESTAMP(6) WITH TIME ZONE` on Oracle ([sitmun-admin-app#516](https://github.com/sitmun/sitmun-admin-app/issues/516)).
+- **Liquibase**: Development changelog 91, and PostgreSQL and Oracle changelog 35, copy populated `SEC_OBSERVED` and `SCS_OBSERVED` values as UTC before that `ALTER`. The `ALTER` changesets are unchanged ([#135](https://github.com/sitmun/sitmun-application-stack/issues/135)).
### Security
diff --git a/back/backend/sitmun-backend-core b/back/backend/sitmun-backend-core
index a9ba615..747461c 160000
--- a/back/backend/sitmun-backend-core
+++ b/back/backend/sitmun-backend-core
@@ -1 +1 @@
-Subproject commit a9ba615be04b2cb1e17e9d587a39658754d82b9f
+Subproject commit 747461c4c481ffe3b1e418f010bc984285717399
diff --git a/profiles/development/backend/liquibase/changelog/91_service_check_observed_timestamptz_rebuild.sql b/profiles/development/backend/liquibase/changelog/91_service_check_observed_timestamptz_rebuild.sql
new file mode 100644
index 0000000..b60a42d
--- /dev/null
+++ b/profiles/development/backend/liquibase/changelog/91_service_check_observed_timestamptz_rebuild.sql
@@ -0,0 +1,103 @@
+--liquibase formatted sql
+
+-- Oracle raises ORA-01439 when ALTER MODIFY changes TIMESTAMP to
+-- TIMESTAMP WITH TIME ZONE and the column already has values.
+-- Copy each value onto a new column as UTC. The backend stores these
+-- instants with hibernate.jdbc.time_zone set to UTC.
+-- The later ALTER changeset sees TIMESTAMP(6) WITH TIME ZONE and is skipped.
+
+--changeset sitmun:91-service-check-sec-observed-rebuild-oracle dbms:oracle splitStatements:false endDelimiter:/
+DECLARE
+ l_type VARCHAR2(128);
+ l_tz NUMBER;
+ l_nullable VARCHAR2(1);
+BEGIN
+ BEGIN
+ SELECT data_type, nullable INTO l_type, l_nullable
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK' AND column_name = 'SEC_OBSERVED';
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ l_type := NULL;
+ l_nullable := NULL;
+ END;
+
+ SELECT COUNT(*) INTO l_tz
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK' AND column_name = 'SEC_OBSERVED_TZ';
+
+ IF l_type LIKE '%WITH TIME ZONE' THEN
+ IF l_nullable = 'Y' THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED NOT NULL)';
+ END IF;
+ IF l_tz = 1 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK DROP COLUMN SEC_OBSERVED_TZ';
+ END IF;
+ ELSE
+ IF l_tz = 0 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK ADD (SEC_OBSERVED_TZ TIMESTAMP(6) WITH TIME ZONE)';
+ END IF;
+ IF l_type IS NOT NULL THEN
+ EXECUTE IMMEDIATE 'UPDATE STM_SERVICE_CHECK SET SEC_OBSERVED_TZ = FROM_TZ(SEC_OBSERVED, ''UTC'') WHERE SEC_OBSERVED_TZ IS NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED_TZ NOT NULL)';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK DROP COLUMN SEC_OBSERVED';
+ ELSE
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED_TZ NOT NULL)';
+ END IF;
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK RENAME COLUMN SEC_OBSERVED_TZ TO SEC_OBSERVED';
+ END IF;
+END;
+/
+
+--changeset sitmun:91-service-check-scs-observed-rebuild-oracle dbms:oracle splitStatements:false endDelimiter:/
+DECLARE
+ l_type VARCHAR2(128);
+ l_tz NUMBER;
+ l_idx NUMBER;
+ l_nullable VARCHAR2(1);
+BEGIN
+ BEGIN
+ SELECT data_type, nullable INTO l_type, l_nullable
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK_SAMPLE' AND column_name = 'SCS_OBSERVED';
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ l_type := NULL;
+ l_nullable := NULL;
+ END;
+
+ SELECT COUNT(*) INTO l_tz
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK_SAMPLE' AND column_name = 'SCS_OBSERVED_TZ';
+
+ IF l_type LIKE '%WITH TIME ZONE' THEN
+ IF l_nullable = 'Y' THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED NOT NULL)';
+ END IF;
+ IF l_tz = 1 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE DROP COLUMN SCS_OBSERVED_TZ';
+ END IF;
+ ELSE
+ SELECT COUNT(*) INTO l_idx FROM user_indexes WHERE index_name = 'STM_SCS_IX_SER_OBS';
+ IF l_idx = 1 THEN
+ EXECUTE IMMEDIATE 'DROP INDEX STM_SCS_IX_SER_OBS';
+ END IF;
+ IF l_tz = 0 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE ADD (SCS_OBSERVED_TZ TIMESTAMP(6) WITH TIME ZONE)';
+ END IF;
+ IF l_type IS NOT NULL THEN
+ EXECUTE IMMEDIATE 'UPDATE STM_SERVICE_CHECK_SAMPLE SET SCS_OBSERVED_TZ = FROM_TZ(SCS_OBSERVED, ''UTC'') WHERE SCS_OBSERVED_TZ IS NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED_TZ NOT NULL)';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE DROP COLUMN SCS_OBSERVED';
+ ELSE
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED_TZ NOT NULL)';
+ END IF;
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE RENAME COLUMN SCS_OBSERVED_TZ TO SCS_OBSERVED';
+ END IF;
+
+ SELECT COUNT(*) INTO l_idx FROM user_indexes WHERE index_name = 'STM_SCS_IX_SER_OBS';
+ IF l_idx = 0 THEN
+ EXECUTE IMMEDIATE 'CREATE INDEX STM_SCS_IX_SER_OBS ON STM_SERVICE_CHECK_SAMPLE (SCS_SERID, SCS_OBSERVED)';
+ END IF;
+END;
+/
diff --git a/profiles/development/backend/liquibase/master.xml b/profiles/development/backend/liquibase/master.xml
index f75d145..f84e17f 100644
--- a/profiles/development/backend/liquibase/master.xml
+++ b/profiles/development/backend/liquibase/master.xml
@@ -95,6 +95,8 @@
+
+
diff --git a/profiles/oracle/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql b/profiles/oracle/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql
new file mode 100644
index 0000000..bfd6a86
--- /dev/null
+++ b/profiles/oracle/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql
@@ -0,0 +1,103 @@
+--liquibase formatted sql
+
+-- Oracle raises ORA-01439 when ALTER MODIFY changes TIMESTAMP to
+-- TIMESTAMP WITH TIME ZONE and the column already has values.
+-- Copy each value onto a new column as UTC. The backend stores these
+-- instants with hibernate.jdbc.time_zone set to UTC.
+-- The later ALTER changeset sees TIMESTAMP(6) WITH TIME ZONE and is skipped.
+
+--changeset sitmun:35-service-check-sec-observed-rebuild-oracle dbms:oracle splitStatements:false endDelimiter:/
+DECLARE
+ l_type VARCHAR2(128);
+ l_tz NUMBER;
+ l_nullable VARCHAR2(1);
+BEGIN
+ BEGIN
+ SELECT data_type, nullable INTO l_type, l_nullable
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK' AND column_name = 'SEC_OBSERVED';
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ l_type := NULL;
+ l_nullable := NULL;
+ END;
+
+ SELECT COUNT(*) INTO l_tz
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK' AND column_name = 'SEC_OBSERVED_TZ';
+
+ IF l_type LIKE '%WITH TIME ZONE' THEN
+ IF l_nullable = 'Y' THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED NOT NULL)';
+ END IF;
+ IF l_tz = 1 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK DROP COLUMN SEC_OBSERVED_TZ';
+ END IF;
+ ELSE
+ IF l_tz = 0 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK ADD (SEC_OBSERVED_TZ TIMESTAMP(6) WITH TIME ZONE)';
+ END IF;
+ IF l_type IS NOT NULL THEN
+ EXECUTE IMMEDIATE 'UPDATE STM_SERVICE_CHECK SET SEC_OBSERVED_TZ = FROM_TZ(SEC_OBSERVED, ''UTC'') WHERE SEC_OBSERVED_TZ IS NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED_TZ NOT NULL)';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK DROP COLUMN SEC_OBSERVED';
+ ELSE
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED_TZ NOT NULL)';
+ END IF;
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK RENAME COLUMN SEC_OBSERVED_TZ TO SEC_OBSERVED';
+ END IF;
+END;
+/
+
+--changeset sitmun:35-service-check-scs-observed-rebuild-oracle dbms:oracle splitStatements:false endDelimiter:/
+DECLARE
+ l_type VARCHAR2(128);
+ l_tz NUMBER;
+ l_idx NUMBER;
+ l_nullable VARCHAR2(1);
+BEGIN
+ BEGIN
+ SELECT data_type, nullable INTO l_type, l_nullable
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK_SAMPLE' AND column_name = 'SCS_OBSERVED';
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ l_type := NULL;
+ l_nullable := NULL;
+ END;
+
+ SELECT COUNT(*) INTO l_tz
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK_SAMPLE' AND column_name = 'SCS_OBSERVED_TZ';
+
+ IF l_type LIKE '%WITH TIME ZONE' THEN
+ IF l_nullable = 'Y' THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED NOT NULL)';
+ END IF;
+ IF l_tz = 1 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE DROP COLUMN SCS_OBSERVED_TZ';
+ END IF;
+ ELSE
+ SELECT COUNT(*) INTO l_idx FROM user_indexes WHERE index_name = 'STM_SCS_IX_SER_OBS';
+ IF l_idx = 1 THEN
+ EXECUTE IMMEDIATE 'DROP INDEX STM_SCS_IX_SER_OBS';
+ END IF;
+ IF l_tz = 0 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE ADD (SCS_OBSERVED_TZ TIMESTAMP(6) WITH TIME ZONE)';
+ END IF;
+ IF l_type IS NOT NULL THEN
+ EXECUTE IMMEDIATE 'UPDATE STM_SERVICE_CHECK_SAMPLE SET SCS_OBSERVED_TZ = FROM_TZ(SCS_OBSERVED, ''UTC'') WHERE SCS_OBSERVED_TZ IS NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED_TZ NOT NULL)';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE DROP COLUMN SCS_OBSERVED';
+ ELSE
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED_TZ NOT NULL)';
+ END IF;
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE RENAME COLUMN SCS_OBSERVED_TZ TO SCS_OBSERVED';
+ END IF;
+
+ SELECT COUNT(*) INTO l_idx FROM user_indexes WHERE index_name = 'STM_SCS_IX_SER_OBS';
+ IF l_idx = 0 THEN
+ EXECUTE IMMEDIATE 'CREATE INDEX STM_SCS_IX_SER_OBS ON STM_SERVICE_CHECK_SAMPLE (SCS_SERID, SCS_OBSERVED)';
+ END IF;
+END;
+/
diff --git a/profiles/oracle/liquibase/master.xml b/profiles/oracle/liquibase/master.xml
index 6d0ee84..68c5d53 100644
--- a/profiles/oracle/liquibase/master.xml
+++ b/profiles/oracle/liquibase/master.xml
@@ -37,6 +37,8 @@
+
+
diff --git a/profiles/postgres/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql b/profiles/postgres/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql
new file mode 100644
index 0000000..bfd6a86
--- /dev/null
+++ b/profiles/postgres/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql
@@ -0,0 +1,103 @@
+--liquibase formatted sql
+
+-- Oracle raises ORA-01439 when ALTER MODIFY changes TIMESTAMP to
+-- TIMESTAMP WITH TIME ZONE and the column already has values.
+-- Copy each value onto a new column as UTC. The backend stores these
+-- instants with hibernate.jdbc.time_zone set to UTC.
+-- The later ALTER changeset sees TIMESTAMP(6) WITH TIME ZONE and is skipped.
+
+--changeset sitmun:35-service-check-sec-observed-rebuild-oracle dbms:oracle splitStatements:false endDelimiter:/
+DECLARE
+ l_type VARCHAR2(128);
+ l_tz NUMBER;
+ l_nullable VARCHAR2(1);
+BEGIN
+ BEGIN
+ SELECT data_type, nullable INTO l_type, l_nullable
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK' AND column_name = 'SEC_OBSERVED';
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ l_type := NULL;
+ l_nullable := NULL;
+ END;
+
+ SELECT COUNT(*) INTO l_tz
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK' AND column_name = 'SEC_OBSERVED_TZ';
+
+ IF l_type LIKE '%WITH TIME ZONE' THEN
+ IF l_nullable = 'Y' THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED NOT NULL)';
+ END IF;
+ IF l_tz = 1 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK DROP COLUMN SEC_OBSERVED_TZ';
+ END IF;
+ ELSE
+ IF l_tz = 0 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK ADD (SEC_OBSERVED_TZ TIMESTAMP(6) WITH TIME ZONE)';
+ END IF;
+ IF l_type IS NOT NULL THEN
+ EXECUTE IMMEDIATE 'UPDATE STM_SERVICE_CHECK SET SEC_OBSERVED_TZ = FROM_TZ(SEC_OBSERVED, ''UTC'') WHERE SEC_OBSERVED_TZ IS NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED_TZ NOT NULL)';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK DROP COLUMN SEC_OBSERVED';
+ ELSE
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED_TZ NOT NULL)';
+ END IF;
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK RENAME COLUMN SEC_OBSERVED_TZ TO SEC_OBSERVED';
+ END IF;
+END;
+/
+
+--changeset sitmun:35-service-check-scs-observed-rebuild-oracle dbms:oracle splitStatements:false endDelimiter:/
+DECLARE
+ l_type VARCHAR2(128);
+ l_tz NUMBER;
+ l_idx NUMBER;
+ l_nullable VARCHAR2(1);
+BEGIN
+ BEGIN
+ SELECT data_type, nullable INTO l_type, l_nullable
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK_SAMPLE' AND column_name = 'SCS_OBSERVED';
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ l_type := NULL;
+ l_nullable := NULL;
+ END;
+
+ SELECT COUNT(*) INTO l_tz
+ FROM user_tab_columns
+ WHERE table_name = 'STM_SERVICE_CHECK_SAMPLE' AND column_name = 'SCS_OBSERVED_TZ';
+
+ IF l_type LIKE '%WITH TIME ZONE' THEN
+ IF l_nullable = 'Y' THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED NOT NULL)';
+ END IF;
+ IF l_tz = 1 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE DROP COLUMN SCS_OBSERVED_TZ';
+ END IF;
+ ELSE
+ SELECT COUNT(*) INTO l_idx FROM user_indexes WHERE index_name = 'STM_SCS_IX_SER_OBS';
+ IF l_idx = 1 THEN
+ EXECUTE IMMEDIATE 'DROP INDEX STM_SCS_IX_SER_OBS';
+ END IF;
+ IF l_tz = 0 THEN
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE ADD (SCS_OBSERVED_TZ TIMESTAMP(6) WITH TIME ZONE)';
+ END IF;
+ IF l_type IS NOT NULL THEN
+ EXECUTE IMMEDIATE 'UPDATE STM_SERVICE_CHECK_SAMPLE SET SCS_OBSERVED_TZ = FROM_TZ(SCS_OBSERVED, ''UTC'') WHERE SCS_OBSERVED_TZ IS NULL';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED_TZ NOT NULL)';
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE DROP COLUMN SCS_OBSERVED';
+ ELSE
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE MODIFY (SCS_OBSERVED_TZ NOT NULL)';
+ END IF;
+ EXECUTE IMMEDIATE 'ALTER TABLE STM_SERVICE_CHECK_SAMPLE RENAME COLUMN SCS_OBSERVED_TZ TO SCS_OBSERVED';
+ END IF;
+
+ SELECT COUNT(*) INTO l_idx FROM user_indexes WHERE index_name = 'STM_SCS_IX_SER_OBS';
+ IF l_idx = 0 THEN
+ EXECUTE IMMEDIATE 'CREATE INDEX STM_SCS_IX_SER_OBS ON STM_SERVICE_CHECK_SAMPLE (SCS_SERID, SCS_OBSERVED)';
+ END IF;
+END;
+/
diff --git a/profiles/postgres/liquibase/master.xml b/profiles/postgres/liquibase/master.xml
index e4d8f6f..e951da9 100644
--- a/profiles/postgres/liquibase/master.xml
+++ b/profiles/postgres/liquibase/master.xml
@@ -35,6 +35,8 @@
+
+
diff --git a/tools/tests/test_service_check_observed_rebuild_order.py b/tools/tests/test_service_check_observed_rebuild_order.py
new file mode 100644
index 0000000..159bd74
--- /dev/null
+++ b/tools/tests/test_service_check_observed_rebuild_order.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+"""Oracle service-check timestamptz rebuild runs before the empty-column ALTER."""
+
+from __future__ import annotations
+
+import unittest
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[2]
+
+TREES = (
+ (
+ "profiles/oracle/liquibase/master.xml",
+ "35_service_check_observed_timestamptz_rebuild.sql",
+ "33_service_check_observed_timestamptz.yaml",
+ "profiles/oracle/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql",
+ ),
+ (
+ "profiles/postgres/liquibase/master.xml",
+ "35_service_check_observed_timestamptz_rebuild.sql",
+ "33_service_check_observed_timestamptz.yaml",
+ "profiles/postgres/liquibase/changelog/35_service_check_observed_timestamptz_rebuild.sql",
+ ),
+ (
+ "profiles/development/backend/liquibase/master.xml",
+ "91_service_check_observed_timestamptz_rebuild.sql",
+ "89_service_check_observed_timestamptz.yaml",
+ "profiles/development/backend/liquibase/changelog/91_service_check_observed_timestamptz_rebuild.sql",
+ ),
+)
+
+
+class ServiceCheckObservedRebuildOrderTest(unittest.TestCase):
+ def test_rebuild_is_included_before_empty_column_alter(self) -> None:
+ for master_rel, rebuild_name, alter_name, rebuild_rel in TREES:
+ master = (ROOT / master_rel).read_text(encoding="utf-8")
+ rebuild_at = master.find(rebuild_name)
+ alter_at = master.find(alter_name)
+ self.assertGreaterEqual(rebuild_at, 0, master_rel)
+ self.assertGreaterEqual(alter_at, 0, master_rel)
+ self.assertLess(rebuild_at, alter_at, master_rel)
+
+ rebuild = (ROOT / rebuild_rel).read_text(encoding="utf-8")
+ self.assertIn(
+ "UPDATE STM_SERVICE_CHECK SET SEC_OBSERVED_TZ = FROM_TZ(SEC_OBSERVED, ''UTC'')",
+ rebuild,
+ )
+ self.assertIn(
+ "UPDATE STM_SERVICE_CHECK_SAMPLE SET SCS_OBSERVED_TZ = FROM_TZ(SCS_OBSERVED, ''UTC'')",
+ rebuild,
+ )
+ self.assertNotIn("DELETE FROM STM_SERVICE_CHECK", rebuild)
+ self.assertIn("dbms:oracle", rebuild)
+
+ alter = (ROOT / master_rel).parent.joinpath("changelog", alter_name).read_text(
+ encoding="utf-8"
+ )
+ self.assertIn(
+ "ALTER TABLE STM_SERVICE_CHECK MODIFY (SEC_OBSERVED TIMESTAMP(6) WITH TIME ZONE)",
+ alter,
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()