Reuse Cursor Declaration in postgres - sql

Is there a way to reuse the cursor declaration in postgres.
For example :
I have a function like below, I am trying to use the declaration of curs1 for curs2 is it possible ?
create or replace function vin_temp_test(k date,x varchar) RETURNS numeric[] AS $$
declare
curs1 CURSOR FOR select prod_name,sum(item_val) sum_value from temp_table group by prod_name;
curs2 cursor curs1;
begin
null
end;
$$ LANGUAGE plpgsql VOLATILE;

Directly it is not possible
but you can simplify code by using views
you can use dynamic unbound queries
DECLARE
c1 refcursor;
c2 refcursor;
sqlstr text;
BEGIN
sqlstr := 'SELECT ... ';
OPEN c1 FOR EXECUTE sqlstr;
OPEN c2 FOR EXECUTE sqlstr;
Important question is - what do you mean 'reuse a cursor'"?
Maybe you can use scrollable cursor with possible reset
There is a statement MOVE
MOVE FIRST IN curs1 -- reset cursor curs1
see http://www.postgresql.org/docs/9.3/static/plpgsql-cursors.html

Related

Creating an anonymous DO block

Following Sergey's example here, https://stackoverflow.com/a/60834163/1513027
I'm trying to create an anonymous DO block rather than a function.
If I have the FETCH inside the block, it gives a syntax error, possibly wanting an INTO clause.
And it doesn't matter whether the name of the cursor is in quotes.
DO
$$
DECLARE _query TEXT;
DECLARE _cursor CONSTANT refcursor := _cursor;
BEGIN
_query := 'select "Port", "Version", "AddDate" from "LatestLogEntry";';
OPEN _cursor FOR EXECUTE _query;
FETCH ALL FROM _cursor; -- syntax error at ;
END
$$;
If I have it outside, as in Sergey's example, then it can't see the cursor declared inside the block. And it does matter whether the name of the cursor is in quotes.
DO
$$
DECLARE _query TEXT;
DECLARE _cursor CONSTANT refcursor := '_cursor';
BEGIN
_query := 'select "Port", "Version", "AddDate" from "LatestLogEntry";';
OPEN _cursor FOR EXECUTE _query;
END
$$;
FETCH ALL FROM _cursor -- ERROR: cursor "_cursor" does not exist
The answer was hidden in a comment in one of the examples.
-- need to be in a transaction to use cursors.
Wrapping it in a transaction works.
BEGIN;
DO
$$
DECLARE _query TEXT;
DECLARE _cursor CONSTANT refcursor := '_cursor';
BEGIN
_query := 'select "Port", "Version", "AddDate" from "LatestLogEntry";';
OPEN _cursor FOR EXECUTE _query;
END
$$;
FETCH ALL FROM _cursor -- ERROR: cursor "_cursor" does not exist
COMMIT
In pgadmin this does work see screen below run postgres 15
as Sergey pointed out this has to be in a transaction, else you get the error message you get.
you can try to use it in an tranction

How do I execute a SELECT query in a text string?

I have a function my_funct(param1,param2) returning a SELECT QUERY as a text, I usually C/c the result, remove quotes, then run it.
How can execute the returned text in a query that call the function ?
I expect something like this:
SELECT resultOf( myfunct('foo','bar'))
with no extra columnname/type to declare. If such function does not exits built-in, let's create it, I don't mind.
If I understood correctly you want
Call a function returning a select query as text
Run that query to get the result.
Number and type of columns are dynamic
1. Using Do Block:
DO
$$
declare
ref_cursor refcursor:='mycursor';
begin
open ref_cursor for execute (select * from my_funct('foo','bar')) ;
end;
$$;
--Fetch all data from cursor
Fetch all from mycursor;
2. Using Function returning refcursor:
You can create a function like below:
create function my_funct1(param1 text) returns refcursor as
$$
declare
ref_cursor refcursor:='mycursor';
begin
open ref_cursor for execute param1;
return ref_cursor;
end;
$$
language plpgsql
To call above function use following code:
begin ;
select my_funct1((select * from my_funct('foo','bar')) );
fetch all from mycursor;
commit;
DEMO

How to read multiple refcursor return by other procedure to another procedure

i'm having one procedure which returns setof cursors
Now i have to call that procedure to another procedure and access the data
that return by that procedure
is their any way to do this in postgres.
This is code for 1st procedure,
CREATE OR REPLACE FUNCTION public.returns_multiple_cursor( )
RETURNS SETOF refcursor
LANGUAGE 'plpgsql'
COST 100.0
AS $function$
DECLARE
_daily refcursor := 'first_cur';
_fac_hourly refcursor := 'second_cur';
BEGIN
open first_cur for
select * from x;
return next first_cur;
open second_cur for
select * from y;
return second_cur;
END
$function$;
ALTER FUNCTION public.returns_multiple_cursor();
Here code for other second procedure
CREATE OR REPLACE FUNCTION public.access_cursor( )
RETURNS SETOF refcursor
LANGUAGE 'plpgsql'
COST 100.0
AS $function$
DECLARE
BEGIN
-- what code will be here to access the cursor data in this procedure
select public.returns_multiple_cursor();
END;
ALTER FUNCTION public.access_cursor();
Unfortunately, you cannot use the FOR <recordvar> IN <cursor> loop, because it only works for bound cursors (which refcursors are not).
But you can still loop through them, with the old-fashioned FETCH:
declare
rec record;
cur refcursor;
begin
for cur in select returns_multiple_cursor() loop
loop
fetch next from cur into rec;
exit when not found;
-- do whatever you want with the single rows here
end loop;
close cur;
end loop;
end
Unfortunately, there is still another limitation: PostgreSQL caches the first cursor's plan (at least, it seems it does something like that), so you must use cursors, which uses the same column types (you'll have to use the same column names anyway, to be able to refer them in the inner loop, like rec.col1).
Complete, working example: http://rextester.com/FNWG91106 (see f.ex. what happens, when you remove casting from the cursors' queries).
If you have fix number of cursors (like in your example), but differently structured underlying queries, it might be easier to declare your returns_multiple_cursor as:
create or replace function returns_multiple_cursor(out first_cur refcursor,
out second_cur refcursor)
-- returns record (optional)
language plpgsql
-- ...
This way, you could access your cursors more directly in the calling context.
Update: it seems that when you don't use explicit column names, just generic record processing (via f.ex. JSON or hstore), plan caching does not cause any trouble:
http://rextester.com/QHR6096

run a query from a column

What i want: i have a table with queries, i need to make a query that runs one of the values in that column
ie:
queryname query
Chips select * from chips_table c join all_stores s on c.id=s.id where s.loc>213...
... ...
I know i want the result from the above query, how can i run a procedure or script or view or whatnot like
getme(Chips)
and this to run the
select * from chips_table c join all_stores s on c.id=s.id where s.loc>213...
Depends on what you want to do with the results afterwards, but for PL/SQL processing you may use something like:
-- Function to open and return the cursor for the query based on query name
CREATE OR REPLACE FUNCTION get_cursor (in_queryname IN VARCHAR2)
RETURN SYS_REFCURSOR
IS
c_query SYS_REFCURSOR;
v_query queries.query%type;
BEGIN
SELECT query INTO v_query FROM queries WHERE queryname = in_queryname;
OPEN c_query FOR v_query;
RETURN c_query;
END;
-- Example of use
DECLARE
c_query SYS_REFCURSOR;
some_variable INTEGER;
another_variable INTEGER;
BEGIN
LOOP
FETCH c_query INTO some_variable, another_variable;
EXIT WHEN c_query%NOTFOUND;
-- Do someting!
END LOOP;
CLOSE c_query;
EXCEPTION WHEN no_data_found THEN
NULL; -- Log the error!
END;

Calling a function that returns a refcursor

I am using Postgresql 8.3 and have the following simple function that will return a refcursor to the client
CREATE OR REPLACE FUNCTION function_1() RETURNS refcursor AS $$
DECLARE
ref_cursor REFCURSOR;
BEGIN
OPEN ref_cursor FOR SELECT * FROM some_table;
RETURN (ref_cursor);
END;
$$ LANGUAGE plpgsql;
Now , I can use the following SQL commands to call this function and manipulate the returned cursor ,but the cursor name is automatically generated by the PostgreSQL
BEGIN;
SELECT function_1(); --It will output the generated cursor name , for example , "<unnamed portal 11>" ;
FETCH 4 from "<unnamed portal 11>";
COMMIT;
Besides explicitly declaring the cursor name as the input parameter of the function as described by 38.7.3.5. Returning Cursors, can I declare my own cursor name and use this cursor name to manipulate the returned cursor instead of Postgresql automatically generates for me ?
If not, are there any commands that can get the generated cursor name ?
I'm not quite sure from wich version of Postgre this is available (in 8.4 it is valid) but i found quite easiest to define the cursor name when you declare it, like this:
CREATE OR REPLACE FUNCTION function_1() RETURNS refcursor AS $$
DECLARE
ref_cursor REFCURSOR := 'mycursor';
BEGIN
OPEN ref_cursor FOR SELECT * FROM some_table;
RETURN (ref_cursor);
END;
$$ LANGUAGE plpgsql;
And then you can get it like this:
BEGIN;
SELECT function_1();
FETCH 4 from mycursor;
COMMIT;
I find this method less cumbersome.
Hope that helps.
Yes, use:
CREATE OR REPLACE FUNCTION function_1(refcursor) RETURNS refcursor AS $$
BEGIN
OPEN $1 FOR SELECT * FROM some_table;
RETURN $1;
END;
$$ LANGUAGE plpgsql;
Result:
SELECT function_1('myowncursorname');
function_1
-----------------
myowncursorname
(1 row)
It looks like auto-generated name is <unnamed portal n>, where n is natural number (from 1).
EDIT:
As another way you could use pg_cursors view with such query to obtain generated cursor name:
SELECT name FROM pg_cursors WHERE statement LIKE 'SELECT * FROM some_table';
For example:
BEGIN;
SELECT function_1();
SELECT name FROM pg_cursors WHERE statement LIKE 'SELECT * FROM some_table';
COMMIT;
Result:
function_1
--------------------
<unnamed portal 3>
(1 row)
name
--------------------
<unnamed portal 3>
(1 row)