diff --git a/CHANGELOG.md b/CHANGELOG.md index 1086d15b9..925415e05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## Unreleased +### Added + +- SQL status code in error message +- All transactional errors cause setting of `ProblemHint.RETRY_RECOMMENDED` + +### Fixed + +- Check constraint on table `subjects` obeys empty `identifiers`: + If there are no identifiers then type and label must be unique + among those entries without identifiers. Therefore entries are allowed + that have the same type and label but one is with and one w/o + identifiers. + ## [9.4.1](https://github.com/dbmdz/metadata-service/releases/tag/9.4.1) - 2025-01-09 ### Fixed diff --git a/metasvc-server/backend-jdbi/src/main/resources/io/github/dbmdz/metadata/server/backend/impl/database/migration/R__func_subjects_is_unique_type_identifier.sql b/metasvc-server/backend-jdbi/src/main/resources/io/github/dbmdz/metadata/server/backend/impl/database/migration/R__func_subjects_is_unique_type_identifier.sql new file mode 100644 index 000000000..3e53240f8 --- /dev/null +++ b/metasvc-server/backend-jdbi/src/main/resources/io/github/dbmdz/metadata/server/backend/impl/database/migration/R__func_subjects_is_unique_type_identifier.sql @@ -0,0 +1,36 @@ +CREATE OR REPLACE FUNCTION public.subjects_is_unique_type_identifier(puuid uuid, ptype character varying, ids dbidentifier[], plabel jsonb) +RETURNS boolean +STABLE LANGUAGE plpgsql +AS $function$ +/** + * Ensures uniqueness of `type` and single identifier across table `subjects`. + * + * If there are not any identifiers then `type` and `label` must be unique. + * It is intended for check constraints and + * returns `false` on violation. + */ +declare + db_ident record; --dbidentifier actually but makes trouble in backups + tuple_exists boolean; +begin + if ids is null or cardinality(ids) = 0 then + execute 'select exists(select 1 from public.subjects where $1 = type and $2 = label and coalesce(identifiers, array[]::dbidentifier[]) = array[]::dbidentifier[] and $3 <> uuid)' + into tuple_exists + using ptype, plabel, puuid; + if tuple_exists then + return false; + end if; + else + foreach db_ident in array ids loop + execute 'select exists(select 1 from public.subjects where $1 = type and $2 = any (identifiers) and $3 <> uuid)' + into tuple_exists + using ptype, db_ident, puuid; + if tuple_exists then + return false; + end if; + end loop; + end if; + return true; +end; +$function$; +