Reputation: 67
I want to execute a before update trigger, which checks if all the fields in a row are the same and cancel the update. I'm using Firebird 2.5.
My current approach is this:
Use procedure to get all names of fields with old.FIELD
, new.FIELD
. Something like this:
IF (new.LOCATION IS DISTINCT FROM
old.LOCATION) OR (new.NAME IS DISTINCT FROM old.NAME)
... the return type of procedure is Varchar(1000)
. This works. The procedure is this: STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE');
SYNC_INFO
table and proceed with the update of the row. If the condition is false, I want to cancel the update row. I do that by throwing an exception.My code:
SET TERM ^ ;
ALTER TRIGGER BI_MERILA_STRANKE ACTIVE
BEFORE INSERT OR UPDATE POSITION 0
AS
declare variable besedilo_primerjave varchar(5000);
BEGIN
begin
if (new.ID_MERILA_STRANKE is null OR new.ID_MERILA_STRANKE = 0) then new.ID_MERILA_STRANKE = gen_id(GEN_ID_MERILA_STRANKE,1);
end
begin
besedilo_primerjave = execute procedure
STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE'); -- if this is true then you need to save othervise not
execute statement besedilo_primerjave || ' THEN BEGIN INSERT INTO SYNC_INFO(TABLE_NAME,ID_COLUMN_NAME,ID_VALUE,DATETIME)
VALUES (
''MERILA_STRANKE'',
''ID_MERILA_STRANKE'',
NEW.ID_MERILA_STRANKE,
CURRENT_TIMESTAMP
);
END ELSE BEGIN
exception ENAK_RECORD;
END';
end
END^
SET TERM ; ^
When I try to execute this, I get the following error:
Token unknown - line 18, column 10
execute
This is this line of code:
execute statement besedilo_primerjave || ' THEN BEGIN INSERT INTO SYNC_INFO(TABLE_NAME,ID_COLUMN_NAME,ID_VALUE,DATETIME)
I am not working a lot with Firebird, so if anyone has any idea what I'm doing wrong, or if anyone knows a better solution to achieve this, please help me.
I need to do it on database, probably better approach would be to do it in software, but I can not do that.
Upvotes: 1
Views: 4094
Reputation: 109015
You are wrong about the problematic line. The actual problem is on
besedilo_primerjave = execute procedure STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE');
You can't have execute procedure
after assignment, you need to use
execute procedure STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE')
returning_values :besedilo_primerjave;
Your next statement cannot work as execute statement
cannot be used to execute snippets of PSQL (procedural SQL) like that, it can only execute normal DSQL (dynamic SQL), and you cannot access the context variables (like new
) in that way. You would need to pass the required columns from new
explicitly as parameter values to execute statement
, and you could try if you can get it to work by wrapping the PSQL you try to execute dynamically in an execute block
, but that would turn ugly pretty fast.
I suggest you rethink what you're doing, and maybe write the real logic in a trigger, instead of trying to do it fully dynamic like you're trying to do now.
Upvotes: 2
Reputation: 1
Here's my example based on Mark's example above and working in Firebird 3.0:
SET TERM ^ ;
CREATE TRIGGER UMCDB_DRIVER_BI FOR UMCDB_DRIVER ACTIVE
BEFORE INSERT POSITION 0
AS
BEGIN
new.ID = gen_id(GEN_DRIVER, 1);
new.CREATE_USERID = CURRENT_USER;
new.CREATE_TS = CURRENT_TIMESTAMP;
-- Get the hashed value for the driver name.
execute procedure PRC_NAME_HASH( new.DRVR_FIRST_NAME, new.DRVR_MID_INITS, new.DRVR_LAST_NAME)
returning_values new.NAME_HASH;
END^
SET TERM ; ^
Works beautifully! Thanks, Mark!
Upvotes: 0