How to Dynamically Call PL/SQL Procedure in Oracle

Posted in: Technical Track

Just got an interesting note on Twitter that you can’t call a stored procedure dynamically in Oracle from a PL/SQL block like passing the procedure name in a variable.

Well, yes we can!

And the answer is EXECUTE IMMEDIATE — it can be used to run anonymous PL/SQL blog and not just a SQL statement. However, you will want to think many many times before doing so… if you love your data.

Let’s create the test procedures:

SQL> create or replace procedure bingo as
  2  begin
  3  dbms_output.put_line('Bingo!');
  4  end;
  5  /

Procedure created.

SQL> create or replace procedure bambam as 
  2  begin
  3  dbms_output.put_line('BAM BAM!');
  4  end;
  5  /

Procedure created.

Now let’s create a wrapper that we will call passing a procedure name:

SQL> create or replace procedure call_dynamic(proc_name IN varchar2) as
  2  begin
  3  execute immediate 'begin ' || proc_name || '; end;';
  4  end;
  5  /

Procedure created.

Now let’s enable server output and try to call our procedures dynamically

SQL> set serverout on
SQL> exec call_dynamic('bingo');
Bingo!

PL/SQL procedure successfully completed.

SQL> exec call_dynamic('bambam');
BAM BAM!

PL/SQL procedure successfully completed.

Now, what was that we wanted to think about? Ah here… Let’s create a table:

SQL> create table important_data (data varchar2(1000));

Table created.

SQL> insert into important_data values ('Oracle rocks!');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from important_data;

DATA
-----------------------
Oracle rocks!

So what can someone do with such procedure… perhaps, something like this?

SQL> exec call_dynamic('delete from important_data; commit');

PL/SQL procedure successfully completed.

SQL> select * from important_data;

no rows selected

Oups… or maybe something like this?

SQL> exec call_dynamic('execute immediate ''drop table important_data''');

PL/SQL procedure successfully completed.

SQL> select * from important_data;
select * from important_data
              *
ERROR at line 1:
ORA-00942: table or view does not exist

You’ve got an idea. :)

OK. Let’s finally clean up:

SQL> exec call_dynamic('execute immediate ''drop procedure bingo''')

PL/SQL procedure successfully completed.

SQL> exec call_dynamic('execute immediate ''drop procedure bambam''')

PL/SQL procedure successfully completed.

And final clean up needs to be smarter as this will hang blocking itself:

SQL> exec call_dynamic('execute immediate ''drop procedure call_dynamic''')

^CBEGIN call_dynamic('execute immediate ''drop procedure call_dynamic'''); END;

*
ERROR at line 1:
ORA-01013: user requested cancel of current operation
ORA-06512: at line 1
ORA-06512: at "SYS.CALL_DYNAMIC", line 3
ORA-06512: at line 1

But doable:

SQL> exec call_dynamic('declare a number; begin dbms_job.submit(a,''begin execute immediate ''''drop procedure call_dynamic''''; end;''); commit; end')

PL/SQL procedure successfully completed.

SQL> exec call_dynamic('null');
BEGIN call_dynamic('null'); END;

      *
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'CALL_DYNAMIC' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

Anyway, the real requirements were more complicated. Granted I don’t know all the details but I strongly suspect that there would be a better solution than calling a PL/SQL procedure dynamically.

email
Want to talk with an expert? Schedule a call with our team to get the conversation started.

About the Author

What does it take to be chief technology officer at a company of technology experts? Experience. Imagination. Passion. Alex Gorbachev has all three. He’s played a key role in taking the company global, having set up Pythian’s Asia Pacific operations. Today, the CTO office is an incubator of new services and technologies – a mini-startup inside Pythian. Most recently, Alex built a Big Data Engineering services team and established a Data Science practice. Highly sought after for his deep expertise and interest in emerging trends, Alex routinely speaks at industry events as a member of the OakTable.

16 Comments. Leave new

Matthew Watson
June 4, 2009 2:49 am

Thats kind of what I was after, but specifically dynamically calling a private procedure from within a package. Unfortunately I haven’t been able to find a workable solution to my problem.

https://en.wikipedia.org/wiki/Reflection_(computer_science)

execute immediate is of course a fantastic option for hosing your your database :)

Reply

ok, you just made me fear the oracle power!

Now I want to see a procedure that dynamically creates it self.

Reply

Hi.

Without wanting to sound obvious, the big issue with dynamically calling a procedure is what happens if the procedure is not there? :)

People really need to think carefully about whether they actually need dynamic SQL in their production code. It’s a very good way of introducing runtime errors into your code. There is a warm and fuzzy feeling about no compile-time errors/warnings, but this means nothing if you are using dynamic SQL.

Obvious warning over… :)

Regarding calling a private procedure, that is what invoker rights is for. :)

Cheers

Tim…

Reply
Alex Gorbachev
June 4, 2009 6:09 am

I think Reflection approach is a sure way to make sure your code won’t be understood by future developers and make sure there are so many bugs that there is no way to fix them over the life-time of the program. :)

Reply

I think I have to go with Alex on this one. There is probably a better approach than dynamic calls and definitely a better approach than reflection. ugh. That just sounds like a nightmare in the long run.

LewisC

Reply

it can be used to run anonymous PL/SQL blog

As far as typos go, that was pretty entertaining. It could…

Reply
Alex Gorbachev
June 4, 2009 9:05 pm

Thanks for the feedback guys. I didn’t touch on twists with definer and invoker privileges but that’s another topic.

joel, LOL — that’s funny indeed. I won’t correct it and leave it as is — it’s too funny. :)

Reply
Log Buffer #149: a Carnival of the Vanities for DBAs | Pythian Group Blog
June 5, 2009 12:50 pm

[…] Here on the Pythian blog, Alex Gorbachev showed how to dynamically call a PL/SQL procedure. […]

Reply

Good discussion. One question is : what if the need to pass parameter to this dynamic procedure. Might be an issue here.

Reply
Alex Gorbachev
June 15, 2009 8:14 am

@plsql: Can you clarify potential issues? I don’t see any additional complications. I showed how to use that procedure. If you want, you can even make the wrapper more fine-tuned with additional parameters to be passed.

Reply
Olivier Mengué
June 30, 2009 11:49 am

There is an other issue: user rights.

PL/SQL procedures run with the rights of the user which own them instead of the rights of the user who call them.
This means that the call_dynamically() presented here may also be a way for a user to escape a sandbox to get higher privileges.

Reply
Olivier Mengué
June 30, 2009 11:52 am

@plsql: you can bind variables in the EXECUTE IMMEDIATE call. See the reference documentation about EXECUTE IMMEDIATE.

Reply
Alex Gorbachev
June 30, 2009 7:45 pm

@Oliver: re invoker vs definer rights – that’s what I was hinting at when used procedure to clean up. ;-)

Reply

Lots of comments that this should never be run in production.

Never covers a lot of territory, and there are surely exceptions.

For instance, consider the following scenario:

– Oracle Queues are used for different stages of processing incoming data
– There is a different procedure in a package for each business rule handled by a queue.
– The process is data driven. A table is used to store the ‘chain of command’.
The processes to run are fetched from the table, and run in that order.
The ‘call_dynamic()’ procedure is locked down in the sense that the only code to be run
is procedures in the same package.
The procedure name is passed, and verified with dbms_utility.name_resolve

The call_dynamic() procedure could even consider that driving table as a whitelist and verify
that the procedure exists in the package and in the table.

Many Languages have facilities to elegantly run such dynamic chains of code.

PL/SQL unfortunately, does not.

Reply

Almost 10 years later you got time to come back to it? :)
Your TOREAD list must be pretty long! :)

Reply

Wonderful explanation for a procedure, can you please give an example in which a function is dynamically calling a function. I am very confused and need some urgent help.

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *