diff --git a/db/008_ci_item_rename.sql b/db/008_ci_item_rename.sql new file mode 100644 index 0000000..ddac90a --- /dev/null +++ b/db/008_ci_item_rename.sql @@ -0,0 +1,89 @@ +-- 008 - Re-key the seed on CI Server item names +-- +-- WHY. The point list delivered in August named the published values +-- PS_STN_WET_WELL_LEVEL and the like. Those were never CI Server names: they +-- came from the PLC-side generator, and the CI Server generator ignored them. +-- A corrected delivery on 2026-09-01 is keyed on the CI Server ITEM each point +-- feeds - AID.WRPS.STN.LEVEL - which is what the historian is keyed on too. +-- +-- WHY A MIGRATION AND NOT JUST A RELOAD. 001_schema.sql is CREATE TABLE IF NOT +-- EXISTS, so it will not add the three new columns to a table that already +-- exists, and deploy.sh only ever upserts - nothing deletes. Re-running the +-- seed load on its own would fail on the missing columns and, if it did not, +-- would leave 45 retired keys sitting beside their 45 replacements with two +-- foreign keys still pointing at the old ones. +-- +-- SAFE TO RE-RUN. Every step is guarded. On a fresh database created by +-- 001_schema.sql this does nothing at all. + +BEGIN; + +-- 1. The column change 001_schema.sql cannot make on an existing table. +ALTER TABLE historian_items ADD COLUMN IF NOT EXISTS ci_station TEXT; +ALTER TABLE historian_items ADD COLUMN IF NOT EXISTS ci_point TEXT; +ALTER TABLE historian_items ADD COLUMN IF NOT EXISTS poll_group TEXT; + +-- Carry the old value across before dropping it, so the column is not simply +-- lost if the seed reload is not run immediately after this migration. +UPDATE historian_items SET ci_point = scada_point + WHERE ci_point IS NULL + AND EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'historian_items' AND column_name = 'scada_point'); + +ALTER TABLE historian_items DROP COLUMN IF EXISTS scada_point; + +-- 2. Capture the mapping BEFORE anything is updated. historian_items.tag_id is +-- itself about to change, so a later lookup through it finds nothing - an +-- ordering bug that would have left alarm_bits pointing at deleted rows. +CREATE TEMP TABLE _rename ON COMMIT DROP AS +SELECT tag_id AS old_tag, item_name AS new_tag + FROM historian_items + WHERE tag_id LIKE 'PS!_%' ESCAPE '!'; + +-- Every alarm_bits key must be in that mapping, or we stop before touching +-- anything. A silently unmapped alarm is how an alarm count becomes wrong. +DO $$ +DECLARE unmapped INT; +BEGIN + SELECT count(*) INTO unmapped + FROM alarm_bits a + WHERE a.tag_id LIKE 'PS!_%' ESCAPE '!' + AND NOT EXISTS (SELECT 1 FROM _rename r WHERE r.old_tag = a.tag_id); + IF unmapped > 0 THEN + RAISE EXCEPTION '% alarm_bits rows have no item to move to', unmapped; + END IF; +END $$; + +-- 3. Give every retired key its replacement row, copying the old row's own +-- facts. The seed reload that follows overwrites these with the delivered +-- values; they exist here so the foreign keys below have somewhere to land. +INSERT INTO tags (tag_id, equipment_id, display_name, aliases, signal_type, + engineering_unit, range_low, range_high, alarm_setpoint_hi, + alarm_setpoint_lo, trip_setpoint, description) +SELECT r.new_tag, t.equipment_id, t.display_name, t.aliases, t.signal_type, + t.engineering_unit, t.range_low, t.range_high, t.alarm_setpoint_hi, + t.alarm_setpoint_lo, t.trip_setpoint, t.description + FROM _rename r JOIN tags t ON t.tag_id = r.old_tag +ON CONFLICT (tag_id) DO NOTHING; + +-- 4. Repoint both foreign keys, alarm_bits first so it still reads the mapping. +UPDATE alarm_bits a SET tag_id = r.new_tag + FROM _rename r WHERE a.tag_id = r.old_tag; + +UPDATE historian_items h SET tag_id = r.new_tag + FROM _rename r WHERE h.tag_id = r.old_tag; + +-- 5. Anything still referencing a retired key is a defect, not a leftover. +DO $$ +DECLARE orphans INT; +BEGIN + SELECT count(*) INTO orphans FROM alarm_bits WHERE tag_id LIKE 'PS!_%' ESCAPE '!'; + IF orphans > 0 THEN RAISE EXCEPTION 'alarm_bits still holds % retired keys', orphans; END IF; + SELECT count(*) INTO orphans FROM historian_items WHERE tag_id LIKE 'PS!_%' ESCAPE '!'; + IF orphans > 0 THEN RAISE EXCEPTION 'historian_items still holds % retired keys', orphans; END IF; +END $$; + +-- 6. Now unreferenced, so they can go. +DELETE FROM tags WHERE tag_id LIKE 'PS!_%' ESCAPE '!'; + +COMMIT;