Returning array via INOUT parameter without modifications - arrays

I'm using PostgreSQL 9.1.3 and the following functions:
CREATE OR REPLACE FUNCTION cad(INOUT args text[], OUT retval int4) AS $cad$
BEGIN
retval := 0;
RAISE NOTICE 'cad: %', args;
END;
$cad$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION dodo(in_args text[]) RETURNS text[] AS $dodo$
DECLARE
_res text[];
_rv int4;
BEGIN
_res := in_args;
EXECUTE 'SELECT cad($1)' USING _res INTO _res, _rv;
RETURN _res;
END;
$dodo$ LANGUAGE plpgsql;
When I call cad directly, I get expected output:
psql$ select cad(ARRAY['Quiz']);
NOTICE: cad: {Quiz}
-[ RECORD 1 ]---
cad | ({Quiz},0)
Time: 0,319 ms
My expected result for the dodo(ARRAY['Quiz']) call is the input array without changes. But instead I receive the following error:
psql$ select dodo(ARRAY['Quiz']);
NOTICE: cad: {Quiz}CONTEXT: SQL statement "SELECT cad($1)"
PL/pgSQL function "dodo" line 8 at EXECUTE statement
ERROR: array value must start with "{" or dimension information
CONTEXT: PL/pgSQL function "dodo" line 8 at EXECUTE statement
What is wrong here?
P.S.: I have to use EXECUTE as function to call will vary, code simplified for the purpose of question.

You want something like:
EXECUTE 'SELECT * FROM cad($1)' USING _res INTO _res, _rv;
The return type isn't two columns of text[],int it's a record of (text[],int) which needs unwrapping.

Related

My function with array as parameter does not work

I proceed to specify my question and the solution I gave to the problem, for the benefit of the community.
I was trying to perform a multi-column insert using the identifier with a function.
For which, I was getting an error, my code was the following:
CREATE OR REPLACE FUNCTION acc.asignar_periodo(ids NUMERIC[], periodo INTEGER,codigo_subdiario VARCHAR)
RETURNS void
VOLATILE
AS
$$
DECLARE
cant_registros integer:= 0;
BEGIN
cant_registros := array_length(ids,1);
FOR i IN 1..cant_registros LOOP
EXECUTE'UPDATE '||$3||' SET periodo_tributario = $2 WHERE id = ids[i]';
END LOOP;
END;
$$ LANGUAGE plpgsql;
and my query is:
SELECT acc.asignar_periodo('{2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302}'::NUMERIC[],201612,'_08');
My solution was the following:
CREATE OR REPLACE FUNCTION acc.asignar_periodo(INTEGER[],INTEGER,INTEGER) RETURNS text VOLATILE AS
$$
DECLARE
qty integer:= array_length($1,1);
respuesta varchar := null;
BEGIN
FOR i IN 1..qty LOOP
EXECUTE'UPDATE _'||$3||' SET periodo_tributario = '||$2||' WHERE id = '||$1[i];
END LOOP;
respuesta := 'Periodo '||$2||' asignado a '||qty||' comprobantes del subdiario '||$3;
RETURN respuesta;
END;
$$ LANGUAGE plpgsql;
Note the correction, since when using EXECUTE it is necessary that the arguments escape the statements
There is no to loop needed to process the array. Postgres will process the entry array at once. After all set processing is what SQL is all about. Get into the mindset that whenever you write loop, likely incorrect and much slower. (Yes there occasions where it is necessary, but very few.) So: (see demo)
create or replace function asignar_periodo(ids numeric[], periodo integer,codigo_subdiario varchar)
returns void
language plpgsql
as $$
declare
stmt constant text = 'update %I set periodo_tributario = %s where id = any (''%s'')';
torun text;
begin
--torun = format(stmt, $3, $2, $1); -- this would work but
torun = format(stmt, codigo_subdiario, periodo, ids); -- I perfer parameter names to position reference
raise notice '%', torun;
execute torun;
end ;
$$;

GreenPlum -- 'concat ' function in greenplum

Is there 'concat' function in GreenPlum? I can use concat function in postgresql and it works well, but when i use it in Greenplum, I got an error.
select concat('a', 'b');
ERROR: function concat(unknown, unknown) does not exist at character 8
HINT: No function matches the given name and argument types. You may need to add explicit type casts.
LINE 1: select concat('a', 'b');
^
Is there some other functions can instead of 'concat' function in GreenPlum? And I have tried to create a function to instead of it, but got some syntax errors also.
CREATE OR REPLACE FUNCTION my_concat(VARIADIC arr VARCHAR[] ) RETURNS VARCHAR AS $$ SELECT array_to_string(arr, ''); $$ LANGUAGE SQL;
ERROR: syntax error at or near "VARCHAR" at character 51
LINE 1: CREATE OR REPLACE FUNCTION my_concat(VARIADIC arr VARCHAR[] ...
^
Anyone can help? Thanks very much!
Like most databases, Greenplum uses "||" to concatenate two strings together.
SELECT 'Green' || 'plum';
Result:
Greenplum
its a versional issue , you have use || in place where ever u using contact function.
Greenplum doesn't have the concat function yet. May be you can modify your code to use "||" instead of concat.
Well,
First I agree that you should replace your code to use the correct SQL syntax '||' for concatenation.
If you really want to create a function to emulate the concat, you could do something like:
create or replace function myschema.concat(arg1 text, arg2 text)
returns text as
$body$
declare
v_arg1 text;
v_arg2 text;
begin
v_arg1 := arg1;
v_arg2 := arg2;
return v_arg1 || v_arg2;
end
$body$
language plpgsql volatile;
Then, the query will work:
select myschema.concat('test1', 'test2');
>>test1test2
Hope you are looking for the below query.
gpadmin=# CREATE OR REPLACE FUNCTION my_concat( character varying[] ) RETURNS VARCHAR AS $$ SELECT array_to_string($1, ''); $$ LANGUAGE SQL;
gpadmin=# select my_concat(ARRAY['Green','plum']);
my_concat
Greenplum

PL/pgSQL "Malformed array literal" error within for loop

I have the following pl/pgsql function. (Obviously, this is not the full function, it's just the minimal amount of code needed to reproduce the problem)
CREATE OR REPLACE FUNCTION test_func(infos TEXT[][])
RETURNS void AS
$$
DECLARE
info TEXT[];
type TEXT[];
name TEXT;
BEGIN
FOREACH info SLICE 1 IN ARRAY infos LOOP
RAISE NOTICE 'Stuff: %', info;
type := info[1];
name := info[2];
RAISE NOTICE 'Done with stuff';
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
When I run the function using SELECT test_func('{{something, things},{other, data}}'::TEXT[][]);, I get the following output:
NOTICE: Stuff: {something,things}
ERROR: malformed array literal: "something"
DETAIL: Array value must start with "{" or dimension information.
CONTEXT: PL/pgSQL function test_func(text[]) line 10 at assignment
I don't understand how this error is happening. When the value of info is printed, it shows {something,things}, which seems to me to be a proper array literal.
I am using PostgreSQL version 9.4.7, in case it matters.
The variable type should be text (not text[]):
CREATE OR REPLACE FUNCTION test_func(infos TEXT[][])
RETURNS void AS
$$
DECLARE
info TEXT[];
type TEXT;
name TEXT;
...

how to call a pg function with libpq and get the param value

ALL
I have a postgresql function,so this:
CREATE OR REPLACE FUNCTION query_callouts(
INOUT io_cursor_ref refcursor,
INOUT opstatus integer,
INOUT errtext character varying)
RETURNS record AS
$BODY$
DECLARE
BEGIN
OPEN $1 FOR
SELECT tablename FROM pg_tables limit 10;
--SELECT * from call_out_numbers;
RETURN;
Exception
When Others Then
GET STACKED DIAGNOSTICS opstatus = RETURNED_SQLSTATE,
errText = MESSAGE_TEXT;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION query_callouts(refcursor, integer, character varying)
OWNER TO postgres;
I want to known ,how to use libpq in my c codes to visit the function - query_callouts and get the param io_cursor_ref and opstatus and errtext?
You can call the function just like you are executing any query:
select * from query_callouts('mycur', 0, '');
io_cursor_ref | opstatus | errtext
---------------+----------+---------
mycur | 0 |
(1 row)
opstatus and errtext would be set to the appropriate values if an exception occurs.
io_cursor_ref contains the name you have passed to the function.
Internally, a refcursor value is simply the string name of a so-called
portal containing the active query for the cursor. This name can be
passed around, assigned to other refcursor variables, and so on,
without disturbing the portal.
Note, you can use a refcursor only within a transaction.
All portals are implicitly closed at transaction end. Therefore a
refcursor value is usable to reference an open cursor only until the
end of the transaction.
You can use explicit transaction:
begin;
select * from query_callouts('mycur', 0, '');
fetch all in mycur;
-- save or show the query result
-- and finally
commit;
or use mycur inside a function.
The quotes are from the documentation.
It's just like any other query.
SELECT * FROM query_callouts('cursorname', 4, 'msg')
I suspect some if not all of your parameters should be OUT parameters not INOUT parameters, though. You don't ever use the input value of errtext at least.

Passing Array to Oracle Function

I am passing an array to a PL/SQL package function. I am doing this to use this array in a query inside the function which has IN clause.
My declaration of package looks like :
create or replace
PACKAGE selected_pkg IS
TYPE NUM_ARRAY IS TABLE OF NUMBER;
FUNCTION get_selected_kml(
in_layer IN NUMBER,
in_id IN NUMBER,
in_feature_ids IN selected_pkg.NUM_ARRAY,
in_lx IN NUMBER,
in_ly IN NUMBER,
in_ux IN NUMBER,
in_uy IN NUMBER
)
RETURN CLOB;
END selected_pkg;
In my PL/SQL function I am firing a query like following
select a.id, a.geom from Table_FIELD a where a.id in (select * from table (in_feature_ids)) and sdo_filter(A.GEOM,mdsys.sdo_geometry(2003,4326,NULL,mdsys.sdo_elem_info_array(1,1003,3), mdsys.sdo_ordinate_array(0,57,2.8,59)),'querytype= window') ='TRUE'
The same query runs fine if I run it from anonymous block like
CREATE TYPE num_arr1 IS TABLE OF NUMBER;
declare
myarray num_arr1 := num_arr1(23466,13396,14596);
BEGIN
FOR i IN (select a.id, a.geom from Table_FIELD a where a.id in (select * from table (myarray)) and sdo_filter(A.GEOM,mdsys.sdo_geometry(2003,4326,NULL,mdsys.sdo_elem_info_array(1,1003,3), mdsys.sdo_ordinate_array(0,57,2.8,59)),'querytype= window') ='TRUE'
loop
dbms_output.put_line(i.id);
end loop;
end;
If I try to run it by calling function as below
--Running function from passing array for IDs
declare
result CLOB;
myarray selected_pkg.num_array := selected_pkg.num_array(23466,13396,14596);
begin
result:=SELECTED_PKG.get_selected_kml(3, 19, myarray, 0.0,57.0,2.8,59);
end;
I am getting error
ORA-00904: "IN_FEATURE_IDS": invalid identifier
Could someone please help me understand the cause of it?
Thanks,
Alan
You cannot query a type declared in plsql in a sql query, as the sql engine doesn't recognise it.
Your first example works because you have declared the type numarr1 in the database, whereas the type selected_pkg.num_array is declared in a package.
Good summary here
I can't quite recreate the error you're getting; the anonymous block doesn't refer to in_feature_ids, and the package ought to only report that if it doesn't recognise it on compilation rather than at runtime - unless you're using dynamic SQL. Without being able to see the function body I'm not sure how that's happening.
But you can't use a PL/SQL-defined type in an SQL statement. At some point the table(in_feature_ids) will error; I'm getting an ORA-21700 when I tried it, which is a new one for me, I'd expect ORA-22905. Whatever the error, you have to use a type defined at schema level, not within the package, so this will work (skipping the spatial stuff for brevity):
CREATE TYPE num_array IS TABLE OF NUMBER;
/
CREATE OR REPLACE PACKAGE selected_pkg IS
FUNCTION get_selected_kml(
in_layer IN NUMBER,
in_id IN NUMBER,
in_feature_ids IN NUM_ARRAY,
in_lx IN NUMBER,
in_ly IN NUMBER,
in_ux IN NUMBER,
in_uy IN NUMBER
) RETURN CLOB;
END selected_pkg;
/
CREATE OR REPLACE PACKAGE BODY selected_pkg IS
FUNCTION get_selected_kml(
in_layer IN NUMBER,
in_id IN NUMBER,
in_feature_ids IN NUM_ARRAY,
in_lx IN NUMBER,
in_ly IN NUMBER,
in_ux IN NUMBER,
in_uy IN NUMBER
) RETURN CLOB IS
BEGIN
FOR i IN (select * from table(in_feature_ids)) LOOP
DBMS_OUTPUT.PUT_LINE(i.column_value);
END LOOP;
RETURN null;
END get_selected_kml;
END selected_pkg;
/
... and calling that also using the schema-level type:
set serveroutput on
declare
result CLOB;
myarray num_array := num_array(23466,13396,14596);
begin
result:=SELECTED_PKG.get_selected_kml(3, 19, myarray, 0.0,57.0,2.8,59);
end;
/
23466
13396
14596
PL/SQL procedure successfully completed.
Also note that you have to use exactly the same type, not just one that looks the same, as discussed in a recent question. You wouldn't be able to call your function with a variable of num_arr1 type, for example; they look the same on the surface but to Oracle they are different and incompatible.

Resources