I have created some schemas (dsfv, dsfn, etc.) and insert some tables inside each schema, including the following tables :
- poste_hta_bt (parent table with attribute "code_pt" as unique key);
- transfo_hta_bt (having also "code_pt" attribute as foreign key that referenced poste_hta_bt).
I have also created a function trigger that count the total number of entities from "transfo_hta_bt" and report it in "nb_transf" attribute of "poste_hta_bt".
My code is as follows :
SET SESSION AUTHORIZATION dsfv;
SET search_path TO dsfv, public;
CREATE TABLE IF NOT EXISTS poste_hta_bt
(
id_pt serial NOT NULL,
code_pt varchar(30) NULL UNIQUE,
etc.
);
CREATE TABLE IF NOT EXISTS transfo_hta_bt
(
id_tra serial NOT NULL,
code_tra varchar(30) NULL,
code_pt varchar(30) NULL,
etc.
);
ALTER TABLE transfo_hta_bt ADD CONSTRAINT "FK_transfo_hta_bt_poste_hta_bt"
FOREIGN KEY (code_pt) REFERENCES poste_hta_bt (code_pt) ON DELETE No Action ON UPDATE No Action;
CREATE OR REPLACE FUNCTION recap_transf() RETURNS TRIGGER
language plpgsql AS
$$
DECLARE
som_transf smallint;
som_transf1 smallint;
BEGIN
IF (TG_OP = 'INSERT') THEN
SELECT COUNT(*) INTO som_transf FROM dsfv.transfo_hta_bt WHERE code_pt = NEW.code_pt;
UPDATE dsfv.poste_hta_bt SET nb_transf = som_transf WHERE dsfv.poste_hta_bt.code_pt = NEW.code_pt;
RETURN NULL;
ELSIF (TG_OP = 'DELETE') THEN
SELECT COUNT(*) INTO som_transf FROM dsfv.transfo_hta_bt WHERE code_pt = OLD.code_pt;
UPDATE dsfv.poste_hta_bt SET nb_transf = som_transf WHERE dsfv.poste_hta_bt.code_pt = OLD.code_pt;
RETURN NULL;
ELSIF (TG_OP = 'UPDATE') THEN
SELECT COUNT(*) INTO som_transf FROM dsfv.transfo_hta_bt WHERE code_pt = NEW.code_pt;
SELECT COUNT(*) INTO som_transf1 FROM dsfv.transfo_hta_bt WHERE code_pt = OLD.code_pt;
UPDATE dsfv.poste_hta_bt SET nb_transf = som_transf WHERE dsfv.poste_hta_bt.code_pt = NEW.code_pt;
UPDATE dsfv.poste_hta_bt SET nb_transf = som_transf1 WHERE dsfv.poste_hta_bt.code_pt = OLD.code_pt;
RETURN NULL;
ELSE
RAISE WARNING 'Other action occurred: %, at %', TG_OP, now();
RETURN NULL;
END IF;
END;
$$
;
DROP TRIGGER IF EXISTS recap_tr ON dsfv.transfo_hta_bt;
CREATE TRIGGER recap_tr AFTER INSERT OR UPDATE OR DELETE ON dsfv.transfo_hta_bt FOR EACH ROW EXECUTE PROCEDURE recap_transf();
This code runs correctly but I didn’t understand why the following:
In the function trigger, I noticed that I have to specify the schema of each table, despite that I adjusted search_path to dsfv from the beginning.
Also when I replace dsfv.transfo_hta_bt with TG_TABLE_NAME in the function trigger, the lattest variable is unrecognized.
Thank you in advance for your help.
2
Answers
You need to repeat
SET search_path TO dsfv, public;
at the beginning of the function body for it to apply to its inner context.TG_TABLE_NAME
is atext
variable not unlikeTG_OP
that you are already using, so you can’t directly plug it in a query as a table name. You’d have to construct your queries as text and use dynamic SQL EXECUTE to run them.PostgreSQL stores a function as string, which is interpreted when the function is executed. The
search_path
that applies is the one in effect when the function is called, not the one in effect when it is created. (SQL functions created with the new syntax from v14 are safe from that, since they are parsed when the function is created.)To avoid these problems, you should fix the
search_path
for all functions:Note that it is not safe to add a schema where untrusted users can create objects, so only add
public
if you revoked theCREATE
privilege forPUBLIC
that it has in versions before v15.