3

I am working on a application which is used to get ddl of an Oracle database object.

Using following query to get objects of the database

SELECT object_name, object_type  
FROM dba_objects 
where owner = '" + alternative_schema + "' 
order by object_type, object_name;

Using following query to get ddl of the db object

SELECT DBMS_METADATA.GET_DDL('TABLE','" + tableName + "','" + alternative_schema + "') 
FROM dual;

and It is working fine.

To execute above queries oracle user need following grants

GRANT SELECT_CATALOG_ROLE TO john;
GRANT SELECT ANY TABLE TO john;

Now due to some security issue, dba is not allowing to grant SELECT_CATALOG_ROLE and as my research says that with the SELECT_CATALOG_ROLE its not possible.

But someone suggest to do it by 'sys'.

So now I can list of all objects by following query

select * 
from sys.all_tables 
where owner ='mydb'

Its returning all the created object under the mydb schema.

But my next challenge is to get ddl

How can I get ddl without having SELECT_CATALOG_ROLE?

Is it possible by any way to execute DBMS_METADATA.GET_DDL without granting SELECT_CATALOG_ROLE?

Update: according to the link oracle Security Model

Nonprivileged users can see the metadata of only their own objects.

So owner does not need to have "SELECT_CATALOG_ROLE" permission to get_ddl()

and my user is readOnly type of user, I need to final solution to getDDL from readonly user (non-owner) account, which should not have SELECT_CATALOG_ROLE

Tej Kiran
  • 2,218
  • 5
  • 21
  • 42
  • As far as I can tell, you do need `select_catalog_role`. `sys` you mentioned is irrelevant here, as you're selecting from `all_tables` which is accessible to you anyway (it contains all objects you have access to). "sys" just says who owns it, but it doesn't really matter in this case. – Littlefoot Jun 20 '18 at 06:37
  • Thanks @Littlefoot. Actually due to security requirement where dba cannot let us have select privileges on DBA_OBJECTS table in Oracle databases. So we can not use DBA_OBJECTS. So can we do it any alternative way by which this happen or it is not possible means I have to grant CATALOG_ROLE to get DDL. – Tej Kiran Jun 20 '18 at 06:45
  • 4
    If you have to do that job (because someone (boss?) told you that) but can't because you don't have required privileges, you'll have to talk to that *boss* person, explain what's going on and see the outcome. Either you'll get the privilege (and do it), or you wont' get it (and wont' do it). – Littlefoot Jun 20 '18 at 06:48
  • Thank you @Littlefoot for your feedback – Tej Kiran Jun 20 '18 at 06:50
  • You're welcome. Good luck! – Littlefoot Jun 20 '18 at 06:52
  • Tej, is `alternative_schema` the same as the user you are connecting with? That is important for USER_/ALL_/DBA_OBJECTS... – wolφi Jun 20 '18 at 07:01
  • From what I know, the other option left would be to select from `all_tables`, `all_constraints` `all_indexes` `all_tab_partitions` etc. But, I would agree with Littlefoot's option, which is much better. – Kaushik Nayak Jun 20 '18 at 07:03
  • Is connecting as the object owner not an option? Or getting a wrapper procedure created under that schema as a one-off, or even under a priveleged schema with suitable access restrictions if this has to get DDL across multiple owners? You'd still need DBA support for that of course. – Alex Poole Jun 20 '18 at 07:31
  • Will the DBA give you an export of the database (can be metadata-only), or of the schemas you are interested in? – Alex Poole Jun 20 '18 at 07:57
  • @TejKiran - regarding your latest update; [you can't](https://stackoverflow.com/a/26026495/266304). That's Oracle's security model. You have to connect as the owner, or connect as a privileged user that has that role, or have that role granted to you; or have a wrapper proc in a priv schema you can call; or work from an export. There is no magic answer. Talk again to your DBA and whoever gave you this task. – Alex Poole Jun 20 '18 at 13:48
  • What is the purpose of the exercise? Why do you need to generate the DDL? – APC Jun 21 '18 at 05:59

3 Answers3

2

The only scenario in which we need to run DBMS_METADATA.GET_DDL() is when we're working with a database whose schemas are not under proper source control. This is a bad situation and one which a DBA ought to want to improve.

So, you need to get the DBA on your side. This should be easy if the purpose of your request is to get the database into source control, that is, this is a one-off exercise and safe development practices are being put in place to ensure that all future changes to the database will be tracked under source control.

Suggested approach: work on a database which is not Production but has the same data structures as Production. This should be an easier sell than asking for privilege escalation in Production.

Ideally it should be already available (UAT, Pre-prod environment) but if you need to use DBMS_METADATA.GET_DDL() maybe you're working without such an environment. In which case you need the DBA to create a new database for you.


@AlexPoole makes a good suggestion. You can generate source files using a metadata export through Data Pump with the sqlfile option. Find out more.

APC
  • 144,005
  • 19
  • 170
  • 281
  • 1
    If it isn't under source control there's a reasonable chance that UAT/pre-production won't match production anyway, so getting a new DB as a clone of production might be safer. (But then getting a metadata-only export and using `sqlfile` to get the DDL might be just as good?) – Alex Poole Jun 20 '18 at 07:57
  • I can't request to make a same data structures as production. – Tej Kiran Jun 20 '18 at 12:51
0

Yes, it its possible to extract the DDL for an object from the data dictionary views, but it is nearly impossible to write code that is complete or correct or both.

Oracle's security concept has three basic roles:

1) The owner of the schema: You can do anything you want with your tables/views/objects without any permisssions, even execute DBMS_METADATA. You use the data dictionary views starting with USER_ like USER_TABLES, USER_TAB_COLUMNS etc.

2) An "application user" or somebody with a few privileges on other schema objects. You use the data dictionary views that start with ALL_ like ALL_TABLES, ALL_TAB_COLUMNS. Which other objects appear in your views, depend on many things, for instance select privs on tables. But frankly, nobody knows the full list (just ask in a job interview which Grants you need to see or change a materialized view in another schema)

3) A DBA. He/she can see and change all other objects in all schemas. You use the data dictionary views starting with DBA_ like DBA_TABLES, DBA_TAB_COLUMNS etc. Some newer packages run with a subset of DBA privileges like SELECT_CATALOG_ROLE in your example.

There is reason to believe that DBMS_METADATA was written for Oracle's export/import datapump product, which needs to see all objects and falls therefore in category 3)

So, you have three options to solve your task.

1) Go along route 1. Write a stored procedure in PL/SQL as the owner of the tables, use DBMS_METADATA to get the DDL and do what ever you need to do. This procedure can be granted to other users.

2) Go along route 2. Use the views ALL_ to extract a little bit of DDL. Be aware that there are 365 of those views in Oracle 11.2.

3) Go along route 3. Talk to your DBA, get them involved. Maybe they grant you the SELECT_CATALOG_ROLE on a dev database. Maybe they can contribute to the script / program and will execute it themselves.

wolφi
  • 8,091
  • 2
  • 35
  • 64
0

First of all thanks to all for all suggestions. I got the solution for my scenario, according to the linkenter link description here

Nonprivileged users can see the metadata of only their own objects.

So owner does not need to have "SELECT_CATALOG_ROLE" permission to get_ddl(). and my requirement is to get ddl from the user which should not have "SELECT_CATALOG_ROLE" permission. So one solution is that if a function is created under the owner account which internally execute dbma_metadata.get_ddl() and return ddl string and if we grant select/execute permission of the new method to the user (Non-Owner) then she can get ddl without having "SELECT_CATALOG_ROLE" from out side the owner account.

create function get_ddl( i_owner in varchar2, i_name in varchar2, i_type in varchar2)
    return clob
is
begin
    dbms_output.put_line('Listing active session roles...');
    for r_role in (select role from sys.session_roles) loop
        dbms_output.put_line('Role : '||r_role.role);
    end loop;
    dbms_output.put_line('Roles listed');
    dbms_output.put_line('Userid is : '||sys_context('userenv', 'current_userid'));
    return dbms_metadata.get_ddl( schema => i_owner, name => i_name, object_type => i_type);
end;

Call this method from other user (non-owner). By this readonly user will have only access of getDDL() to get definition. But do not have other permission will be granted to readonly user.

Tej Kiran
  • 2,218
  • 5
  • 21
  • 42