Put stored procedure result/output into variable - sql

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).

Related

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.

How to handle parameters in SQL PACKAGE?

I have a table which has columns id, name and password.
I made also a SQL PACKAGE for that which looks like (I omitted Package header, since to emphasis my point more clear):
create or replace PACKAGE BODY MEMBER
is
FUNCTION createWith(v_id, v_name, v_password)
return Number
is
BEGIN
Insert into tbl_member(id, name, password)
Values(v_id, v_name, v_password);
return SQL%ROWCOUNT ;
END createWith;
However, since name column is not necessary column(has no 'not null' option), I sometimes I pass only two parameters(id and password). As far as I know, if the numbers of parameter I sending and numbers of declared parameters in function do not match, it should be 'wrong type or number exception', but It works well.
The thing I wonder is how it can automatically handle empty parameter.
Is anyone who knows useful link or its logic, explain this.
//=============================================================
This is first addition
First of all, I guess my question was not clear enough.
So I going to try again.
step 0, make a table with no constrains and options.(also no default values)
step 1, this is the function header.
function creatWith(v_id in varchar2, v_name in varchar2, v_password in varchar2) return number;
step 2, I call this Package in java(it is web application based on Springframework. However, my company call this a 'solution', so I can not open source code).
However, the method which mapped with this Function has only two parameters. like
public void insert(String id, String pw);
step 3, This is the point of question. It occurs an error or not? In my case, it works. But I do not know My company solution handle or Oracle DB automatically does this.
If Oracle does have, can I get some documents for this policy?
It seems that Oracle tries to use "NULL" values for empty parameters. Change the field to NOT NULL and it will start to return an error.
Try declaring a DEFAULT attribute, like:
FUNCTION createWith(
v_id IN NUMBER,
v_name IN VARCHAR2 DEFAULT 'empty',
v_password IN VARCHAR2)
With this, it will write 'empty' for the Name field when the parameter is empty.
For Oracle Database, declare DEFAULT value in the function definition.
FUNCTION createWith(v_id IN NUMBER,
v_name IN VARCHAR2 DEFAULT 'N.A.',
v_password IN VARCHAR2);

How to obtain name of input variable of the procedure (PLSQL)

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

Function/variable scope (pass by value or reference?)

I'm completely confused by Lua's variable scoping and function argument passing (value or reference).
See the code below:
local a = 9 -- since it's define local, should not have func scope
local t = {4,6} -- since it's define local, should not have func scope
function moda(a)
a = 10 -- creates a global var?
end
function modt(t)
t[1] = 7 -- create a global var?
t[2] = 8
end
moda(a)
modt(t)
print(a) -- print 9 (function does not modify the parent variable)
print(t[1]..t[2]) -- print 78 (some how modt is modifying the parent t var)
As such, this behavior completely confuses me.
Does this mean that table variables
are passed to the function by
reference and not value?
How is the global variable creation
conflicting with the already define
local variable?
Why is modt able to
modify the table yet moda is not able
to modify the a variable?
You guessed right, table variables are passed by reference. Citing Lua 5.1 Reference Manual:
There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table.
....
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
So nil, booleans, numbers and strings are passed by value. This exactly explains the behavior you observe.
Lua's function, table, userdata and thread (coroutine) types are passed by reference. The other types are passed by value. Or as some people like to put it; all types are passed by value, but function, table, userdata and thread are reference types.
string is also a kind of reference type, but is immutable, interned and copy-on-write - it behaves like a value type, but with better performance.
Here's what's happening:
local a = 9
local t = {4,6}
function moda(a)
a = 10 -- sets 'a', which is a local introduced in the parameter list
end
function modt(t)
t[1] = 7 -- modifies the table referred to by the local 't' introduced in the parameter list
t[2] = 8
end
Perhaps this will put things into perspective as to why things are the way they are:
local a = 9
local t = {4,6}
function moda()
a = 10 -- modifies the upvalue 'a'
end
function modt()
t[1] = 7 -- modifies the table referred to by the upvalue 't'
t[2] = 8
end
-- 'moda' and 'modt' are closures already containing 'a' and 't',
-- so we don't have to pass any parameters to modify those variables
moda()
modt()
print(a) -- now print 10
print(t[1]..t[2]) -- still print 78
jA_cOp is correct when he says "all types are passed by value, but function, table, userdata and thread are reference types."
The difference between this and "tables are passed by reference" is important.
In this case it makes no difference,
function modt_1(x)
x.foo = "bar"
end
Result: both "pass table by reference" and "pass table by value, but table is a reference type" will do the same: x now has its foo field set to "bar".
But for this function it makes a world of difference
function modt_2(x)
x = {}
end
In this case pass by reference will result in the argument getting changed to the empty table. However in the "pass by value, but its a reference type", a new table will locally be bound to x, and the argument will remain unchanged. If you try this in lua you will find that it is the second (values are references) that occurs.
I won't repeat what has already been said on Bas Bossink and jA_cOp's answers about reference types, but:
-- since it's define local, should not have func scope
This is incorrect. Variables in Lua are lexically scoped, meaning they are defined in a block of code and all its nested blocks.
What local does is create a new variable that is limited to the block where the statement is, a block being either the body of a function, a "level of indentation" or a file.
This means whenever you make a reference to a variable, Lua will "scan upwards" until it finds a block of code in which that variable is declared local, defaulting to global scope if there is no such declaration.
In this case, a and t are being declared local but the declaration is in global scope, so a and t are global; or at most, they are local to the current file.
They are then not being redeclared local inside the functions, but they are declared as parameters, which has the same effect. Had they not been function parameters, any reference inside the function bodies would still refer to the variables outside.
There's a Scope Tutorial on lua-users.org with some examples that may help you more than my attempt at an explanation. Programming in Lua's section on the subject is also a good read.
Does this mean that table variables are passed to the function by reference and not value?
Yes.
How is the global variable creation conflicting with the already define local variable?
It isn't. It might appear that way because you have a global variable called t and pass it to a function with an argument called t, but the two ts are different. If you rename the argument to something else, e,g, q the output will be exactly the same. modt(t) is able to modify the global variable t only because you are passing it by reference. If you call modt({}), for example, the global t will be unaffected.
Why is modt able to modify the table yet moda is not able to modify the a variable?
Because arguments are local. Naming your argument a is similar to declaring a local variable with local a except obviously the argument receives the passed-in value and a regular local variable does not. If your argument was called z (or was not present at all) then moda would indeed modify the global a.

Call for a function with a variable name?

I have one package that has different procedures, and one main procedure through which I am calling other procedures.
Through the front end, I am passing the procedure name into main(). Is there any way by which the procedure can be called just writing the parameter name containing('Procedure Name that is need to be called')?
CREATE OR REPLACE PACKAGE BODY UPLOAD_PKG
IS
--This procedure will populate LOG with messages
PROCEDURE PRINT_LOG_PR IS
BEGIN
fnd_file.put_line(fnd_file.LOG,'ABC');
END PRINT_LOG_PR;
--This procedure will populate LOG with messages
PROCEDURE PRINT_LOG1 IS
BEGIN
fnd_file.put_line(fnd_file.LOG, 'XYZ');
END PRINT_LOG1;
PROCEDURE Main( p_obj_type VARCHAR2
, errbuf VARCHAR2
, retcode VARCHAR2) IS
BEGIN
-Is this possible for eg i have passed PRINT_LOG1 here and calling PRINT_LOG1
p_obj_type ;-
END main;
END UPLOAD_PKG
Yes.
PROCEDURE Main( p_obj_type VARCHAR2
, errbuf VARCHAR2
, retcode VARCHAR2) IS
BEGIN
CASE p_obj_type
WHEN 'PRINT_LOG_PR' THEN PRINT_LOG_PR;
WHEN 'PRINT_LOG1' THEN PRINT_LOG1;
END CASE;
END main;
Use:
CREATE OR REPLACE PACKAGE BODY UPLOAD_PKG
IS
--This procedure will populate LOG with messages
PROCEDURE PRINT_LOG_PR IS
BEGIN
fnd_file.put_line(fnd_file.LOG,'ABC');
END PRINT_LOG_PR;
--This procedure will populate LOG with messages
PROCEDURE PRINT_LOG1 IS
BEGIN
fnd_file.put_line(fnd_file.LOG, 'XYZ');
END PRINT_LOG1;
PROCEDURE MAIN( p_obj_type VARCHAR2
, errbuf VARCHAR2
, retcode VARCHAR2) IS
BEGIN
CASE p_obj_type
WHEN 'PRINT_LOG_PR' THEN UPLOAD_PKG.PRINT_LOG_PR;
WHEN 'PRINT_LOG1' THEN UPLOAD_PKG.PRINT_LOG1;
END CASE;
END MAIN;
END UPLOAD_PKG
The CASE statement I used in the MAIN stored procedure is the PLSQL CASE statement, not the ANSI SQL CASE. You can tell because the PLSQL version needs END CASE to end the CASE statement.
If you don't want to use dynamic pl/sql, then I would suggest to use constant variables in package header to choose between procedures (avoiding hard coding much as possible).
Main procedure call would be for example:
UPLOAD_PKG.MAIN(UPLOAD_PKG.C_PRINT_LOG_PR, v_errbuf, v_retcode);
And in the Main body you would use case like this:
CASE p_obj_type
WHEN C_PRINT_LOG_PR THEN UPLOAD_PKG.PRINT_LOG_PR;
WHEN C_PRINT_LOG1 THEN UPLOAD_PKG.PRINT_LOG1;
ELSE RAISE SOME_ERROR;
END CASE;
In header you can define constant variables to contain whatever:
CREATE OR REPLACE PACKAGE UPLOAD_PKG
IS
C_PRINT_LOG_PR CONSTANT VARCHAR2(22) := 'What ever';
C_PRINT_LOG1 CONSTANT VARCHAR2(22) := 'What ever2';
...
But some cases client applications cannot refer global variables of packages, so you need to create function for every constant variable to return those. But this will go little bit too complicated, if you just could call those correct procedures...
But for the curiosity can you tell us why do you need to use package this way?
As well as the CASE solution, it is possible to do this using dynamic PL/SQL.
PROCEDURE MAIN( p_obj_type VARCHAR2
, errbuf VARCHAR2
, retcode VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'begin upload_pkg.'||p_obj_type|| '; end;';
END MAIN;
Simple parameters (Date, Varhar2, Number) can be passed IN OUT with the USING command.
The key question is whether it is advisable.
As with any dynamic language, it leaves scope for errors that will only be found at runtime, rather than compile time - i.e. passing in a value for p_obj_type that does not exist. You could mitigate this through constants or abstract data types.
Also each dynamic sql or pl/sql command incurs a small parsing overhead vs actual compiled code. This overhead is small, but becomes noticeable if performed inside a loop.
Lastly, the called code must have the same parameter signature.