Files
pgz-sport/_audit/data_integrity_20260505_0836/D_CONSTRAINTS.sql
T

117 lines
4.5 KiB
PL/PgSQL

-- pgz_sport.clanovi — schema lockdown DDL (Subagent D)
-- Author: dradulic@outlook.com / damir@rinet.one
-- Date: 2026-05-05
-- Description: Final, applied DDL. Pre-flight all-clean blocks below were
-- committed; SKIPPED candidates (length>=2 CHECK, klub+name+dob
-- UNIQUE) are documented in D_violations.md and intentionally
-- omitted here.
--
-- Row count at apply time: 3240 (live), 3243 (backup_20260505_0836).
-- Rollback hints: each block is independent and reversible via
-- ALTER TABLE pgz_sport.clanovi DROP CONSTRAINT ...;
-- DROP INDEX pgz_sport.clanovi_hns_uniq;
-- DROP TRIGGER clanovi_normalize_trigger ON pgz_sport.clanovi;
-- DROP FUNCTION pgz_sport.clanovi_normalize_fn();
-- ===========================================================================
-- C1: CHECK no internal CamelCase boundary (lower->upper letter pair)
-- Pre-flight violators: 0
-- ===========================================================================
BEGIN;
ALTER TABLE pgz_sport.clanovi
ADD CONSTRAINT clanovi_no_camelcase_chk
CHECK (
ime !~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]'
AND prezime !~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]'
);
COMMIT;
-- ===========================================================================
-- C2: CHECK ime/prezime are trimmed
-- Pre-flight violators: 0
-- ===========================================================================
BEGIN;
ALTER TABLE pgz_sport.clanovi
ADD CONSTRAINT clanovi_trimmed_chk
CHECK (ime = trim(ime) AND prezime = trim(prezime));
COMMIT;
-- ===========================================================================
-- C4: spol values constraint
-- NOT applied as new constraint — existing clanovi_spol_check already enforces
-- spol IN ('M','Ž',NULL). Documented for completeness.
-- CHECK (spol IS NULL OR spol IN ('M','Ž'))
-- ===========================================================================
-- ===========================================================================
-- C5: UNIQUE partial index on hns_igrac_id (non-null, non-empty)
-- Pre-flight duplicate groups: 0
-- ===========================================================================
BEGIN;
CREATE UNIQUE INDEX IF NOT EXISTS clanovi_hns_uniq
ON pgz_sport.clanovi (hns_igrac_id)
WHERE hns_igrac_id IS NOT NULL AND hns_igrac_id != '';
COMMIT;
-- ===========================================================================
-- C7: BEFORE INSERT/UPDATE normalize trigger
-- Trims ime/prezime, rejects CamelCase, enforces length>=2 only when names
-- change (so the existing 22 short-name historical rows can still be UPDATEd
-- on other fields without rejection).
-- ===========================================================================
BEGIN;
CREATE OR REPLACE FUNCTION pgz_sport.clanovi_normalize_fn()
RETURNS trigger
LANGUAGE plpgsql
AS $fn$
DECLARE
v_changed_name boolean;
BEGIN
IF NEW.ime IS NOT NULL THEN
NEW.ime := trim(NEW.ime);
END IF;
IF NEW.prezime IS NOT NULL THEN
NEW.prezime := trim(NEW.prezime);
END IF;
IF TG_OP = 'INSERT' THEN
v_changed_name := true;
ELSE
v_changed_name := (NEW.ime IS DISTINCT FROM OLD.ime)
OR (NEW.prezime IS DISTINCT FROM OLD.prezime);
END IF;
IF v_changed_name THEN
IF NEW.ime ~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]' THEN
RAISE EXCEPTION 'CamelCase rejected in ime: %', NEW.ime
USING ERRCODE = 'check_violation';
END IF;
IF NEW.prezime ~ '[a-zćčšđžáàâäéèêëíìîïóòôöúùûüñçý][A-ZĆČŠĐŽÁÀÂÄÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÑÇÝ]' THEN
RAISE EXCEPTION 'CamelCase rejected in prezime: %', NEW.prezime
USING ERRCODE = 'check_violation';
END IF;
IF length(coalesce(NEW.ime, '')) < 2 THEN
RAISE EXCEPTION 'ime too short (<2 chars): %', NEW.ime
USING ERRCODE = 'check_violation';
END IF;
IF length(coalesce(NEW.prezime, '')) < 2 THEN
RAISE EXCEPTION 'prezime too short (<2 chars): %', NEW.prezime
USING ERRCODE = 'check_violation';
END IF;
END IF;
RETURN NEW;
END;
$fn$;
DROP TRIGGER IF EXISTS clanovi_normalize_trigger ON pgz_sport.clanovi;
CREATE TRIGGER clanovi_normalize_trigger
BEFORE INSERT OR UPDATE ON pgz_sport.clanovi
FOR EACH ROW EXECUTE FUNCTION pgz_sport.clanovi_normalize_fn();
COMMIT;
-- END