Skip to Main Content
  • Questions
  • Finding certaing string into PL/SQL stored procedures

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Ulises.

Asked: August 09, 2013 - 2:54 am UTC

Last updated: August 13, 2013 - 7:23 pm UTC

Version: 11.2.0

Viewed 10K+ times! This question is

You Asked

I want to find PL/SQL stored procedures into my database, which have the text: DELETE FROM MyTable WHERE username='SCOTT'

How could I do that?

Regards,

and Tom said...

it is not as easy as it sounds since there could be white space, newlines, etc.

You'd have to reformat the text, glue a few lines of code together, and use like.

something similar to:

ops$tkyte%ORA11GR2> create or replace procedure foo
  2  as
  3  begin
  4          delete
  5          from
  6          t
  7          where
  8          username = 'SCOTT';
  9  end;
 10  /

Procedure created.

ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> variable x varchar2(80)
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> exec :x := q'|DELETEFROMTWHEREUSERNAME='SCOTT'|'

PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> select name, type, line,
  2         substr( big_txt, instr( big_txt, :x ), 40 ) || '...' snippet
  3    from (
  4  select name, type, line,
  5         lag(txt,3) over (partition by name, type order by line) ||
  6         lag(txt,2) over (partition by name, type order by line) ||
  7         lag(txt,1) over (partition by name, type order by line) ||
  8             txt ||
  9         lead(txt,1) over (partition by name, type order by line) ||
 10         lead(txt,2) over (partition by name, type order by line) ||
 11         lead(txt,3) over (partition by name, type order by line) big_txt
 12    from (
 13  select name, type, line,
 14         upper(replace( replace( replace( translate( text, chr(13)||chr(10)||chr(9), '   ' ), ' ', ' ~'), '~ ', ''), ' ~', '')) txt
 15    from user_source
 16         )
 17             )
 18   where instr( big_txt, :x ) > 0
 19  /

NAME                           TYPE               LINE SNIPPET
------------------------------ ------------ ---------- -------------------------------------------
FOO                            PROCEDURE             5 DELETEFROMTWHEREUSERNAME='SCOTT';...
FOO                            PROCEDURE             6 DELETEFROMTWHEREUSERNAME='SCOTT';END;...
FOO                            PROCEDURE             7 DELETEFROMTWHEREUSERNAME='SCOTT';END;...




i turn whitespace (end of line, tabs - anything else you can think of) into a space, turn multiple spaces into "nothing" and upper case the string.

using lag and lead - we concatenate the prior and latter three lines into one - to pick up anything that spans up to seven lines.

then we look for instr's - yes, you'll get multiple hits - but it would see ok to do that since you are just scanning.


you could further refine this to add a where clause on user dependencies to search only code that COULD have a delete if you like...

Rating

  (2 ratings)

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

Comments

ORA-01489: result of string concatenation is too long

Ulises Vazquez, August 13, 2013 - 3:13 am UTC


1. I executed it in my real database with the real string to search and I got an error.

2. I created the scenario same to you and I got the same error:

SQL> create or replace procedure foo
  2  as
  3  begin
  4  delete 
  5  from 
  6  t
  7  where   
  8  username='SCOTT';
  9  end;
 10  /

Advertencia: Procedimiento creado con errores de compilacion.


SQL> variable x varchar2(80)
SQL> exec :x := q'|DELETEFROMTWHEREUSERNAME='SCOTT'|'

Procedimiento PL/SQL terminado correctamente.

SQL> select name, type, line,
  2         substr( big_txt, instr( big_txt, :x ), 40 ) || '...' snippet
  3  from (
     select name, type, line,
     lag(txt,3) over (partition by name, type order by line) ||
     lag(txt,2) over (partition by name, type order by line) ||
     lag(txt,1) over (partition by name, type order by line) ||
     txt ||
     lead(txt,1) over (partition by name, type order by line) ||
  4    5    6    7    8    9   10       lead(txt,2) over (partition by name, type order by line) ||
     lead(txt,3) over (partition by name, type order by line) big_txt
     from (
          select name, type, line,
          upper(replace( replace( replace( translate( text, 
          chr(13)||chr(10)||chr(9), '   ' ), ' ', ' ~'), '~ ', ''), ' ~', '')) txt
from user_source
         )
 11   12   13   14   15   16   17   18           )
where instr( big_txt, :x ) > 0 19  ;
from user_source
     *
ERROR en linea 16:
ORA-01489: el resultado de la concatenacion de cadena de caracteres es
demasiado largo

Tom Kyte
August 13, 2013 - 7:09 pm UTC

1) then you have some really - what I would call - 'bad' code.

that means the result of concatenating seven lines of code EXCEEDS 4000 bytes!!!!!!!!

that means the average width of a line of code was 571 bytes!!!

a line of code over 500 bytes?!?!?!!?

seriously?

just drop the lag/lead of 3 rows back and forwards - just do five lines.


and talk to your developers - having seven lines of code that exceed 4000 bytes is really "not good"

@Ulises Vazquez

Steve, August 13, 2013 - 2:21 pm UTC

Ulises, what was the error after creating procedure foo? Did you resolve that or just kept going?
Tom Kyte
August 13, 2013 - 7:23 pm UTC

probably, they did not have a table T or if they did - it did not have a username column.


however, it doesn't matter, it means they have some other procedure with *really long lines of code*.


More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.