Receive a db link name as a variable in Oracle PLSQL - oracle

I have the following function in PLSQL which connects remotely to different Database Links to change passwords:
FUNCTION fun_change_password(DB_LINK_VARIABLE varchar2)
RETURN binary_integer IS
jobid binary_integer;
BEGIN
dbms_job.submit#DB_LINK_VARIABLE (jobid,'begin execute immediate ''alter user MYUSER identified by mypassw''; end;');
COMMIT;
RETURN jobid;
END;
My goal is to specify which DB Link to use sending its name in a varchar2 variable called *DB_LINK_VARIABLE*. But when I compile this into a package, the parser sends me an error:
PLS-00352: Unable to access another database 'DB_LINK_VARIABLE'
Obviously, I pre-configured and tested all my datalinks and works perfectly.
How can I use variable 'DB_LINK_VARIABLE' into this code?

You can do this with dynamic SQL by executing an anonymous PL/SQL block.
Below is a simple example where I execute dbms_utility.get_time function over a database link.
$ cat so35.sql
declare
function remote_time(p_dblink in varchar2) return number is
v_time number;
begin
execute immediate
'begin :time := dbms_utility.get_time#' || p_dblink || '; end;'
using out v_time;
return v_time;
end;
begin
dbms_output.put_line('time = ' || remote_time('foo'));
end;
/
SQL> select dbms_utility.get_time as local, dbms_utility.get_time#foo as remote from dual;
LOCAL REMOTE
---------- ----------
77936814 1546395927
SQL> #so35.sql
time = 1546396850
PL/SQL procedure successfully completed.
SQL>

PLS-00352: Unable to access another database 'DB_LINK_VARIABLE'
Error message shows, oracle is looking for a db link called DB_LINK_VARIABLE instead of the value associated to it.
You may need to do a check on variable, and make the hardcoding of the db link , instead of using a bind variable for it.!
Functions are compiled code in DB, so I guess oracle would do a semantic check on this during compilation itself, rather than doing it in runtime.
If it was just a SQL call to remote db, EXECUTE IMMEDIATE would have been used. Since it is PL/SQL there is no way for it, but for having multiple IF conditions, to validate the variable name, and making the full name in your PL/SQL block.

Related

Not able to call procedure in Oracle APEX

I am trying to call procedure in oracle apex but I am facing problem in displaying the output of procedure while passing the parameter as emp_id to that procedure from oracle apex. Can anyone help me?
procedure that I have written in SQL developer tool.
create or replace PROCEDURE TEST_PROC(EMP_ID1 IN Number)
As
RESULT TIMESHEET_EMPLOYEES%ROWTYPE;
BEGIN
SELECT * INTO RESULT.EMP_ID,RESULT.NAME,RESULT.LOCATION,RESULT.CITY,RESULT.COUNTRY,RESULT.EMPLOYMENT_TYPE,RESULT.EMAIL_ID,RESULT.PHONE_NUMBER,RESULT.CREATED_BY,RESULT.CREATED_ON,RESULT.UPDATED_ON,
RESULT.UPDATED_BY,RESULT.DATE_OF_JOINING,RESULT.ROLE_ID,RESULT.SUPERVISOR_ID FROM TIMESHEET_EMPLOYEES
WHERE EMP_ID=EMP_ID1;
DBMS_OUTPUT.PUT_LINE('EMP_ID:'||RESULT.EMP_ID||' '||'NAME:'||RESULT.NAME||' '||'LOCATION:'||RESULT.LOCATION||' '||'CITY:'||RESULT.CITY ||' '||'COUNTRY:'||RESULT.COUNTRY||' '||'EMPLOYMENT_TYPE:'||
RESULT.EMPLOYMENT_TYPE||' '||'EMAIL_ID:'||RESULT.EMAIL_ID||' '||'PHONE_NUMBER:'||RESULT.PHONE_NUMBER||' '||'CREATED_BY:'||RESULT.CREATED_BY||' '||'CREATED_ON:'||RESULT.CREATED_ON||' '||'UPDATED_ON:'||
RESULT.UPDATED_ON||' '||'UPDATED_BY:'||RESULT.UPDATED_BY||' '||'DATE_OF_JOINING:'||RESULT.DATE_OF_JOINING||' '||'ROLE_ID:'||RESULT.ROLE_ID||' '||'SUPERVISOR_ID:'||RESULT.SUPERVISOR_ID);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE'||' '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('SQLERRM'||' '||SQLERRM);
END;
herein oracle apex in PLSQL code I am trying to call that procedure but I am not able to see any output.
BEGIN
TEST_PROC(:P1_EMPID);
END;
Can someone help me as I am new to APEX???
Apex can't display result of DBMS_OUTPUT.PUT_LINE.
Two simple options you might use:
add another, OUT parameter(s) to your current procedure, or
convert this procedure to a function which returns the result as a concatenated string
Both of them should return the result into an item on the page.
For example, if it were a procedure:
create or replace PROCEDURE TEST_PROC(EMP_ID1 IN Number,
par_result out varchar2
)
is
-- ... your current code goes here; I presume it does what you wanted
-- at the end, return the result as
par_result := 'EMP_ID:'||RESULT.EMP_ID||' '||'NAME:'||RESULT.NAME || ...
end;
Call it in a process as
TEST_PROC(:P1_EMPID, :P1_RESULT);
As of code you wrote: if you declared result as %rowtype, it is simpler to insert directly into it, not into every separate piece of it. For example:
select *
into result --> this
from timesheet_employees
where emp_id = emp_id1;

How to write an Oracle procedure with a select statement (Specifically on SQL Developer)?

I want to create a simple Oracle Stored procedure on SQL Developer that will return some records on a simple select query. I do not want to pass in any parameter, but I just want the Records to be returned back from the procedure into a result set -> a suitable variable.
I have been trying to use the following syntax :
create or replace PROCEDURE Getmarketdetails2(data OUT varchar2)
IS
BEGIN
SELECT *
into data
from dual;
END Getmarketdetails2;
But it gives me an error while I try to execute with the following exec statement -->
Declare a Varchar2;
exec Getmarketdetails2(a);
Error: PLS-00103: Encountered the symbol "end-of-file" when expecting "something else".
Cause: Usually a PL/SQL compilation error.
Appreciate if anyone can help me out of this long pending situation! I have tried enough to find a basic guide to create a simple Oracle stored procedure and execute it in SQL Developer, but none of them answer to the point!!
You want:
DECLARE
a VARCHAR2(4000); -- Give it a size
BEGIN -- Begin the anonymous PL/SQL block
Getmarketdetails2(a); -- Call the procedure
DBMS_OUTPUT.PUT_LINE( a ); -- Output the value
END; -- End the anonymous PL/SQL block
/ -- End the PL/SQL statement
or:
VARIABLE a VARCHAR2(4000); -- Create a bind variable
EXEC Getmarketdetails2(:a); -- Execute the procedure using the bind variable
PRINT a -- Print the bind variable
Assuming an up-to-date Oracle version, you can use dbms_sql.return_result()
create or replace PROCEDURE Getmarketdetails2
IS
c1 SYS_REFCURSOR;
BEGIN
OPEN c1 FOR
SELECT *
from dual;
DBMS_SQL.RETURN_RESULT(c1);
END Getmarketdetails2;
/
Then simply run
exec Getmarketdetails2
The only drawback is that SQL Developer only displays the result as text, not as a proper result grid.
This is how I return a cursor in Oracle
PROCEDURE GetAllData (P_CURSOR OUT SYS_REFCURSOR)
IS
BEGIN
OPEN P_CURSOR FOR
SELECT *
FROM TABLE ;
END GetAllData ;
Declare a Varchar2;
exec Getmarketdetails2(a);
Your procedure is ok;
Instead of above query, use below query to run sp:
Declare
a Varchar2(10);
Begin
Getmarketdetails2(a);
End;

Temporary and Permanent Stored Procedure

I am creating Stored Procedure in Oracle and one of them is created permanently and another one is temporarily created and vanished after serving its purpose.How it is working please give your guidance when to use and how it is created.
---- This is not created in DB, just temporarily created and vanished
DECLARE name varchar2(10);
PROCEDURE printVal (name varchar2) IS
BEGIN
dbms_output.put_line ('name:' || name);
END;
BEGIN
name := 'Joe';
printVal(name);
END;
/
---- This is created in DB and permanently available
create PROCEDURE printVal (name varchar2) IS
BEGIN
dbms_output.put_line ('name:' || name);
END;
To understand, Dividing your sql in two parts.
Stored Procedure:
Stored procedures are stored in database.
We can call stored procedures any time after creation.
Stored procedures also supports input output parameters.
Anonymous Block:
These are unnamed pl/sql blocks.
Anonymous blocks are not stored in database.
Cannot pass paramters
---------- Stored Procedure Start--------
DECLARE name varchar2(10);
PROCEDURE printVal (name varchar2) IS
BEGIN
dbms_output.put_line ('name:' || name);
END;
--------- Stored Procedure End-----------
----------anonymous block Start----------
BEGIN
name := 'Joe';
printVal(name);
END;
/
----------anonymous block end ------------
Well, clearly there is different syntax -- the first one is an anonymous block, and the second creates a stored procedure. The expected behaviour is exactly what you observe, and covered by Oracle PL/SQL documentation. https://docs.oracle.com/cloud/latest/db112/LNPLS/overview.htm#LNPLS141

How to execute one procedure within another procedure

Hi I am writing one procedure which will be called by the program and this procedure will further call to another procedure to perform different business logic. so I did something like this.
PROCEDURE calculator(service_id IN NUMBER, amount IN NUMBER) as
p_proc_name varchar(100);
begin
select sc.procedure_name into p_proc_name from test.procedure sc where sc.service_config_id = service_id;
begin
execute immediate (p_proc_name) using 1;
exception when NO_DATA_FOUND then
DBMS_OUTPUT.PUT_LINE('p_proc_name = ' || p_proc_name);
end;
end sb_referal_calculator;
PROCEDURE f_service(amount IN NUMBER) as
cmpany_id NUMBER;
service_date date;
leases_days NUMBER;
referal_amount Number;
requested_quote_id number :=1;
begin
referal_amount :=0;
DBMS_OUTPUT.PUT_LINE('service_date = ');
end f_service;
PROCEDURE d_service(amount IN NUMBER) as
cmpany_id NUMBER;
service_date date;
leases_days NUMBER;
referal_amount Number;
requested_quote_id number :=1;
begin
referal_amount :=0;
DBMS_OUTPUT.PUT_LINE('service_date = ');
end d_service;
So here calcultor procedure will find the another procedure name dynamically and try to execute it with parameter. But it gives an error.
It is just a test program.
Executing PL/SQL: CALL DBMS_DEBUG_JDWP.CONNECT_TCP( '10.1.26.70', '55891' )
Debugger accepted connection from database on port 55891.
ORA-00900: invalid SQL statement
ORA-06512: at "test.demo_pkg", line 38
ORA-06512: at line 8
Executing PL/SQL: CALL DBMS_DEBUG_JDWP.DISCONNECT()
Process exited.
I really do not how this procedure will work to perform this task. I remembered it was running and I was doing testing. But really do not what i have did and stop working.
Please correct me what i doing wrong.
Thanks
When you use execute immediate it runs the dynamic statement in an SQL context that isn't able to see your PL/SQL context. That has several impacts here. Firstly, you have to call your procedure from PL/SQL so you need to create an anonymous block, as Egor Skriptunoff said, and exactly the format you need depends on what the table (and thus your vaiable) contains. The shortest it might be is:
execute immdiate 'begin ' || p_proc_name || ' end;' using 1;
But that assumes the varible contains a value like:
test_pkg.d_service(:arg);
If it only contains the name of the procedure with no arguments and no package qualifier, i.e. just d_service, it might need to be as much as:
execute immdiate 'begin test_pkg.' || p_proc_name || '(:arg); end;' using 1;
Or something in between.
The other impact is that the procedure name has to be public as it is effectively being called from outside the package when it's invoked dynamically; so it has to be declared in the package specification. That may already be the case here from the order the procedures are appearing in the body.
But if you are always calling procedures in the same package, and since you must then have a limited number of possible values, it might be simpler to avoid dynamic SQL and use the value to decide which procedure to call:
case p_proc_name
when 'f_service' then
f_service(1);
when 'd_service' then
d_service(1);
-- etc.
end case;
That also lets you call private procedures.

Get input from user in PL/SQL procedure

I'm building a procedure which would require to get an input from user to print few details. But when I use & to get values it fails with errors. the logic is as follows..
DBMS_OUTPUT.PUT_LINE('Enter Y to display Unauthorized records OR N to skip the display');
--SELECT &1 INTO lv_choice FROM DUAL;
IF NOT ('&lv_choice'='Y') THEN
DBMS_OUTPUT.PUT_LINE ('RECORDS WILL NOT BE DISPLAYED');
ELSE
DBMS_OUTPUT.PUT_LINE ('RECORDS TO BE DISPLAYED ARE:');
......
I have tried using &1 into dual or directly calling &lv_choice which is failing with PLSQL internal errors.
Any methods to get input from user to proceed further in the procedure?
This isn't possible in PL/SQL - PL/SQL doesn't have access to the terminal(unless you do something like plug in Java or call your program from a something like SQL*Plus(in which you can use commands like ACCEPT/PROMPT before you run the procedure).
The & variables are substitution variables, and are specific to SQL*Plus, not PL/SQL
If you are using some UI Terminal like SQLDeveloper or TOAD, you can achieve it using below code:
CREATE OR REPLACE INPUTPROCEDURE (LV_CHOICE IN VARCHAR2)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE('Enter Y to display Unauthorized records OR N to skip the display');
--SELECT &1 INTO lv_choice FROM DUAL;
IF lv_choice <> 'Y' THEN
DBMS_OUTPUT.PUT_LINE ('RECORDS WILL NOT BE DISPLAYED');
ELSE
DBMS_OUTPUT.PUT_LINE ('RECORDS TO BE DISPLAYED ARE:');
END INPUTPROCEDURE;
And Invoke the above Procedure like below:
DECLARE
dyn_stmt VARCHAR2(200);
b BOOLEAN := TRUE;
BEGIN
dyn_stmt := 'BEGIN INPUTPROCEDURE(:LV_CHOICE); END;';
EXECUTE IMMEDIATE dyn_stmt USING b;
END;

Resources