views:

73

answers:

2

Let's say I have an ORACLE schema with contains a package. That package defines types, functions, procedures, etc:

CREATE PACKAGE...
  DECLARE 
  FUNCTION ...
  PROCEDURE ...
END;

Is there a query I can execute to get the definitions of those individual objects, without the wrapping package?

+4  A: 

If you need the procedures/functions of the package, you can use user_procedures:

Create Package package_test As
  Procedure dummy( x In Number );
  Function dummy2 Return Number;
End package_test;

Select object_name, procedure_name From user_procedures Where object_name = 'PACKAGE_TEST';

returns

PACKAGE_TEST    DUMMY
PACKAGE_TEST    DUMMY2
PACKAGE_TEST    

To get the parameters, select from user_arguments.


If you want the code for your packages/procedures/functions, use user_source for objects of your user, all_source for objects your user has grants for, and dba_source for all objects:

Select *
From user_source
Where name = 'YOUR_TEST'
And type = 'PROCEDURE';

If you created the procedure your_test before:

Create Procedure your_test As
Begin
  dbms_output.put_line('test');
End your_test;

it returns

YOUR_TEST  PROCEDURE  1  Procedure your_test As
YOUR_TEST  PROCEDURE  2  Begin
YOUR_TEST  PROCEDURE  3    dbms_output.put_line('test');
YOUR_TEST  PROCEDURE  4  End your_test; 
Peter Lang
Thank you Peter for your reply!I executed Select * From dba_source (I have the appropriate permissions), but I don't see my package nor my procedure.I'm new to ORACLE, so I might easily miss something here.I noticed that PL/SQL Developer puts an error mark on my package node in the left tree. Is this related to the problem I'm experiencing?Here's my package code:create package pgtest asprocedure p as begin null; end; end;
Yaakov Davis
You need to create a package `create package pgtest as procedure p; end;` and a package body `create package body pgtest as procedure p as begin null; end; end;`
René Nyffenegger
Ah Ha!I executed them separately, and now the node appears OK.But, still, no record in dba_source (or others).
Yaakov Davis
Yaakov Davis: Do you query for the package-name in uppercase? `Select * From dba_source Where name = 'PGTEST'`
Peter Lang
Yaakov Davis
That begs the question; Is there a way of getting ALL the sub-package objects definitions, without knowing their names in prior?
Yaakov Davis
@Yaakov Davis: I'm not sure if I understand your question, but if you want to get **all**, just omit the `WHERE` clause to get everything.
Peter Lang
Peter, when I omit the WHERE clause, my object's record disappears from the result set. Try to see yourself.
Yaakov Davis
@Yaakov Davis: That does not really make sense. `Select * From dba_source` should return you the source of all objects available. Have you tried `Select * From user_source´?
Peter Lang
Also, I see now that I'm still unable to get the definition of the procedure -by itself-.Executing SELECT * from dba_source WHERE name = 'PGTEST' returns package's definition, but when executing WHERE name ='p', I don't get the procedure's definition.
Yaakov Davis
Select * From user_source poses similar behavior (my objects are omitted).
Yaakov Davis
`WHERE name ='p'` cannot return anything, names are stored in uppercase. What kind of objects do you want to see (packages, procedures, ...)? And who owns them? Do you see them with `Select * From user_objects` ?
Peter Lang
I actually executed WHERE name ='P'; no appropriate result.I want to see the P proc previously defined as part of the PGTEST package (using the above scripts).Select * From user_objects doesn't return it.
Yaakov Davis
I'm logged-in as a SYS_DBA when creating the package. I hope this answers the owner question.
Yaakov Davis
Ok, now I think I finally understood what you want. You want the code of a single procedure which is defined within a package. This is not possible like that, only the whole source of the package can be retrieved using `user_source`. What do you need the source for, maybe there is another way?
Peter Lang
I'm building some kind of a management tool. I want to display the names do they resort to parsing?
Yaakov Davis
@Yaakov Davis: That's in the first part of my answer. Use `user_procedures` and `user_arguments` instead.
Peter Lang
Well, select * from user_procedures where object_name='P' doesn't return it..Am I missing something?
Yaakov Davis
`Select * From user_procedures Where object_name='PGTEST'`
Peter Lang
OK, great :)1. So now I can retrieve various information about procs inside a certain package. The only bit left: to get its code. Do you see other way of doing it, other than dba_source?2. When querying user_procedures without a WHERE clause, I don't see my proc. Any idea why is this so?
Yaakov Davis
**1.** I see no other way than to use `dba_source`, but you could try to ask another question (explaining exactly what you have so far and what you want). **2.** I can only imagine that you are getting too many records and that your client only shows you some?
Peter Lang
2. No, there's only ~30 records.Anyway, thanks for your help so far!I'll investigate more on this.
Yaakov Davis
+1  A: 

It is possible to retrieve the signatures of individual methods from the data dictionary. The relevant view is USER/ALL/DBA_ARGUMENTS.

There are a couple of snags to watch out for. If an argument has a postition of 0 it is the return value of a function not a parameter. If the parameter is a complex type (such as a nested table or PL/SQL record) it will appear multiple times, with each layer incrementing the data_level.

The following query joins arguments with their owning procedures. I am excluding the entries in USER_PROCEDURES at the package level (that is, subprogram_id=0) and the entries in USER_ARGUMENTS for the lower levels of complex_type (that is, data_level > 0). The query also handles procedures without any parameters.

SQL> select o.object_type
  2          , case
  3                when o.object_type in ( 'PACKAGE', 'TYPE') then p.object_name
  4                else null
  5            end as object_name
  6          , case
  7                when o.object_type in ( 'PACKAGE', 'TYPE') then p.procedure_name
  8                else p.object_name
  9            end as procedure_name
 10          , case
 11               when a.position != 0 then a.argument_name
 12               when a.position = 0 then '** return value **'
 13               else null
 14            end as argument_name
 15          , a.data_type
 16  from user_arguments a
 17       , user_procedures p
 18       , user_objects o
 19  where o.object_type in ( 'PACKAGE', 'TYPE', 'FUNCTION', 'PROCEDURE')
 20  and   p.object_name = o.object_name
 21  and   p.subprogram_id != 0
 22  and   a.object_id (+) = p.object_id
 23  and   a.subprogram_id (+) = p.subprogram_id
 24  and   a.data_level(+) = 0
 25  order by o.object_type, o.object_name, p.subprogram_id, a.position
 26  /

OBJECT_TYPE         OBJECT_NAME                    PROCEDURE_NAME                 ARGUMENT_NAME          DATA_TYPE
------------------- ------------------------------ ------------------------------ ------------------------------ -------
FUNCTION                                           COMPARE_OBJECTS                ** return value **     PL/SQL BOOLEAN
FUNCTION                                           COMPARE_OBJECTS                OBJ1                   UNDEFINED
FUNCTION                                           COMPARE_OBJECTS                OBJ2                   UNDEFINED
FUNCTION                                           GET_EMPS                       ** return value **     REF CURSOR
FUNCTION                                           GET_EMPS                       P_ARGS                 UNDEFINED
FUNCTION                                           STR_TO_NUMBER_TOKENS           ** return value **     TABLE
FUNCTION                                           STR_TO_NUMBER_TOKENS           P_STRING               VARCHAR2
FUNCTION                                           STR_TO_NUMBER_TOKENS           P_SEPARATOR            VARCHAR2
PACKAGE             P23                            POP_ARRAY                      ** return value **     TABLE
PACKAGE             P23                            POP_ARRAY                      P_NO                   NUMBER
PACKAGE             P23                            INS_TABLE                      P_ARRAY                TABLE
PROCEDURE                                          CHANGE_EMP_SAL                 P_ENO                  NUMBER
PROCEDURE                                          CHANGE_EMP_SAL                 P_NEW_SAL              NUMBER
PROCEDURE                                          PRINTE
TYPE                NEW_EMP                        EQUALS                         ** return value **     RAW
TYPE                NEW_EMP                        EQUALS                         SELF                   OBJECT

22 rows selected.

SQL>

I could have selected other useful information from USER_ARGUMENTS such as IN_OUT or whether the parameter is DEFAULTED, but I figured it scrolled enough already.

APC
Looks interesting, but for some strange reason, I don't see my proc in the result set.
Yaakov Davis
@Yaakov Davis: If you select from `user_source`, you only see objects that are owned by your current user. If you do it as `sys`-user, you only get packages that have been created in `sys`-schema. Have you checked this?
Peter Lang
@YaakovDavis: without seeing your data it is difficult to be sure. However, I have used the USER versdion of the views, which restricts the query to the current schema's objects. You can replace those views with the ALL_ or DBA_ equivalents, but you would also want to restrict on the basis of OWNER otherwise you'll be swept away by a tsunami of results.
APC
Giving this approach a 2nd thought, I believe it wouldn't work on parameterless func/procs.Peter, I tried connecting as a NORMAL user, no change.
Yaakov Davis
@YaakovDavis - actually it *does* handle parameterless procedures. The join on USER_ARGUMENTS is an outer join. If you scroll down the posted result set, lo! you will see an entry for a procedure PRINTE, which indeed has no paramaters.
APC
APC, you're correct. After playing with it, I do see all the package procedures.Thanks for your help.
Yaakov Davis