Bug or feature in AFTER INSERT trigger?

From: Martin Edlman <martin(dot)edlman(at)gmail(dot)com>
To: pgsql-sql(at)postgresql(dot)org
Subject: Bug or feature in AFTER INSERT trigger?
Date: 2014-11-05 13:00:21
Message-ID: 545A1F65.6050705@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-sql

Hello,

today I encountered strange behaviour in PgSQL 9.0 (tried in 9.3 with
same effect).

There is a table and an AFTER INSERT trigger which call a function which
counts a number of records in the same table. But the newly inserted
record is not selected and counted.

When I delete a record and the very same AFTER trigger calls the very
same function, selected and counted records are already without the
deleted one.

I supposed that after insert the record is already in the database,
isn't it true?!

The documentation doesn't mention this. (or I didn't find it).

Can someone confirm it as a bug or explain why it works this way.

Regards,
Martin Edlman

EXAMPLE:

-- FUNCTION

CREATE OR REPLACE FUNCTION tmp.email_service(contrid integer)
RETURNS integer AS
$BODY$
DECLARE
sid integer := 119;
rec record;
vfrom date;
vto date;
cmnt text;
cnt integer := 0;
BEGIN
vfrom := date_trunc('month', now());
vto := date_trunc('month', now() + interval '1 month') - interval '1 day';
RAISE NOTICE 'sid %, from %, to %', sid, vfrom, vto;
FOR rec IN
SELECT ma.contract_id, count(ma.*) as unitage, string_agg(ma.email, ',
' order by ma.email) as emails
FROM tmp.mail_account as ma
WHERE contract_id = contrid
AND coalesce(ma.valid_from, '-infinity') < now()
AND coalesce(ma.valid_to, 'infinity') > now()
GROUP BY 1
LOOP
RAISE NOTICE 'number of mails: %, mails: %', rec.unitage, rec.emails;
cnt := cnt + 1;
-- here is some code which inserts or updates
-- services ...
END LOOP;
RETURN cnt;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION tmp.email_service(integer)
OWNER TO postgres;
GRANT EXECUTE ON FUNCTION tmp.email_service(integer) TO public;
GRANT EXECUTE ON FUNCTION tmp.email_service(integer) TO postgres;

-- TRIGGER FUNCTION
CREATE OR REPLACE FUNCTION tmp.email_service()
RETURNS trigger AS
$BODY$
BEGIN
IF TG_OP = 'INSERT' THEN
RAISE NOTICE '% % email %(at)% inserted, setting services for id %',
TG_WHEN, TG_OP, NEW.username, NEW.domain, NEW.contract_id;
-- call a function
PERFORM tmp.email_service(NEW.contract_id);
RETURN NEW;
END IF;

IF TG_OP = 'UPDATE' THEN
--
RETURN NEW;
END IF;

IF TG_OP = 'DELETE' THEN
PERFORM tmp.email_service(OLD.contract_id);
RETURN OLD;
END IF;

RETURN NULL;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION tmp.email_service()
OWNER TO edlman;
GRANT EXECUTE ON FUNCTION tmp.email_service() TO public;
GRANT EXECUTE ON FUNCTION tmp.email_service() TO edlman;

-- TABLE
CREATE TABLE tmp.mail_account
(
id serial NOT NULL,
contract_id integer NOT NULL,
username character varying(50) NOT NULL,
domain character varying(100) NOT NULL,
email character varying(255) NOT NULL,
valid_from timestamp without time zone DEFAULT now(),
valid_to timestamp without time zone,
CONSTRAINT mail_account_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE tmp.mail_account OWNER TO postgres;

CREATE UNIQUE INDEX mail_account_email
ON tmp.mail_account
USING btree
(email COLLATE pg_catalog."default");
CREATE UNIQUE INDEX mail_account_email_idx
ON tmp.mail_account
USING btree
(username COLLATE pg_catalog."default", domain COLLATE
pg_catalog."default");
CREATE INDEX mail_account_username_idx
ON tmp.mail_account
USING btree
(username COLLATE pg_catalog."default");
CREATE TRIGGER email_service
AFTER INSERT OR UPDATE OR DELETE
ON tmp.mail_account
FOR EACH ROW
EXECUTE PROCEDURE tmp.email_service();

Responses

Browse pgsql-sql by date

  From Date Subject
Next Message hubert depesz lubaczewski 2014-11-05 14:06:18 Re: Bug or feature in AFTER INSERT trigger?
Previous Message Campbell, Lance 2014-11-04 04:56:43 text search index help