Discover PL/SQL package-level types using Oracle dictionary views
Can I discover types declared in Oracle PL/SQL packages using开发者_Python百科 dictionary views? I.e. when I declare this:
CREATE OR REPLACE PACKAGE my_types AS
TYPE t_cursor_type IS REF CURSOR;
TYPE t_table_type IS TABLE OF some_table%rowtype;
END my_types;
I'd like to formally discover t_cursor_type
and t_table_type
. They don't seem to be listed in
SYS.ALL_TYPES
By "formally" I mean I'd like some "formal meta-data", i.e. querying USER_SOURCE
won't do the trick.
Only from the 11.1 onward.
From the manual:
http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17125/adfns_plscope.htm#ADFNS02204
http://download.oracle.com/docs/cd/E11882_01/server.112/e17110/initparams189.htm#REFRN10271
PL/Scope is a compiler-driven tool that collects data about identifiers in PL/SQL source code at program-unit compilation time and makes it available in static data dictionary views. The collected data includes information about identifier types, usages (declaration, definition, reference, call, assignment) and the location of each usage in the source code.
DEMO
CREATE OR REPLACE PACKAGE my_types AS
TYPE t_cursor_type IS REF CURSOR;
TYPE t_table_type IS TABLE OF employees%rowtype;
type t_associative is table number index by varchar2(20);
END my_types;
alter package my_types compile plscope_settings='IDENTIFIERS:ALL' reuse settings;
select *
from user_identifiers ui
where ui.object_type = 'PACKAGE'
and ui.usage = 'DECLARATION'
and ui.usage_context_id = '1';
NAME SIGNATURE TYPE OBJECT_NAME OBJECT_TYPE USAGE USAGE_ID LINE COL USAGE_CONTEXT_ID
------------------------------ -------------------------------- ------------------ ------------------------------ ------------- ----------- ---------- ---------- ---------- ----------------
T_ASSOCIATIVE 9A18FE6BCB72110F39CED9E08B932ECB ASSOCIATIVE ARRAY MY_TYPES PACKAGE DECLARATION 4 4 8 1
T_TABLE_TYPE 77067FE9732B492C166D38221DC3DF37 NESTED TABLE MY_TYPES PACKAGE DECLARATION 3 3 8 1
T_CURSOR_TYPE EDEC9260784B7721BC3F3DAB293F23DD REFCURSOR MY_TYPES PACKAGE DECLARATION 2 2 8 1
zep@dev>
EDIT: From documentation found by Zep, statement only applies oracle versions prior to 11.1
The bad news for you:
Those types only exist upon execution of the package, so they would never be seen in the oracle dictionary. In other words, those types are not in the database, rather they are in the package.
The good new for you:
The package is in the data dictionary so we could run some sql to search procedures and packages that contain the keywords you care about; in this example 'TYPE':
SELECT *
FROM dba_source
WHERE type IN ('PROCEDURE','PACKAGE','PACKAGE BODY')
AND text LIKE '%TYPE%IS%';
From there define the owner you care about and the do some regex or other fancy code to pull the data you need.
Alternatively, if you want to see the types in the data dictionary you would have to create them outside the package and then reference that type from the package.
References:
Oracle® Database Reference 11g Release 1 (11.1) - ALL_TYPES
Complex solution that works without any special compilation flags
Here's a solution that I've devised for the jOOQ code generator in version 3.9 to discover PL/SQL RECORD
types. It only discovers those types that are actually referenced:
SELECT x.type_owner, x.type_name, x.type_subname, a.*
FROM all_arguments a
JOIN (
SELECT
type_owner, type_name, type_subname,
MIN(owner ) KEEP (DENSE_RANK FIRST ORDER BY owner, package_name, subprogram_id, sequence) owner,
MIN(package_name ) KEEP (DENSE_RANK FIRST ORDER BY owner, package_name, subprogram_id, sequence) package_name,
MIN(subprogram_id) KEEP (DENSE_RANK FIRST ORDER BY owner, package_name, subprogram_id, sequence) subprogram_id,
MIN(sequence ) KEEP (DENSE_RANK FIRST ORDER BY owner, package_name, subprogram_id, sequence) sequence,
MIN(next_sibling ) KEEP (DENSE_RANK FIRST ORDER BY owner, package_name, subprogram_id, sequence) next_sibling,
MIN(data_level ) KEEP (DENSE_RANK FIRST ORDER BY owner, package_name, subprogram_id, sequence) data_level
FROM (
SELECT
LEAD(sequence, 1, sequence) OVER (
PARTITION BY owner, package_name, subprogram_id, data_level
ORDER BY sequence
) next_sibling,
a.type_owner,
a.type_name,
a.type_subname,
a.owner,
a.package_name,
a.subprogram_id,
a.sequence,
a.data_level,
a.data_type
FROM all_arguments a
) a
WHERE data_type = 'PL/SQL RECORD'
GROUP BY type_owner, type_name, type_subname
) x
ON (a.owner, a.package_name, a.subprogram_id)
= ((x.owner, x.package_name, x.subprogram_id))
AND a.sequence BETWEEN x.sequence AND x.next_sibling
AND a.data_level = x.data_level + 1
ORDER BY x.type_owner, x.type_name, x.type_subname, a.sequence
;
More details about the above technique can be found here.
Relatively easy (but incomplete) solution that depends on a special compilation flag
I've just discovered this extremely interesting website, which lists a query that uses the dictionary views mentioned in zep's answer here. Using the package from the question, use this query:
WITH plscope_hierarchy
AS (SELECT line
, col
, name
, TYPE
, usage
, usage_id
, usage_context_id
FROM all_identifiers
WHERE owner = USER
AND object_name = 'MY_TYPES'
AND object_type = 'PACKAGE')
SELECT LPAD (' ', 3 * (LEVEL - 1))
|| TYPE
|| ' '
|| name
|| ' ('
|| usage
|| ')'
identifier_hierarchy
FROM plscope_hierarchy
START WITH usage_context_id = 0
CONNECT BY PRIOR usage_id = usage_context_id
ORDER SIBLINGS BY line, col;
Yielding this result
PACKAGE MY_TYPES (DECLARATION)
REFCURSOR T_CURSOR_TYPE (DECLARATION)
NESTED TABLE T_TABLE_TYPE (DECLARATION)
Unfortunately, the nested table type is not resolved any further.
It won't be available from all_types
or all_objects
but as an alternative you can query user_source
for the name of the type, and it should show up.
Nowadays (18c+ IIRC) there are all_plsq_*
views that do the job. For record types see user_plsql_types
and all_plsql_type_attrs
.
Try to use collection as an argument of package function/procedurę and next see into dictionary user_arguments:
select *
from user_arguments a
where a.object_name = 'MYFUNCTIONNAME'
order by a.sequence;
精彩评论