sql call function multiple times in a loop. postgres 8.3 - sql

I have a function that has 'key' variable as an argument.
I want to call this function for a range of key values.
I tried this, didn't work...
BEGIN
for i IN 773..775 LOOP
test_count(i);
end LOOP;
end;
SQL error:
ERROR: syntax error at or near "for"
LINE 2: for i IN 773..775 LOOP

#Mihai already explained that you cannot run procedural elements outside of a function or anonymous code block with DO.
Your syntax would still fail, because you cannot call a function anywhere without taking care of the returned value(s). If you want to discard possible return values(s) use PERFORM in a function like this (works with PostgreSQL 8.3):
CREATE OR REPLACE FUNCTION foo()
RETURNS void LANGUAGE plpgsql AS
$BODY$
BEGIN
FOR i IN 773 .. 775
LOOP
PERFORM test_count(i);
END LOOP;
END;
$BODY$;

PostgreSQL 8.3 cannot run anonymous procedures/ functions or create variables outside of a procedure/ function.
The DO construct was added as support for anonymous procedures as of version 9.0.
You should run your code inside a function. Because the error message you are receiving states that FOR is an unexpected keyword in a global context.

Use a record type for your keys
DO $BODY$
DECLARE tmp_row record;
BEGIN
FOR tmp_row IN (SELECT key from my_keys_table)
LOOP
PERFORM test_function(tmp_row.key);
END LOOP;
END;
$BODY$;

Related

Passing parameter to SQL Function in plpgsql

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.

Set PgSQL runtime-paramter from function parameter?

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.

How to pass Array to SQL Stored Procedure

I am trying to pass arrays to a DB2 stored procedure and I am having trouble.
Here are a few code snippets:
create type intArrayType as integer array[];
CREATE OR REPLACE PROCEDURE
array_trial (IN integer_array INTARRAYTYPE)
BEGIN
SELECT UNNEST(integer_array) FROM sysibm.sysdummy1;
END
It compiles, but when I try to call:
CALL array_trial(ARRAY[1,2,3]);
I am getting a -104 error.
When I try to call from RPGLE, I cannot compile because it does not like the array
Any ideas?
UNNEST is used in the from clause as it creates a temporary table...
CREATE OR REPLACE PROCEDURE
array_trial (IN integer_array INTARRAYTYPE)
BEGIN
declare c1 cursor with return to client for
SELECT * FROM UNNEST(integer_array) as rs;
open c1;
END;
Unfortunately, the ARRAY constructor is currently rather limited. The documentation specifically says can only be specified on the right side of a SET variable or assignment-statement. So trying to use it directly like so doesn't work.
CALL array_trial(ARRAY[1,2,3]);
It returns the following message:
SQL State: 428H2
Vendor Code: -20441
Message: [SQ20441] Array type not valid where specified.
Cause . . . . . : An array type was used but is not allowed in the
specified context. Array types can only be used: -- As an argument of an
SQL or JAVA procedure. -- For an SQL variable declared in an SQL procedure.
-- In a CAST specification in an SQL procedure.
Recovery . . . : Remove the reference to the array type. Try the request again.
You can build a driver stored procedure:
create or replace procedure mysp
begin
declare myarray intArrayType;
set myarray = ARRAY[1,2,3];
call array_trial(myarray);
end;
And call that
call mysp;
From what I've been able to find so far An SP with an array parm can be called directly from another SQL procedure or Java...but not RPGLE.

VARIADIC parameter must be the last input parameter

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

Function as parameter to another function in Postgres

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()');