I have a plpgsql function that returns a table. One of its columns is dynamically generated based on the parameters passed to the function. Is there a possibility to have the user have the ability to update the non-dynamically generated columns of that returned table, like with an instead of update trigger with a view?
Here's a simplified version:
In reality, the function is a lot more complex, and the value of the calculated column for the currently processing row is dependent on the previous rows, which is why I have to use a plpgsql function.
create table test(id integer, startdate date);
CREATE FUNCTION test2 (IN compare_date date)
RETURNS TABLE(id integer, startdate date, is_before boolean)
LANGUAGE plpgsql
DECLARE
rec record;
BEGIN
FOR rec IN SELECT id, startdate FROM test LOOP
IF rec.startdate < compare_date THEN
test2.is_before := true;
ELSE
test2.is_before := false;
END
test2.id := rec.id;
test2.startdate := rec.startdate;
return next;
END LOOP;
END;
The user just accesses the function, I want him to be able to update the columns in the original table. With a view, this could be done using a trigger, but I can't have dynamically generated columns in a view, can I?
Best Answer
Your function doesn't return a "table" in the usual sense. As noted in the docs,
RETURNS TABLE (...)
is just a syntactic shortcut forRETURNS SETOF record
, plus a bunch ofOUT
params.The output of the function is just a collection of values in memory, with no connection to the source of the data, so while callers can transform those values as they please, there is no way to propagate anything back to the original table via the function output.
If you want a different presentation of the underlying data which the user is still able to apply updates to, the only way is with an updatable view. Including generated columns should be no problem, as long as your trigger is written to handle these appropriately. The main obstacle in your case is that, unlike a function, you cannot (directly) pass parameters to a view.
The only workaround that I know of is to define your view in terms of a custom configuration variable, and require that users set this variable before querying the view, e.g.:
Your
UPDATE
trigger may also query this variable if needed.