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.
Related
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.
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.
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);
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$;