I noticed that implementing deferrable unique constraints is on the
TODO list.  I don't think its been said yet, but currently you can
implement a deferrable unique constraint by using a deferrable
constraint trigger together with a procedural language like plpgsql.
If you need an index on a column, you can use a regular index instead
of a unique index.

Yes, I noticed that getting rid of constraint triggers is also on the
TODO list.

Below is an example.

George Essig

------------------------------------------

create table t (x integer, y integer);
create index t_x_in on t (x);

-- Create a trigger function to test for duplicate values of x.
-- Table t column x unique insert update trigger function.

create or replace function t_x_un_ins_up_tr() RETURNS "trigger"
    AS '
declare
   invalid integer;
begin

    -- Not absolutely necessary, but avoids a query if the new and old
    -- values of x are the same.

    if TG_OP = ''UPDATE'' then
        if new.x = old.x then
            return new;
        end if;
    end if;

    -- If 2 or more rows have the same value of x, set invalid to 1.

    select 1 into invalid
    from t
    where x = new.x
    offset 1 limit 1;

    -- If found, raise exception.

    if FOUND then
        raise EXCEPTION
        ''Violation of unique constraint on column x in table t by new row:
        x %, y %'', new.x, new.y;
    end if;
    
    return new;
end;'
    LANGUAGE plpgsql;  

-- Create a deferrable constraint trigger that executes the trigger function.
-- This runs at transaction commit time for every row that was inserted or 
updated.

create constraint trigger t_x_un_ins_up_tr after insert or update on t 
deferrable initially deferred 
for each row 
execute procedure t_x_un_ins_up_tr ();

-- Begin a transaction.
-- Insert duplicate values of x successfully.
-- Violation of constraint when transaction is committed. 

test=# begin;
BEGIN
test=# insert into t (x, y) values (1,1);
INSERT 30332079 1
test=# insert into t (x, y) values (1,2);
INSERT 30332080 1
test=# commit;
ERROR:  Violation of unique constraint on column x in table t by new row:
        x 1, y 1
test=# select * from t;
 x | y
---+---
(0 rows)

-- Begin a transaction.
-- Insert duplicate values of x successfully.
-- Update one of the duplicate values to another value.
-- Commit transaction successfully.

test=# begin;
BEGIN
test=# insert into t (x, y) values (1,1);
INSERT 30332083 1
test=# insert into t (x, y) values (1,2);
INSERT 30332084 1
test=# update t set x = 2 where y = 2;
UPDATE 1
test=# commit;
COMMIT
test=# select * from t;
 x | y
---+---
 1 | 1
 2 | 2
(2 rows)

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to