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.
Related
I have a stored procedure that I'm working with where I'm calling another stored procedure within. The nested procedure accepts a value and returns an ID based on that successfully, but I can't seem to figure out how to cast that result into a variable for another stored procedure in the same wrapper.
Where I am now:
P1: BEGIN ATOMIC
CALL GET_ID_BY_VALUE(P_VALUE);
-- want to store output into V_NEW_ID
CALL NEW_PROCEDURE(V_NEW_ID);
END P1;
Does that make sense?
Arrange for the stored-procedure GET_ID_BY_VALUE to have a second parameter, which is an OUTPUT parameter (and this can be variable V_NEW_ID declared in the scope of your main procedure).
The signature of the GET_ID_BY_VALUE will then be something like GET_ID_BY_VALUE (IN P_VALUE varchar(...) , OUT V_NEW_ID bigint).
When the GET_ID_BY_VALUE sets that parameter V_NEW_ID to some value and returns, the caller has the assigned value accessible in variable V_NEW_ID, which is declared in the caller's scope. The caller can then supply that same variable as an input parameter to NEW_PROCEDURE( V_NEW_ID).
I am trying to use this PLSQL block:
DECLARE
V_LOG_ENTRY I_LOG_ENTRY;
V_LOG_RETURN INTEGER;
BEGIN
V_LOG_ENTRY := I_LOG_ENTRY(arguments...);
V_LOG_RETURN := I_SESSION_LOGGING.WRITE_LOG_ENTRY#REMOTE(V_LOG_ENTRY, 0);
END;
WRITE_LOG_ENTRY is expecting the type I_LOG_ENTRY. This type is present on both the local db and the remote db. They both have the same OID.
When I execute the block, I get the error: PLS-00306: wrong number or types of arguments in call to 'WRITE_LOG_ENTRY'
Signature for WRITE_LOG_ENTRY:
function WRITE_LOG_ENTRY(
P_LOG_ENTRY I_LOG_ENTRY, P_current_log_level INTEGER DEFAULT NULL
)
Thanks
What I was trying to do is not possible.
Please see Referencing Oracle user defined types over DBLINK? as suggested by #kfinity for a different approach.
Let's say I have procedure called myProc(variable varchar2);
Then I call it:
exec myProc(actionVariable);
Is there a way, how to obtain 'actionVariable' as a string in procedure myProc? So when I use procedure differently:
exec myProc(anotherVariable);
I'll obtain 'anotherVariable' as a string in procedure myProc.
Thanks. I only found that I can obtain origin variable name with 'select argument_name from user_arguments....'
You can't determine the name your caller assigned to the variable it passed (as far as I know; maybe you could hack something with PL/Scope but it wold be horrible).
I can see three options, depending on how many variations you need. I'm assuming there aren't many from your comment that the name affects which table the procedure works against.
You could pass the variable name, or the bit you're interested in, as a separate parameter:
procedure myProc(variable varchar2, variable_name varchar2) ...
exec myProc(varIDShop, 'Shop');
You could finesse that a little with wrapper procedures for each variant:
procedure myProc(variable varchar2, variable_name varchar2) ...
procedure myProcShop(variable varchar2) is
begin
myProc(variable, 'Shop');
end;
/
exec myProcShop(varIDShop);
... so your call just has to pick the relevant wrapper function to call.
Or you could declare multiple variables, one for each variant, and only set the one that's relevant:
procedure myProc(shop_variable varchar2, office_variable varchar2, ...) ...
exec myProc(shop_variable => varIDShop);
... and then test which is set within the procedure.
The last two would both mean your call still only has one argument, but they are a bit more complex, and have potential to use the wrong variable name or procedure name (cut-and-paste errors). Although so does the first, I suppose.
None of those directly use the variable name in the caller though. But on the other hand, you could call any of them, e.g. for testing, without having to declare a variable at all - just passing a string literal:
exec myProc('Tesco', 'Shop');
exec myProc(shop_variable => 'Sainsbury');
exec myProcShop('Asda');
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$;
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()');