Can I create a user defined function in Postgres either through the C-Language Function API or by using pl/pgsql which accepts a callback function as parameter?
As far as I see there is no way to do this through the C-Language API since it only accepts sql datatypes and there is no datatype for function. But maybe I'm missing something?
Since each function / procedure must have an entry in pg_proc, you can use the primary key for identifying the procedure. This would also eliminate the problems with procedures having the same name but different number of parameters or different parameter types.
Shorthands for this are the types regproc and regprocedure with the associated casts for easier handling. Lookup the manual for these.
Identifying the function and passing it around is no problem:
select 'pg_database_size(oid)'::regprocedure; -- create "reference"
regprocedure
-----------------------
pg_database_size(oid)
Use regprocedure as the parameter type.
The problem I did not yet figure out is how to actually call such a thing in a convenient way.
I think you can't, but since there are no anonymous functions, passing function name should do.
Old question and already has an accepted answer. But it doesn't clearly explain how to do this. So I thought of adding a more clear answer.
Let's assume you pass the callback function's name to your main function as a varchar value.
CREATE OR REPLACE FUNCTION public.get_function_fields(fn_name character varying)
...
...
Now if you want to call this fn_name function inside a query, you need to use EXECUTE command, and properly cast your function name using regproc as below.
EXECUTE 'create temp table if not exists temp_call as select * from ' || fn_name::regproc || '() limit 1';
Important part is this: ...|| fn_name::regproc || '()... As you can see, you have to append the parenthesis and cast the function name with ::regproc.
Hope it will help someone!
--create an being parametered function.
CREATE OR REPLACE FUNCTION public.select1() RETURNS integer
LANGUAGE sql
IMMUTABLE
AS $function$ select 10;
$function$
--create an function with function as input parameter.
CREATE OR REPLACE FUNCTION public.func_func(fn_name text)
RETURNS SETOF parent_tree
LANGUAGE plpgsql
AS $function$
begin
RETURN QUERY EXECUTE
format('select * from parent_tree where parent_id = %s::regprocedure', fn_name);
end
$function$
--Call it.
select * from func_func('select1()');
Related
I have written the below function and it works in Postgres 12.5:
CREATE OR REPLACE FUNCTION export_to_s3()
RETURNS TRIGGER
AS $export_to_s3$
BEGIN
PERFORM aws_s3.query_export_to_s3(
'select * from test.allowed_object_status',
aws_commons.create_s3_uri(
'test-db-dumps',
'allowed_object_status.csv',
'eu-west-2'),
options :='format csv, delimiter $$,$$'
);
RETURN NEW;
END;
$export_to_s3$ LANGUAGE plpgsql;
Now i would like to make test.allowed_object_status and allowed_object_status.csv parameters that i pass into export_to_s3().
I have tried a few things but failed so any help would be great.
A second part to my question and less important is it possible for a function to return nothing/void. I made this function a trigger but thats only because I cant figure out how to declare a function that dose not return anything after executing
Solution
This the solution i come up with thanks to the comments from #404 below.
CREATE OR REPLACE FUNCTION export_to_s3(query_cmd text, bucket_prefix text)
RETURNS VOID
AS $export_to_s3$
BEGIN
PERFORM
aws_s3.query_export_to_s3(
query_cmd,
aws_commons.create_s3_uri(
'test-db-dumps',
bucket_prefix,
'eu-west-2'),
options :='format csv, delimiter $$,$$'
);
END;
$export_to_s3$ LANGUAGE plpgsql;
I am sure there is a better way of doing it but very new to plpgsql
You can pass arguments to a trigger function, but that works different than you'd imagine.
You declare the trigger function without parameters.
In the CREATE TRIGGER statement, you specify string literals as function arguments.
These parameters can be accessed in the PL/pgSQL function body through TG_ARGV[], and the argument count is in TG_NARGS.
See the documentation for details.
I'm having a hard time understanding the below plsql function. what exactly does the function return and what exactly does the function do?
function getsysparm(a_name varchar2,
a_default varchar2 := null,
a_date sys_params.date_expires%type := null)
return varchar2;
That's not a function, it's just a function declaration, and from the looks of it, probably in a package spec. You need to look in the package body to see the actual code for the function.
Function accepts 3 parameters: one is mandatory (a_name), while another two are optional.
It returns a string (value whose datatype is VARCHAR2), for example "Abby" or "Stack Overflow" or "x".
What does it exactly do? Who knows ... you didn't post any code. See whether
select text
from user_source
where name = 'GETSYSPARM'
returns something you could have a look at.
I created a pl/pgsql function with a varchar parameter. Within this function I tried to set a runtime paramter to the value of the function parameter.
CREATE FUNCTION test_function (param VARCHAR)
RETURNS VOID AS $tf$
BEGIN
SET choice.p = param;
RAISE NOTICE '%', current_setting('choice.p');
END; $tf$ LANGUAGE plpgsql;
However, the value printed is 'param'. param is treated like a string instead of a parameter name. Why is it like this, and how can I achieve what i try to do?
The PL/pgSQL variables is working only for SELECT and DML commands. These statements has a execution plan, that can be executed with parameters. PLpgSQL runtime is able to use plpgsql variables as parameters. The static SQL commands without a plan like DDL, SET, SHOW, .. cannot to use a plpgsql variables. There is not unique way how to do it - and there is risk of ambiguous semantic. You should to use dynamic SQL in this case.
DO $$
BEGIN
EXECUTE format('SET choice.p = %L', 'some text);
RAISE NOTICE '%', current_setting('choice.p');
END;
$$;
The main reason why your example doesn't work is simple - SQL SET command doesn't support a expressions, and then there is not a correct way, how to apply plpgsql variables there.
Suppose I create two functions like so:
create function test() returns int
as
$$
select 1::int
$$
language sql;
create function test(int default 5) returns int
as
$$
select $1
$$
language sql;
If I do this:
select * from test();
I get an error saying that function test() is not unique. Is there any way to call the first function above? Similarly, how can I call the second function above using the default value?
No - there's not a way and it is documented:
https://www.postgresql.org/docs/current/static/typeconv-func.html
Functions that have default values for parameters are considered to
match any call that omits zero or more of the defaultable parameter
positions. If more than one such function matches a call, the one
appearing earliest in the search path is used. If there are two or
more such functions in the same schema with identical parameter types
in the non-defaulted positions (which is possible if they have
different sets of defaultable parameters), the system will not be able
to determine which to prefer, and so an “ambiguous function call”
error will result if no better match to the call can be found.
Emphasis mine.
How to create two VARIADIC parameters. Look at my code and correct me.
CREATE OR REPLACE FUNCTION ip_source_test(text,text,date,date,VARIADIC int[],VARIADIC text[])
RETURNS TABLE (no_documents int, "Report By" text, "Report_By" text) AS
$$
BEGIN
IF 'Source Member' = $1 THEN
RETURN QUERY SELECT.....
ELSEIF 'company' = $1 THEN
RETURN QUERY SELECT.....
ELSE
RAISE NOTICE 'Not Worked';
END IF;
RETURN;
END;
$$ LANGUAGE plpgsql;
Error: VARIADIC parameter must be the last input parameter.
In SQL code im supposed to use 6 parameters. Please update me with sample code.
There can be only one VARIADIC per function, since variadic encompasses all the other arguments passed by the caller.
If you mean for the caller to use arrays, there's no point in using variadic anyway, the function signature could look like:
CREATE FUNCTION ip_source_test(text,text,date,date,int[], text[])
The error message tells you:
VARIADIC parameter must be the last input parameter.
It follows logically that a function can only take a single VARIADIC parameter. There can be other (non-VARIADIC) parameters before that one. The manual:
Effectively, all the actual arguments at or beyond the VARIADIC
position are gathered up into a one-dimensional array