Firebird Error in Creating Trigger - triggers

Preparing query: CREATE TRIGGER autoincrementor_id FOR ID
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.OID IS NULL) THEN
NEW.OID = GEN_ID(MY_GEN_ID,1)
Error: *** IBPP::SQLException ***
Context: Statement::Prepare( CREATE TRIGGER autoincrementor_id FOR ID
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.OID IS NULL) THEN
NEW.OID = GEN_ID(MY_GEN_ID,1) )
Message: isc_dsql_prepare failed
SQL Message : -104
Invalid token
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Unexpected end of command - line 6, column 33
I get this error while creating the trigger below:
CREATE TRIGGER autoincrementor_id FOR ID
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.OID IS NULL) THEN
NEW.OID = GEN_ID(MY_GEN_ID,1);
END
Where am I missing? I already have my table ID created with a primary id oid, that must be auto incremented. I also created my generator function MY_GEN_ID.

You have to set the statement terminator and use it to terminate the CREATE TRIGGER statement, ie
SET TERM ^;
CREATE TRIGGER autoincrementor_id FOR ID
... rest of the trigger's body
END^
SET TERM ;^

Related

Firebird run execute statement inside trigger

I wrote a procedure STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE') that generates part of code that i want to execute (some long if statement)
IF ((new.LOKACIJA IS DISTINCT FROM old.LOKACIJA )
OR (new.MODIFIED IS DISTINCT FROM old.MODIFIED )
OR (new.KARAKTERISTIKE IS DISTINCT FROM old.KARAKTERISTIKE )
OR (new.LETNIK IS DISTINCT FROM old.LETNIK )
OR (new.ID_PNS_CERT_POS IS DISTINCT FROM old.ID_PNS_CERT_POS )
OR (new.ID_PNS_CERT_POS IS DISTINCT FROM old.ID_PNS_CERT_POS ))
and I want to call it in trigger, then add some code and run it all together.
The code is:
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
execute procedure STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE')
returning_values :besedilo_primerjave;
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 ; ^
Now when I run the update and trigger triggers I get this error:
SQL Message : -104 Invalid token
Engine Code : 335544569 Engine Message : Dynamic SQL Error SQL
error code = -104 Token unknown - line 1, column 1 IF
On the other hand if I write it like this:
SET TERM ^ ;
ALTER TRIGGER BI_MERILA_STRANKE ACTIVE
BEFORE INSERT OR UPDATE POSITION 0
AS
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
IF ((new.LOKACIJA IS DISTINCT FROM old.LOKACIJA )
OR (new.MODIFIED IS DISTINCT FROM old.MODIFIED )
OR (new.KARAKTERISTIKE IS DISTINCT FROM old.KARAKTERISTIKE )
OR (new.LETNIK IS DISTINCT FROM old.LETNIK )
OR (new.ID_PNS_CERT_POS IS DISTINCT FROM old.ID_PNS_CERT_POS )
OR (new.ID_PNS_CERT_POS IS DISTINCT FROM old.ID_PNS_CERT_POS ))
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 ; ^
It works as it should. I do not understand why it doesn't run if is more or less the same code.
As I also mentioned in your previous question, execute statement cannot be used to execute snippets of PSQL (procedural SQL) like that, it can only execute normal DSQL (dynamic SQL). And as it doesn't understand PSQL, you get the "token unknown - if" error, because if is not valid in DSQL.
execute statement is equivalent to executing SQL yourself from a query tool or application (it uses the same API), you can't use if there either.
There is a loophole by using an execute block statement, but that still would not allow you to gain access to the NEW (or OLD) trigger context variables unless explicitly passed as parameters, which would negate most of the usefulness of dynamically generated code in this context.
The only real solution is to write the trigger and not do it dynamically, maybe using a code generator (I'm not sure if any exist, otherwise you need to write that yourself).

DB2 trigger on update

I have the table ORDERS with a lot of columns: (ORDERS_ID, MEMBER_ID, STATUS, ANY MORE....)
when in STATUS I will have the change in the new status 'M' I would save ORDERS_ID, MEMBER_ID, STATUS in another table XORDERSAUDIT.
I wrote this :
CREATE or replace TRIGGER Order_Status_Update_Trigger
AFTER UPDATE OF STATUS ON ORDERS
REFERENCING NEW AS N
FOR EACH ROW
WHEN (N.STATUS = 'M')
BEGIN ATOMIC
INSERT INTO XORDERSAUDIT
(ORDER_ID, USERS_ID, STATUS) VALUES (N.ORDERS_ID, N.MEMBER_ID, N.STATUS);
END;
and I have this error:
DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601,
SQLERRMC=END-OF-STATEMENT;MEMBER_ID, N.STATUS);,
DRIVER=4.19.66 SQLState: 42601 ErrorCode: -104 Error occurred in:
I don't understand the error, I try to correct but encountered the same error, please help me.

INSERT fails because primary key already exists

I'm using PostgreSQL 9.4 and pgAdminIII 1.20 client. When launching an INSERT on a particular table, I get an error message saying: Details: the key (gid)=(31509) already exists. (SQL State: 23505).
I do not enter a gid value in the command in order to let the sequence do the job:
INSERT INTO geo_section (idnum, insee, ident) VALUES (25, '015233', '') ;
The sequence is defined as this:
CREATE SEQUENCE geo_section_gid_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 31509
CACHE 1;
ALTER TABLE geo_section_gid_seq
OWNER TO postgres;
The following query returns 34502:
SELECT max(gid) FROM geo_section ;
Therefore, I've tried to alter the sequence in order to start sequence from 34503:
ALTER SEQUENCE geo_section_gid_seq START 34503 ;
I get a success message saying that the query has been executed properly. But the sequence START parameter remains with 31509 value...
To change the next value for sequence use setval function :
select setval('geo_section_gid_seq'::regclass,34503,false)
false : if you want the next value will be 34503
true : if you want the next value will be 34504
You should execute this command:
SELECT setval('geo_section_gid_seq', (SELECT MAX(gid) FROM 'geo_section'), true)

In FirebirdSql, how to return exception message from procedure

I want to return the error message from a procedure when an exception happens. In SQL Server you would select the Error_Number() and Error_Message(). How would I do it in FirebirdSql
SET TERM ^ ;
CREATE PROCEDURE sprocname
( id int )
RETURNS
( gcode int, errmsg varchar(250) )
AS
BEGIN
gcode = 0;
errmsg = '';
-- do procedure code here
WHEN ANY DO
BEGIN
gcode = gdscode; -- ??
errmsg = ??;
END
SUSPEND;
END^
SET TERM ; ^
Unfortunately, you will need to do that at the client side, as it is currently not possible to obtain this in PSQL. There is a feature request in the Firebird tracker, which has been implemented for Firebird 4, which is expected to be released in 2019.
See Firebird 4 release notes, section System Function RDB$ERROR():
The function RDB$ERROR() takes a PSQL error context as input and
returns the specific context of the active exception. Its scope is
confined to the context of the exception-handling block in PSQL.
Outside the exception handling block, RDB$ERROR always contains
NULL.
The type of the return value depends on the context.
Syntax Rules
RDB$ERROR ( context )
context ::= { GDSCODE | SQLCODE | SQLSTATE | EXCEPTION | MESSAGE }
[..]
Example
BEGIN
...
WHEN ANY DO
EXECUTE PROCEDURE P_LOG_EXCEPTION(RDB$ERROR(MESSAGE));
END
CREATE PROCEDURE ADD_COUNTRY (
ACountryName COUNTRYNAME,
ACurrency VARCHAR(10) )
AS
BEGIN
INSERT INTO country (country,
currency)
VALUES (:ACountryName,
:ACurrency);
WHEN ANY DO
BEGIN
-- write an error in log
IN AUTONOMOUS TRANSACTION DO
INSERT INTO ERROR_LOG (PSQL_MODULE,
GDS_CODE,
SQL_CODE,
SQL_STATE)
VALUES ('ADD_COUNTRY',
GDSCODE,
SQLCODE,
SQLSTATE);
-- Re-throw exception
EXCEPTION;
END
END
http://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql-handleexceptions.html

Firebird autoincrement column

I need help creating an auto-increment column in Firebird.
Here is my table below
I want column Seqid to be auto incrementing
create Table TS_PRODUCT_PRICEHISTORY
(
Seqid int not null,
Remarks varchar(100)
)
I created a generator
CREATE GENERATOR tsproductpricehistory_gen_id;
Then create a trigger
CREATE TRIGGER aitspph_id FOR TS_PRODUCT_PRICEHISTORY
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.SEQID IS NULL) THEN
NEW.SEQID = GEN_ID(tsproductpricehistory_gen_id,1);
END
When I try to create a trigger via above code I get this error
Error: *** IBPP::SQLException *** Context: Statement::Prepare( CREATE
TRIGGER aitspph_id FOR TS_PRODUCT_PRICEHISTORY ACTIVE BEFORE INSERT
POSITION 0 AS BEGIN IF (NEW.SEQID IS NULL) THEN NEW.SEQID =
GEN_ID(tsproductpricehistory_gen_id,1) ) Message: isc_dsql_prepare
failed
SQL Message : -104 Invalid token
Engine Code : 335544569 Engine Message : Dynamic SQL Error SQL
error code = -104 Unexpected end of command - line 6, column 50
I can't seem to find whats wrong with the code creating the trigger.
Try this one:
CREATE TABLE TS_PRODUCT_PRICEHISTORY (
SEQID INTEGER NOT NULL,
REMARKS VARCHAR(100)
);
/* Autoincrement for field (SEQID) */
CREATE GENERATOR GEN_TS_PRODUCT_PRICEHISTORY_ID;
SET TERM ^ ;
CREATE TRIGGER TS_PRODUCT_PRICEHISTORY_BI FOR TS_PRODUCT_PRICEHISTORY
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.SEQID IS NULL) THEN
NEW.SEQID = GEN_ID(GEN_TS_PRODUCT_PRICEHISTORY_ID,1);
END^
SET TERM ; ^