first commit
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Add Constraints Safely in Migrations
|
||||
impact: HIGH
|
||||
impactDescription: Prevents migration failures and enables idempotent schema changes
|
||||
tags: constraints, migrations, schema, alter-table
|
||||
---
|
||||
|
||||
## Add Constraints Safely in Migrations
|
||||
|
||||
PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail.
|
||||
|
||||
**Incorrect (causes syntax error):**
|
||||
|
||||
```sql
|
||||
-- ERROR: syntax error at or near "not" (SQLSTATE 42601)
|
||||
alter table public.profiles
|
||||
add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id);
|
||||
```
|
||||
|
||||
**Correct (idempotent constraint creation):**
|
||||
|
||||
```sql
|
||||
-- Use DO block to check before adding
|
||||
do $$
|
||||
begin
|
||||
if not exists (
|
||||
select 1 from pg_constraint
|
||||
where conname = 'profiles_birthchart_id_unique'
|
||||
and conrelid = 'public.profiles'::regclass
|
||||
) then
|
||||
alter table public.profiles
|
||||
add constraint profiles_birthchart_id_unique unique (birthchart_id);
|
||||
end if;
|
||||
end $$;
|
||||
```
|
||||
|
||||
For all constraint types:
|
||||
|
||||
```sql
|
||||
-- Check constraints
|
||||
do $$
|
||||
begin
|
||||
if not exists (
|
||||
select 1 from pg_constraint
|
||||
where conname = 'check_age_positive'
|
||||
) then
|
||||
alter table users add constraint check_age_positive check (age > 0);
|
||||
end if;
|
||||
end $$;
|
||||
|
||||
-- Foreign keys
|
||||
do $$
|
||||
begin
|
||||
if not exists (
|
||||
select 1 from pg_constraint
|
||||
where conname = 'profiles_birthchart_id_fkey'
|
||||
) then
|
||||
alter table profiles
|
||||
add constraint profiles_birthchart_id_fkey
|
||||
foreign key (birthchart_id) references birthcharts(id);
|
||||
end if;
|
||||
end $$;
|
||||
```
|
||||
|
||||
Check if constraint exists:
|
||||
|
||||
```sql
|
||||
-- Query to check constraint existence
|
||||
select conname, contype, pg_get_constraintdef(oid)
|
||||
from pg_constraint
|
||||
where conrelid = 'public.profiles'::regclass;
|
||||
|
||||
-- contype values:
|
||||
-- 'p' = PRIMARY KEY
|
||||
-- 'f' = FOREIGN KEY
|
||||
-- 'u' = UNIQUE
|
||||
-- 'c' = CHECK
|
||||
```
|
||||
|
||||
Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)
|
||||
Reference in New Issue
Block a user