Thread: Weird Trigger Behaviour using IF ... THEN ... ESLEIF... THEN... ELSEIF... THEN ... ELSE ... END IF;
Weird Trigger Behaviour using IF ... THEN ... ESLEIF... THEN... ELSEIF... THEN ... ELSE ... END IF;
From
"Antony Sohal"
Date:
Hi
Please can you help me with the following trigger I have written in PostgreSQL 7.4.8 running under Fedora Linux, using pgAdmin III as client.
For events in a system, I wanted to break up a string which is a log statement (inserted into event table) into key-value pairs (where the string is '|' delimited) and insert them into a separate table (event_value). I have written a trigger to achieve this and it works fine.
However, I want to execute certain events if the key (that is inserted into the event_value table) matches certain criteria. To do this I wrote a another trigger, however I get very strange behaviour. Follow this example:
I have got the following tables:
CREATE TABLE event (
event_id int4 NOT NULL,
session_id varchar(255),
event_timestamp timestamp,
log_statement varchar(2000),
application varchar(30),
company varchar(30),
environment varchar(30),
CONSTRAINT event_id_pkey PRIMARY KEY (event_id)
);
event_id int4 NOT NULL,
session_id varchar(255),
event_timestamp timestamp,
log_statement varchar(2000),
application varchar(30),
company varchar(30),
environment varchar(30),
CONSTRAINT event_id_pkey PRIMARY KEY (event_id)
);
CREATE TABLE event_value (
event_value_id int4 NOT NULL,
event_id int4 NOT NULL,
event_key varchar(100),
event_value varchar(2000),
CONSTRAINT event_value_id_pkey PRIMARY KEY (event_value_id),
CONSTRAINT fk_event_event_value FOREIGN KEY (event_id) REFERENCES event (event_id) ON UPDATE NO ACTION ON DELETE NO ACTION
);
event_value_id int4 NOT NULL,
event_id int4 NOT NULL,
event_key varchar(100),
event_value varchar(2000),
CONSTRAINT event_value_id_pkey PRIMARY KEY (event_value_id),
CONSTRAINT fk_event_event_value FOREIGN KEY (event_id) REFERENCES event (event_id) ON UPDATE NO ACTION ON DELETE NO ACTION
);
CREATE TABLE strings_tbl (
value VARCHAR(256)
);
value VARCHAR(256)
);
I have added the PL/pgSQL language to the database, if you have not got this installed use the following statements:
CREATE OR REPLACE FUNCTION plpgsql_call_handler()
RETURNS language_handler AS
'$libdir/plpgsql', 'plpgsql_call_handler'
LANGUAGE 'c' VOLATILE;
RETURNS language_handler AS
'$libdir/plpgsql', 'plpgsql_call_handler'
LANGUAGE 'c' VOLATILE;
CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql'
HANDLER plpgsql_call_handler;
HANDLER plpgsql_call_handler;
Now I create a trigger on event table as :
CREATE OR REPLACE FUNCTION fn_event()
RETURNS "trigger" AS
'
DECLARE
-- Declare a variable to hold the event id.
eventid INTEGER;
logme VARCHAR;
eventvalue_id INTEGER;
delimiter VARCHAR DEFAULT \'|\';
-- Declare a variable to key and value.
eventkey VARCHAR;
eventvalue VARCHAR;
RETURNS "trigger" AS
'
DECLARE
-- Declare a variable to hold the event id.
eventid INTEGER;
logme VARCHAR;
eventvalue_id INTEGER;
delimiter VARCHAR DEFAULT \'|\';
-- Declare a variable to key and value.
eventkey VARCHAR;
eventvalue VARCHAR;
BEGIN
eventid := NEW.event_id;
logme := substring(NEW.log_statement FROM position(delimiter IN NEW.log_statement)+1 FOR length(NEW.log_statement));
eventid := NEW.event_id;
logme := substring(NEW.log_statement FROM position(delimiter IN NEW.log_statement)+1 FOR length(NEW.log_statement));
WHILE length(logme) > 0 AND position(delimiter IN logme) > 0 LOOP
BEGIN
eventkey := substring(logme FROM 0 FOR position(delimiter IN logme));
logme := substring(logme FROM (position(delimiter IN logme)+1) FOR length(logme));
IF position(delimiter IN logme) = 0 THEN
BEGIN
eventvalue := logme;
END;
ELSE
BEGIN
eventvalue := substring(logme FROM 0 FOR position(delimiter IN logme));
END;
END IF;
logme := substring(logme FROM position(delimiter IN logme) + 1 FOR length(logme));
SELECT INTO eventvalue_id nextval(\'event_sequence\');
EXECUTE \'INSERT INTO event_value (event_value_id, event_id, event_key, event_value) VALUES (\' ||
eventvalue_id || \',\' || eventid || \',\' || quote_literal(eventkey) || \',\' || quote_literal(eventvalue) || \')\';
END;
END LOOP;
RETURN NULL;
END;
'
LANGUAGE 'plpgsql' VOLATILE;
BEGIN
eventkey := substring(logme FROM 0 FOR position(delimiter IN logme));
logme := substring(logme FROM (position(delimiter IN logme)+1) FOR length(logme));
IF position(delimiter IN logme) = 0 THEN
BEGIN
eventvalue := logme;
END;
ELSE
BEGIN
eventvalue := substring(logme FROM 0 FOR position(delimiter IN logme));
END;
END IF;
logme := substring(logme FROM position(delimiter IN logme) + 1 FOR length(logme));
SELECT INTO eventvalue_id nextval(\'event_sequence\');
EXECUTE \'INSERT INTO event_value (event_value_id, event_id, event_key, event_value) VALUES (\' ||
eventvalue_id || \',\' || eventid || \',\' || quote_literal(eventkey) || \',\' || quote_literal(eventvalue) || \')\';
END;
END LOOP;
RETURN NULL;
END;
'
LANGUAGE 'plpgsql' VOLATILE;
CREATE TRIGGER tg_event AFTER INSERT ON event
FOR EACH ROW EXECUTE PROCEDURE fn_event();
Then I create a trigger on event_value:
CREATE OR REPLACE FUNCTION fn_event_value() RETURNS TRIGGER AS '
DECLARE
-- Declare a variable to key and value.
id INTEGER;
BEGIN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_key) || \')\';
IF \'APPLICATION\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
IF \'CLI\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
-- do nothing, nothing at all...
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(\'EMPTY\') || \')\';
DECLARE
-- Declare a variable to key and value.
id INTEGER;
BEGIN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_key) || \')\';
IF \'APPLICATION\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
IF \'CLI\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
-- do nothing, nothing at all...
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(\'EMPTY\') || \')\';
RETURN NULL;
END;
' LANGUAGE plpgsql;
END;
' LANGUAGE plpgsql;
Create sequence :
CREATE SEQUENCE event_sequence
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 360
CACHE 10;
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 360
CACHE 10;
Now if you execute the following insert statements:
INSERT INTO event (event_id,session_id, event_timestamp, log_statement)
VALUES (nextval('event_sequence'),'testsession1',current_timestamp,'|BROWSER|Voice Browser|23|CLI|12334232|HOSTNAME|server name|THREAD|56|CALL_START|2005-7-29 16:32:25.875|');
VALUES (nextval('event_sequence'),'testsession1',current_timestamp,'|BROWSER|Voice Browser|23|CLI|12334232|HOSTNAME|server name|THREAD|56|CALL_START|2005-7-29 16:32:25.875|');
I get the following results:
event table has the whole log statement
event_value table has log statement broken up in key value pairs
however, in strings_tbl table I have the following rows :
BROWSER
EMPTY
CLI
EMPTY
HOSTNAME
EMPTY
THREAD
EMPTY
CALL_START
EMPTY
What I expect is the following:
BROWSER
EMPTY
CLI
12334232
HOSTNAME
EMPTY
THREAD
EMPTY
CALL_START
EMPTY
Now if I change the trigger with this I get the excepted result:
CREATE OR REPLACE FUNCTION fn_event_value() RETURNS TRIGGER AS '
DECLARE
-- Declare a variable to key and value.
id INTEGER;
BEGIN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_key) || \')\';
IF \'APPLICATION\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
IF \'CLI\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
-- do nothing, nothing at all...
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(\'EMPTY\') || \')\';
DECLARE
-- Declare a variable to key and value.
id INTEGER;
BEGIN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_key) || \')\';
IF \'APPLICATION\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
IF \'CLI\' = NEW.event_key THEN
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(NEW.event_value) || \')\';
RETURN NULL;
END IF;
-- do nothing, nothing at all...
EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || quote_literal(\'EMPTY\') || \')\';
RETURN NULL;
END;
' LANGUAGE plpgsql;
END;
' LANGUAGE plpgsql;
However, please can some one explain why IF .... THEN .... ELSEIF ..... THEN .... ELSEIF .... THEN.... ELSE .... END IF; doesn't work.
And if I use the following insert statement I get syntax errors
INSERT INTO event (event_id,session_id, event_timestamp, log_statement)
VALUES (nextval('event_sequence'),'testsession1',current_timestamp,'|BROWSER|Voice Browser 23|CLI|12334232|HOSTNAME|servername|APPLICATION|some application|THREAD|56|CALL_START|2005-7-29 16:32:25.875|');
VALUES (nextval('event_sequence'),'testsession1',current_timestamp,'|BROWSER|Voice Browser 23|CLI|12334232|HOSTNAME|servername|APPLICATION|some application|THREAD|56|CALL_START|2005-7-29 16:32:25.875|');
Thanks
Antony Sohal
Winner - e-Government excellence 2004.
Runner up - European Information Management awards 2004:
- The Premier Project Award.
- B2C Commerce Project Award.
- CRM Project Award.
For more information visit us at www.voxgen.com
Note:
This message is for the named person's use only. It may contain confidential, proprietary or legally privileged information. No confidentiality or privilege is waived or lost by any mistransmission. If you receive this message in error, please immediately delete it and all copies of it from your system, destroy any hard copies of it and notify the sender. You must not, directly or indirectly, use, disclose, distribute, print, or copy any part of this message if you are not the intended recipient. Vox Generation Limited and any of its subsidiaries each reserve the right to monitor all e-mail communications through its networks.
Any views expressed in this message are those of the individual sender, except where the message states otherwise and the sender is authorised to state them to be the views of any such entity.
Thank You.
Vox Generation Limited,Manor House,21 Soho Square, London W1D 3QP, Registered in England: 3937784.
This e-mail message has been scanned for Viruses and Content and cleared by NetIQ MailMarshal
On Mon, 5 Sep 2005, Antony Sohal wrote: > Please can you help me with the following trigger I have written in > PostgreSQL 7.4.8 running under Fedora Linux, using pgAdmin III as > client. > Now I create a trigger on event table as : > > CREATE OR REPLACE FUNCTION fn_event() > RETURNS "trigger" AS > ' > DECLARE > -- Declare a variable to hold the event id. > eventid INTEGER; > logme VARCHAR; > eventvalue_id INTEGER; > delimiter VARCHAR DEFAULT \'|\'; > -- Declare a variable to key and value. > eventkey VARCHAR; > eventvalue VARCHAR; > > BEGIN > eventid := NEW.event_id; > logme := substring(NEW.log_statement FROM position(delimiter IN > NEW.log_statement)+1 FOR length(NEW.log_statement)); > > WHILE length(logme) > 0 AND position(delimiter IN logme) > 0 LOOP > BEGIN > eventkey := substring(logme FROM 0 FOR position(delimiter IN logme)); > logme := substring(logme FROM (position(delimiter IN logme)+1) FOR > length(logme)); > > IF position(delimiter IN logme) = 0 THEN > BEGIN > eventvalue := logme; > END; > ELSE > BEGIN > eventvalue := substring(logme FROM 0 FOR position(delimiter IN > logme)); > END; > END IF; > logme := substring(logme FROM position(delimiter IN logme) + 1 FOR > length(logme)); > SELECT INTO eventvalue_id nextval(\'event_sequence\'); > EXECUTE \'INSERT INTO event_value (event_value_id, event_id, > event_key, event_value) VALUES (\' || > eventvalue_id || \',\' || eventid || \',\' || > quote_literal(eventkey) || \',\' || quote_literal(eventvalue) || \')\'; > END; > END LOOP; > RETURN NULL; > END; > ' > LANGUAGE 'plpgsql' VOLATILE; > > > CREATE TRIGGER tg_event AFTER INSERT ON event > FOR EACH ROW EXECUTE PROCEDURE fn_event(); > > Then I create a trigger on event_value: > > CREATE OR REPLACE FUNCTION fn_event_value() RETURNS TRIGGER AS ' > DECLARE > -- Declare a variable to key and value. > id INTEGER; > BEGIN > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(NEW.event_key) || \')\'; > IF \'APPLICATION\' = NEW.event_key THEN > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(NEW.event_value) || \')\'; > RETURN NULL; > END IF; > IF \'CLI\' = NEW.event_key THEN > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(NEW.event_value) || \')\'; > RETURN NULL; > END IF; > > -- do nothing, nothing at all... > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(\'EMPTY\') || \')\'; > > RETURN NULL; > END; > ' LANGUAGE plpgsql; I don't see the ELSEIF in either of the above. > Now if I change the trigger with this I get the excepted result: > > CREATE OR REPLACE FUNCTION fn_event_value() RETURNS TRIGGER AS ' > DECLARE > -- Declare a variable to key and value. > id INTEGER; > BEGIN > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(NEW.event_key) || \')\'; > IF \'APPLICATION\' = NEW.event_key THEN > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(NEW.event_value) || \')\'; > RETURN NULL; > END IF; > IF \'CLI\' = NEW.event_key THEN > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(NEW.event_value) || \')\'; > RETURN NULL; > END IF; > > -- do nothing, nothing at all... > EXECUTE \'INSERT INTO strings_tbl VALUES ( \' || > quote_literal(\'EMPTY\') || \')\'; > > RETURN NULL; > END; > ' LANGUAGE plpgsql; > > > However, please can some one explain why IF .... THEN .... ELSEIF ..... > THEN .... ELSEIF .... THEN.... ELSE .... END IF; doesn't work. IIRC Until 8.0 the correct spelling is ELSIF. I believe 8.0 added ELSEIF as an alternate spelling.