Execute procedure dynamically from another procedure - oracle

Inside packA I have a procedure:
procedure testA
is
v1 varchar2(3200) = 'schema1.packB.test2('''||P1||''','''||P2||''',''Name1'',''Name2'',20,30)';
begin
EXECUTE IMMEDIATE v1;
end;
when I test it:
begin
packA.testA();
end;
I get error: "invalid SQL statement"
But, when I execute v1 from the command line, like:
excecute schema1.packB.test2('ABC','DEF','Name1','Name2',20,30);
it's working.
I printed v1 to see what is executed, and looks exactly the same as "schema1.packB.test2('ABC','DEF','Name1','Name2',20,30)"

You need to include BEGIN..END when running a stored procedure using EXECUTE IMMEDIATE.
v1 varchar2(3200) = 'BEGIN schema1.packB.test2('''||P1||''','''||P2||''',''Name1'',''Name2'',20,30) END;';
EXECUTE IMMEDIATE runs an SQL(DML/select) statements or PL/SQL anonymous block
Also, consider using BIND variables instead of PL/SQL variables directly.
'schema1.packB.test2( :p1, :p2, :p3, :p4 ,20,30)' USING P1,P2, 'Name1', 'Name2'

You need a block to use execute immediate to call a procedure.
For example:
SQL> create or replace package pck is
2 procedure proc;
3 end;
4 /
Package created.
SQL> create or replace package body pck is
2 procedure proc is
3 begin
4 null;
5 end;
6 end;
7 /
Package body created.
SQL> begin
2 execute immediate 'pck.proc;';
3 end;
4 /
begin
*
ERROR at line 1:
ORA-00900: invalid SQL statement
ORA-06512: at line 2
SQL> begin
2 execute immediate 'begin pck.proc; end;';
3 end;
4 /
PL/SQL procedure successfully completed.
Also, while using an execute immediate, consider passing parameters with bind variables. For example, you can (better) re-write the following
begin
execute immediate 'begin pck.proc(''x''); end;';
end;
as
begin
execute immediate 'begin pck.proc(:1); end;' using 'x';
end;

Related

procedure compiling in oracle is not working

I have written below procedure in oracle but its getting compiled with error.
CREATE OR REPLACE PROCEDURE PROC_MIGRATE_ONEIBER
AS
BEGIN
-- EXECUTE PROCEDURE ONEFIBER_LNK_MIGRATE;
execute ONEFIBER_LNK_MIGRATE;
execute ONEFIBER_LNK_MIGRATE_CITY;
execute ONEFIBER_LNK_MIGRATE_NLDC;
END;
-- NULL;
END PROC_MIGRATE_ONEIBER;
I have to execute 3 procedures in one main procedure without any IN or OUT parameters. But its not working
Just remove the execute keyword. Whenever you want to call another procedure within the procedure you can directly use the procedure name and parameters, If any.
CREATE OR REPLACE PROCEDURE PROC_MIGRATE_ONEIBER AS
BEGIN
-- EXECUTE PROCEDURE ONEFIBER_LNK_MIGRATE;
ONEFIBER_LNK_MIGRATE;
ONEFIBER_LNK_MIGRATE_CITY;
ONEFIBER_LNK_MIGRATE_NLDC;
--END;
-- NULL;
END PROC_MIGRATE_ONEIBER;
/
Update: Check this small code of how it should be. All procedures created in this answer are just for demo. (Make sure that the procedure that you are calling is not INVALID)
SQL>
SQL> CREATE OR REPLACE PROCEDURE ONEFIBER_LNK_MIGRATE AS
2 BEGIN
3 NULL;
4 END;
5 /
Procedure created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE ONEFIBER_LNK_MIGRATE_CITY AS
2 BEGIN
3 NULL;
4 END;
5 /
Procedure created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE ONEFIBER_LNK_MIGRATE_NLDC AS
2 BEGIN
3 NULL;
4 END;
5 /
Procedure created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE PROC_MIGRATE_ONEIBER AS
2 BEGIN
3 ONEFIBER_LNK_MIGRATE;
4 ONEFIBER_LNK_MIGRATE_CITY;
5 ONEFIBER_LNK_MIGRATE_NLDC;
6 END PROC_MIGRATE_ONEIBER;
7 /
Procedure created.
SQL>

PL/SQL block does not execute to end when using EXECUTE IMMEDIATE

What am I trying to achieve?
I would like to copy Oracle procedures from one user to another using PL/SQL.
I would like to copy all procedures - including those with compilation errors.
Where am I stuck?
After EXECUTE IMMEDIATE creates a procedure with compilation errors the PL/SQL block does not execute any further.
There is no exception!
The following two blocks of code demonstrate the problem. The first block executes as expected. The second block does not execute in whole. Procedure p3 having a compilation error is not the problem. My problem is that procedure p4 is not created.
-- creates procedure p1 and p2
BEGIN
EXECUTE IMMEDIATE 'create or replace procedure p1 is begin null; end;';
EXECUTE IMMEDIATE 'create or replace procedure p2 is begin null; end;';
dbms_output.put_line('Done!');
END;
-- creates only procedure p3 and exits with no error
BEGIN
EXECUTE IMMEDIATE 'create or replace procedure p3 is begin null end;'; -- compilation error (missing semicolon)
EXECUTE IMMEDIATE 'create or replace procedure p4 is begin null; end;';
dbms_output.put_line('Done!');
END;
To go into more detail on Bob's answer: if you want to ignore compile exceptions, you'll need to wrap each execute immediate in an anonymous block.
BEGIN
BEGIN
EXECUTE IMMEDIATE 'create or replace procedure p3 is begin null end;'; -- compilation error (missing semicolon)
EXCEPTION WHEN OTHERS THEN null; -- ignore exceptions
END;
BEGIN
EXECUTE IMMEDIATE 'create or replace procedure p4 is begin null; end;';
EXCEPTION WHEN OTHERS THEN null; -- ignore exceptions
END;
dbms_output.put_line('Done!');
END;
Yes, there is an exception being raised. You see, "Success with compilation error" IS an exception. You can catch it by defining an exception variable and initializing it using EXCEPTION_INIT:
eCompilation_error EXCEPTION;
PRAGMA EXCEPTION_INIT(eCompilation_error, -24344);
db<>fiddle here

ORA-00900: invalid SQL statement- when run a package in oracle 12c

I am using Oracle 12c database and trying to run a package using SQL commands.
CREATE OR REPLACE PACKAGE "PK_CP_OTM" as
FUNCTION F_CP_OPTIMIZATION (
v_current_day IN VARCHAR2,
v_branch_code IN VARCHAR2)
RETURN VARCHAR2;
END PK_CP_OTM;
When I try to execute it using:
DECLARE
BEGIN
EXECUTE IMMEDIATE PK_CP_OTM.F_CP_OPTIMIZATION('20190409','BRNCD001');
END;
It shows:
ORA-00900: invalid SQL statement
ORA-06512: at line 3
00900. 00000 - "invalid SQL statement"
Thanks for your help.
As #Littlefoot said, you don't need dynamic SQL here, you can make a static call; but as you are calling a function you do need somewhere to put the result of the call:
declare
l_result varchar2(30); -- make it a suitable size
begin
l_result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
end;
/
In SQL*Plus, SQL Developer and SQLcl you can use the execute client command (which might have caused some confusion) and a bind variable for the result:
var result varchar2(30);
exec :result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
print result
There's nothing dynamic here, so - why would you use dynamic SQL at all?
Anyway: if you insist, then you'll have to select the function into something (e.g. a local variable). Here's an example
First, the package:
SQL> set serveroutput on
SQL>
SQL> create or replace package pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2;
6 end pk_cp_otm;
7 /
Package created.
SQL> create or replace package body pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2
6 is
7 begin
8 return 'Littlefoot';
9 end;
10 end pk_cp_otm;
11 /
Package body created.
How to call the function?
SQL> declare
2 l_result varchar2 (20);
3 begin
4 execute immediate
5 'select pk_cp_otm.f_cp_optimization (''1'', ''2'') from dual'
6 into l_result;
7
8 dbms_output.put_line ('result = ' || l_result);
9 end;
10 /
result = Littlefoot
PL/SQL procedure successfully completed.
SQL>

PL/SQL Trying to execute a very simple procedure

I know this is a very stupid question, but I just can't get this to work. I get an error saying that identifier hello must be declared
CREATE OR REPLACE PROCEDURE hello (p_name IN VARCHAR2)
IS
BEGIN
dbms_output.put_line (‘Welcome '|| p_name);
END hello;
/
EXECUTE hello('JOHN');
Everything's fine, except the first single quote in DBMS_OUTPUT call:
SQL> CREATE OR REPLACE PROCEDURE hello (p_name IN VARCHAR2)
2 IS
3 BEGIN
4 dbms_output.put_line ('Welcome '|| p_name);
5 END hello; -- ^ change this one
6 /
Procedure created.
SQL> EXECUTE hello('JOHN');
Welcome JOHN
PL/SQL procedure successfully completed.
SQL>

Running PLSQL ( Oracle ) Stored Procedure in Liquibase error : Package or function X is in an invalid state

I am trying to run the following stored procedure:
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL;
END;
END;
/
and calling it in changelog.xml as:
<sql>CALL RETRY_TRANS_EXCEPTION();</sql>
i get error:
Liquibase update Failed: Migration failed for change set eldata-changelog.xml::2016-08-25-cn-01::Ch Will:Reason: liquibase.exception.DatabaseException: Error executing SQL CALL RETRY_TRANS_EXCEPTION(): ORA-06575: Package or function RETRY_TRANS_EXCEPTION is in an invalid state
What i am trying to achieve is to be able to run a stored procedure through Liquibase with a loop in it.
Thanks for your help Prashant. What worked in my case was your solution plus one change:
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
v_query varchar2(100);
BEGIN
FOR i IN 1..500 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
v_query := 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NULL';
execute immediate v_query;
END loop;
END;
/
and then calling the Stored Procedure from the changelog, as:
<changeSet id="2016-08-25-cw-01" author="Ch Will">
<comment>
Testing retry logic on liquibase
</comment>
<sql>CALL RETRY_TRANS_EXCEPTION();</sql>
</changeSet>
You can't call it because the procedure does not compile correctly. Go back and fix the compilation errors, then try again.
Here are a couple of errors that stand out to me:
the for loop should end with end loop;, not end;
You can't have DDL statements directly in the code. You need dynamic SQL to execute a DDL statement from a procedure: execute immediate 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL';
Additional note: I don't understand why you are trying to execute the same DDL statement multiple times inside a loop. Obviously, you won't be able to add the same column with the same name over and over. You will get a runtime error.
SQL> CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
2 AS
3 BEGIN
4 FOR i IN 1..5 LOOP
5 DBMS_OUTPUT.PUT('Try #' || i);
6 ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL;
7 END;
8 END;
9 /
Warning: Procedure created with compilation errors
SQL> show err
Errors for PROCEDURE PRASHANT-MISHRA.RETRY_TRANS_EXCEPTION:
LINE/COL ERROR
-------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6/4 PLS-00103: Encountered the symbol "ALTER" when expecting one of the following: ( begin case declare end exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Did required fixes :
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
v_query varchar2(100);
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
v_query := 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL' ;
execute immediate v_query;
END loop;
END;
PLSQL stored procedure can't use DDL statements, like
alter table ...
so the
execute immediate ("...")
statement is required because in fact it creates an autonomous implicit transition that can't be rollbacked

Resources