Blame | Last modification | View Log | RSS feed
-- Migration: Scheme Item Windowing (BRD Scheme-Item-Windowing)-- Adds surrogate PK, audit columns, unique constraint, and safety triggers to fofo.scheme_item-- Step 1: Add surrogate PK and audit columnsALTER TABLE fofo.scheme_itemDROP PRIMARY KEY,ADD COLUMN id BIGINT AUTO_INCREMENT PRIMARY KEY FIRST,ADD COLUMN updated_by INT NULL,ADD COLUMN updated_on TIMESTAMP NULL DEFAULT NULL;-- Step 2: Backfill audit columns from existing dataUPDATE fofo.scheme_item SET updated_on = create_timestamp WHERE updated_on IS NULL;-- Step 3: Add unique key on the 4-column business keyALTER TABLE fofo.scheme_itemADD UNIQUE KEY uk_scheme_item_window (catalog_id, scheme_id, start_date, end_date);-- Step 4: Add index for date-driven lookupsCREATE INDEX idx_scheme_item_date_lookup ON fofo.scheme_item (catalog_id, scheme_id, start_date, end_date);-- Step 4b: Drop the legacy 2-column unique constraint that survived the-- DROP PRIMARY KEY in step 1. Without this, the old uniqueness on-- (scheme_id, catalog_id) still blocks multiple windows for the same-- (scheme, catalog) pair — defeating the whole windowing feature.ALTER TABLE fofo.scheme_item DROP INDEX scheme_catalog;-- Step 5: Safety triggers (MySQL 5.7 — CHECK constraints are parsed but ignored)DELIMITER $$CREATE TRIGGER trg_scheme_item_bi BEFORE INSERT ON fofo.scheme_itemFOR EACH ROWBEGINDECLARE v_scheme_start DATETIME;DECLARE v_scheme_end DATETIME;DECLARE v_overlap_cnt INT;-- Validate start <= endIF NEW.start_date IS NOT NULL AND NEW.end_date IS NOT NULL AND NEW.start_date > NEW.end_date THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'scheme_item: start_date must be <= end_date';END IF;-- Validate containment within parent scheme windowIF NEW.start_date IS NOT NULL AND NEW.end_date IS NOT NULL THENSELECT start_date_time, end_date_time INTO v_scheme_start, v_scheme_endFROM catalog.scheme WHERE id = NEW.scheme_id;IF NEW.start_date < v_scheme_start OR NEW.end_date > v_scheme_end THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'scheme_item: window outside parent scheme window';END IF;-- Validate non-overlap within same (catalog_id, scheme_id)SELECT COUNT(*) INTO v_overlap_cnt FROM fofo.scheme_itemWHERE catalog_id = NEW.catalog_idAND scheme_id = NEW.scheme_idAND NEW.start_date < end_dateAND NEW.end_date > start_date;IF v_overlap_cnt > 0 THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'scheme_item: window overlaps existing row';END IF;END IF;END$$CREATE TRIGGER trg_scheme_item_bu BEFORE UPDATE ON fofo.scheme_itemFOR EACH ROWBEGINDECLARE v_scheme_start DATETIME;DECLARE v_scheme_end DATETIME;DECLARE v_overlap_cnt INT;-- Validate start <= endIF NEW.start_date IS NOT NULL AND NEW.end_date IS NOT NULL AND NEW.start_date > NEW.end_date THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'scheme_item: start_date must be <= end_date';END IF;-- Validate containment within parent scheme windowIF NEW.start_date IS NOT NULL AND NEW.end_date IS NOT NULL THENSELECT start_date_time, end_date_time INTO v_scheme_start, v_scheme_endFROM catalog.scheme WHERE id = NEW.scheme_id;IF NEW.start_date < v_scheme_start OR NEW.end_date > v_scheme_end THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'scheme_item: window outside parent scheme window';END IF;-- Validate non-overlap within same (catalog_id, scheme_id), excluding selfSELECT COUNT(*) INTO v_overlap_cnt FROM fofo.scheme_itemWHERE catalog_id = NEW.catalog_idAND scheme_id = NEW.scheme_idAND id <> NEW.idAND NEW.start_date < end_dateAND NEW.end_date > start_date;IF v_overlap_cnt > 0 THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'scheme_item: window overlaps existing row';END IF;END IF;END$$DELIMITER ;