I have a trigger AFTER INSERT ON mytable that calls a function
CREATE OR REPLACE FUNCTION myfunction() RETURNS trigger AS
$BODY$
DECLARE
index TEXT;
BEGIN
index := 'myIndex_' || NEW.id2::text;
IF to_regclass(index::cstring) IS NULL THEN
EXECUTE 'CREATE INDEX ' || index || ' ON mytable(id) WITH (FILLFACTOR=100) WHERE id2=' || NEW.id2|| ';';
RAISE NOTICE 'Created new index %',index;
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
SECURITY DEFINER
COST 100;
ALTER FUNCTION myfunction()
OWNER TO theadmin;
This works wonderfully. For each distinct id2 I create an index. Speeds up relevant queries by a lot.
As mentioned above I trigger this AFTER INSERT ON. Before doing that however I had the trigger set to BEFORE INSERT ON. And the function did some strange things. (Yes, I had changed the RETURN NULL to RETURN NEW)
- insert of a new row
insert into mytable VALUES(1391, 868, 0.5, 0.5); - creates the corresponding index
myIndex_868 - the inserted row does not appear in mytable when doing a select :(
- trying to insert the same row results in
ERROR: duplicate key value violates unique constraint "mytable_pkey"because of courseDETAIL: Key (id, id2)=(1391, 868) already exists. - inserting other rows for the same id2 works as expected :)
DELETE FROM mytable WHERE id = 1391 and id2 = 868does nothingDROP INDEX myIndex_868;drops the index. And suddenly the initial row that never appeared in the table is suddenly there!
Why does BEFORE INSERT ON behave so differently? Is this a bug in postgres 9.4 or did I overlook something?
Just for completeness' sake:
CREATE TRIGGER mytrigger
AFTER INSERT ON mytable
FOR EACH ROW EXECUTE PROCEDURE myfunction();
vs.
CREATE TRIGGER mytrigger
BEFORE INSERT ON mytable
FOR EACH ROW EXECUTE PROCEDURE myfunction();