Skip to Main Content
  • Questions
  • DBMS_METADATA does not work inside a function

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Mauro.

Asked: February 07, 2022 - 7:10 am UTC

Last updated: February 28, 2022 - 6:50 am UTC

Version: 11.2.0.4

Viewed 10K+ times! This question is

You Asked

I am trying to use DBMS_METADATA in a function but it does not work, only in direct SQL.
I was unable to find anything in the docs, just that SELECT_CATALOG_ROLE privilege is needed ( but of course my user has it ).
I know that privileges inside Pl/Sql are not the same as Sql but I cannot understand why this package cannot be used inside a function, it returns ORA-31603.
I tried to give this user every possible privilege ( directly, not through a role), no luck.
I even gave every privilege of SELECT_CATALOG_ROLE directly, well aware that privileges from roles are not active in Pl/Sql.

This is my code:

create or replace function scott.Get_Source ( Package_Name varchar2 ) return clob is
begin
     return DBMS_METADATA.GET_DDL ('PACKAGE', Package_Name, 'USER1' );
end;
/


where USER1 is the owner of the package
( in the final version it was supposed to be another input variable )

The only user with this is working is sys, I tried just for sake of curiosity, in a test db of course, but I strongly dislike the idea of messing with sys, even for a an innocent and simple function.
What am I missing?
If really DBMS_METADATA is designed for being used only in sql it should at least be documented

Best regards

Mauro

and Connor said...

From the docs:

"The DBMS_METADATA package considers a privileged user to be one who is connected as user SYS or who has the SELECT_CATALOG_ROLE role. In stored procedures, functions, and definers-rights packages, roles (such as SELECT_CATALOG_ROLE) are disabled. Therefore, such a PL/SQL program can only fetch metadata for objects in its own schema. If you want to write a PL/SQL program that fetches metadata for objects in a different schema (based on the invoker's possession of SELECT_CATALOG_ROLE), you must make the program invokers-rights."

SQL> create or replace
  2  procedure p11(p_user varchar2) is
  3    x clob;
  4  begin
  5    x := dbms_metadata.get_ddl('TABLE','EMP',p_user);
  6  end;
  7  /

Procedure created.

SQL>
SQL> exec p11(user)

PL/SQL procedure successfully completed.

SQL> exec p11('SCOTT')
BEGIN p11('SCOTT'); END;

*
ERROR at line 1:
ORA-31603: object "EMP" of type TABLE not found in schema "SCOTT"
ORA-06512: at "SYS.DBMS_METADATA", line 6731
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 105
ORA-06512: at "SYS.DBMS_METADATA", line 2588
ORA-06512: at "SYS.DBMS_METADATA", line 2827
ORA-06512: at "SYS.DBMS_METADATA", line 3608
ORA-06512: at "SYS.DBMS_METADATA", line 5008
ORA-06512: at "SYS.DBMS_METADATA", line 5336
ORA-06512: at "SYS.DBMS_METADATA", line 6702
ORA-06512: at "SYS.DBMS_METADATA", line 9734
ORA-06512: at "MCDONAC.P11", line 4
ORA-06512: at line 1


SQL> desc scott.emp
 Name                                                                    Null?    Type
 ----------------------------------------------------------------------- -------- ----------------
-------
 EMPNO                                                                   NOT NULL NUMBER(4)
 ENAME                                                                            VARCHAR2(10)
 JOB                                                                              VARCHAR2(9)
 MGR                                                                              NUMBER(4)
 HIREDATE                                                                         DATE
 SAL                                                                              NUMBER(7,2)
 COMM                                                                             NUMBER(7,2)
 DEPTNO                                                                           NUMBER(2)

SQL> create or replace
  2  procedure p11(p_user varchar2) authid current_user is
  3    x clob;
  4  begin
  5    x := dbms_metadata.get_ddl('TABLE','EMP',p_user);
  6  end;
  7  /

Procedure created.

SQL> exec p11(user)

PL/SQL procedure successfully completed.

SQL> exec p11('SCOTT')

PL/SQL procedure successfully completed.




Rating

  (4 ratings)

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

Comments

True but it is not the point, alas ...

Mauro, February 10, 2022 - 9:58 am UTC

Unfortunately, using authid current_user does not resolve my problem.
Perhaps a few more words may help.
I have several couples of users, such as let me say SCOTT ( owner of data ) and SCOTT_RW which has only usage permissions on SCOTT's schema.
People are allowed to use only SCOTT_RW, so they can read, write and execute code belonging to SCOTT but of course SCOTT_RW is not allowed to see the code source ( otherwise it could just call DBMS_METADATA directly, no need for a special funcion ).
So my idea was to create this function in a privileged user ( let us call SCOTTDBA ) with public execute and a public synonym ( of course with all the checks so that a specific RW user is allowed to see only the right owner code ).
Well, SCOTTDBA can use DBMS_METADATA directly but it does not work in a function.
I tried to give SCOTTDBA each and every privilege but nothing worked.
The only way I found is to create that function in the SYS schema, which I do not like at all ( even if it is a harmless function ), but perhaps there is some other way ...
Regards
Mauro
PS I do hope to be clearer this time, sorry for my poor English

Connor McDonald
February 11, 2022 - 4:41 am UTC

Going back to the docs:

"The DBMS_METADATA package considers a privileged user to be one who is connected as user SYS or who has the SELECT_CATALOG_ROLE role"

Notice that it does not say "we need the privs associated with the SELECT_CATALOG_ROLE " it says "you need the *actual role* SELECT_CATALOG_ROLE"

Because roles are not enabled via PLSQL, then without authid current user then that pretty much leaves SYS.

Thanks

Mauro, February 11, 2022 - 9:55 am UTC

You are quite right, it is the presence of the SELECT_CATALOG_ROLE that really matters.
It is surprising to see such a usage for a role.
Just for sake of curiosity, I created a test db, I dropped SELECT_CATALOG_ROLE and I recreated it empty: it works ( of course only in sql ).
I mean, just the presence of that role, not the privileges included, is considered.
This is kind of unusual way to use a role I think.
Thank you again, at least now I have a clear picture.
Have a nice weekend
Mauro

Connor McDonald
February 14, 2022 - 1:46 am UTC

I agree its odd - presumably its a security related thing

Why clob data type only

A reader, February 27, 2022 - 3:24 am UTC

Why you are using CLOB(x clob) data type only? Is there any specific reason.
Connor McDonald
February 28, 2022 - 6:50 am UTC

As opposed to?

Thanks....

Rajeshwaran Jeyabal, March 01, 2022 - 12:07 pm UTC

Thanks...but when you say "...Going back to the docs:...." why dont you put the link to the docs there? it would be easy for others to go into that link and see where it really exists and even what else was mentioned there...

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