0

I want to replace INSERT into a table with a PostgreSQL rule.

Here is my two tables:

Resource:
  uid (PK): UUID
  type (NOT_NULL): ENUM

SpecificResource:
  uid (PK, FK on resource.uid): UUID
  content (NOT_NULL): JSONB

I want any user to the database to be able to make insert/update/delete on SpecificResource directly without the need to insert/update/delete on Resource.

Here is my unsuccessful try that triggers an infinite recursion loop (indeed because I try to re-insert in specific_resource table with a RULE (...) DO INSTEAD :

CREATE OR REPLACE RULE insert_specific_resource
AS ON INSERT TO specific_resource
DO INSTEAD (
    INSERT INTO resource (uid, type)
    VALUES (NEW.uid, 'SPECIFIC_RESOURCE');
    
    INSERT INTO specific_resource (uid)
    VALUES (new.uid)
);
4
  • Do you insist on using a rule? Maybe an instead of trigger? Commented Nov 10, 2021 at 14:44
  • A trigger would be excellent also, but it's far beyond my SQL knowledge. Commented Nov 10, 2021 at 14:45
  • I will suggest one to you. It is easier to comprehend. Commented Nov 10, 2021 at 14:46
  • @Stefanov.sm the following trigger works well for resource table. However, it does not insert anything in specific_resource table on INSERT INTO specific_resource ... CREATE OR REPLACE FUNCTION add_specific_resource() RETURNS TRIGGER AS $BODY$ BEGIN INSERT INTO resource(uid, type) VALUES (uid, 'SPECIFIC_RESOURCE'); RETURN NEW; END $BODY$ LANGUAGE PLPGSQL; CREATE OR REPLACE TRIGGER add_dashboard BEFORE INSERT ON dashboard FOR EACH ROW EXECUTE PROCEDURE add_specific_resource(); Commented Nov 10, 2021 at 14:57

2 Answers 2

1
create or replace function specific_resource_tf()
returns trigger language plpgsql as
$$
begin
 insert into resource(uid, type) VALUES (new.uid, 'SPECIFIC_RESOURCE');
 return new;
end;
$$;

create trigger specific_resource_t 
before insert on specific_resource
for each row
execute procedure specific_resource_tf();

Explanation

After creating trigger specific_resource_t it will be executed before each insert in table specific_resource. The trigger invokes function specific_resource_tf which does what your rule was intended to - inserts a record into resource before proceeding with the insert in table specific_resource.

Illustration (with temporary tables and function)

-- drop table if exists specific_resource; drop table if exists resource;
create temp table resource (uid integer primary key, type text);
create temp table specific_resource (uid integer references resource(uid), content JSONB);  

create or replace function pg_temp.specific_resource_tf()
returns trigger language plpgsql as $$
begin
 insert into resource(uid, type) VALUES (new.uid, 'SPECIFIC_RESOURCE');
 return new;
end;
$$;

create trigger specific_resource_t 
before insert on specific_resource
for each row execute procedure pg_temp.specific_resource_tf();

insert into specific_resource values (22, '"test"');
-- does insert in both tables
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for your answer. It does not insert any row in specific_resource when I execute INSERT INTO specific_resource (uid, content) VALUES ('an_uuid', '"test'")
I do not believe that. Any error message?
Seems the syntax is wrong in pgadmin : ERROR: syntax error at or near ";" for the last character. If I add parenthesis it works, but I guess it's not calling the function, trying to define it instead... But still add a row in resource and not specific_resource. Weird
My omission. Missed () in the end of create trigger statement. Fixed in the answer.
Sure :) Still, it inserts correctly in resource but not specific_resource..
|
0
CREATE OR REPLACE FUNCTION add_specific_plus_resource()
RETURNS TRIGGER LANGUAGE PLPGSQL AS 
$$
BEGIN
    INSERT INTO resource(uid, type)
    VALUES (uid, 'SPECIFIC');
    RETURN NEW;
END;
$$;

CREATE OR REPLACE TRIGGER add_specific_resource
BEFORE INSERT ON specific_resource
FOR EACH ROW EXECUTE PROCEDURE add_specific_plus_resource();

The following INSERT works well to add a row into resource but not into specific_resource.

INSERT INTO specific_resource(uid, content)
VALUES ('123e4567-e89b-12d3-a456-426614174000', '"test"');

2 Comments

Pls. note that OR REPLACE is illegal for create trigger
@Stefanov.sm You nailed it, it works like a charm, thanks a lot !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.