My table and trigger in PostgreSQL 9.4.3 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit:
CREATE TABLE measurements (
measurement_id SERIAL PRIMARY KEY NOT NULL,
measurement_size_in_bytes INTEGER NOT NULL
);
CREATE TABLE file_headers (
header_id SERIAL PRIMARY KEY NOT NULL,
measurement_id INTEGER NOT NULL,
file_header_index_start INTEGER,
file_header_index_end INTEGER
);
CREATE TRIGGER measurement_ids AFTER INSERT
ON measurements FOR EACH ROW
EXECUTE PROCEDURE ins_function('SELECT measurement_id FROM measurements
ORDER BY measurement_id desc limit 1;', 1, 666 );
where I assumed that the datatype of the SELECT is INTEGER since SERIAL but it is apparently false because I get the error message from this command which starts the trigger:
INSERT INTO measurements (measurement_size_in_bytes) VALUES (888);`
ERROR: invalid input syntax for integer: "SELECT measurement_id FROM measurements ORDER BY measurement_id desc limit 1;" CONTEXT: PL/pgSQL function ins_function() line 10 at assignment
Edit
ins_function()
and edits based on @a_horse_with_no_name and @Joishi's comments:
CREATE OR REPLACE FUNCTION ins_function() RETURNS TRIGGER AS $$
--
-- Perform AFTER INSERT operation on file_header by creating rows with new.measurement_id, new.file_header_index_start and new.file_header_index_end.
--
DECLARE
measurement_id INTEGER;
file_header_index_start INTEGER;
file_header_index_end INTEGER;
BEGIN
SELECT a.measurement_id INTO measurement_id from measurements a ORDER BY measurement_id desc limit 1;
file_header_index_start := TG_ARGV[0];
file_header_index_end := TG_ARGV[1];
IF TG_OP = 'INSERT' THEN
INSERT INTO file_headers (measurement_id, file_header_index_start, file_header_index_end)
VALUES (measurement_id, file_header_index_start, file_header_index_end);
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$$ LANGUAGE plpgsql;
--
-- Function and trigger on INSERT.
--
CREATE TRIGGER measurement_ids AFTER INSERT
ON measurements FOR EACH ROW EXECUTE PROCEDURE ins_function(1, 666);
I get now no error but the output is wrong: no INSERT
seen in the table file_headers
while successfully in the table measurements.
Output of @ErwinBrandstetter's answer
So I started to think about casting from TEXT to INT but this should be so basic operation, since TG_ARGV[]
is a datatype of text. One unsuccessful try is format('SELECT $1.%I', TG_ARGV[0])
.
The regclass
could work as you describe here in insaft_function()
SELECT NEW.measurement_id, TG_ARGV[0]::regclass, TG_ARGV[1]::regclass;
Why are there no successful INSERTs into the table file_headers
?
Best Answer
You have an unresolved naming conflict.
You must be using an old version of Postgres without declaring it. Or you are operating with non-default configuration setting.
Here you declare a variable named
measurement_id
:It's a folly to use ambiguous variable names to begin with. If you do it anyway, you must know what you are doing. I make it a habbit to prepend variable names with an underscore unlike column names, like
_measurement_id
.The later
SELECT
statement is ambiguous:This would raise an error message in modern PostgreSQL with default configuration. Per the documentation:
And:
In Postgres older than 9.0 this would be resolved to mean the variable. Per the documentation
Bold emphasis mine.
This would result in arbitrary results, since the sort order is now undetermined.
Audited Function
Note how I named it
insaft_function()
, since this is only to be used in anAFTER INSERT
trigger.Trigger:
But for the provided setup, you can radically simplify the function: