You need to grant the REFERENCES
privilege on the reference table to user2
.
(See GRANT, Table Privileges section. Note that this cannot be granted to a role, must be granted to the user directly.)
Here's a demo:
SQL> create user user1 identified by user1;
User created.
SQL> grant create session, create table, unlimited tablespace to user1;
Grant succeeded.
SQL> create user user2 identified by user2;
User created.
SQL> grant create session, create table, unlimited tablespace to user2;
Grant succeeded.
SQL> create table user1.ref_table (id number primary key);
Table created.
SQL> insert into user1.ref_table values (1);
1 row created.
SQL> insert into user1.ref_table values (2);
1 row created.
SQL> commit;
Commit complete.
SQL> grant references on user1.ref_table to user2;
Grant succeeded.
SQL> connect user2/user2;
Connected.
SQL> create table oth_table (thing number, fk number);
Table created.
SQL> alter table oth_table add(constraint fk1 foreign key (fk)
2 references user1.ref_table on delete set null);
Table altered.
SQL> insert into oth_table values (42, 1);
1 row created.
SQL> insert into oth_table values (256, 2);
1 row created.
SQL> commit;
Commit complete.
SQL> connect user1/user1;
Connected.
SQL> delete from ref_table where id = 1;
1 row deleted.
SQL> commit;
Commit complete.
SQL> connect user2/user2;
Connected.
SQL> select * from oth_table;
THING FK
---------- ----------
42
256 2
If you want admin
to do all the work, it'll need the CREATE ANY INDEX
privilege, and you still need the REFERENCES
grant to user2
.
Here's how that could work:
SQL> create user user1 identified by user1;
User created.
SQL> create user user2 identified by user2;
User created.
SQL> create user admin identified by admin;
User created.
--- Grants
----------------
SQL> grant create session, create table, unlimited tablespace to user1;
Grant succeeded.
SQL> grant create session, create table, unlimited tablespace to user2;
Grant succeeded.
SQL> grant create session, create any table,
2 create any index, alter any table to admin;
Grant succeeded.
--- Create reference table as admin
----------------
SQL> connect admin/admin
Connected.
SQL> create table user1.ref_table (id number primary key);
Table created.
--- Do the "references" grant
----------------
SQL> connect / as sysdba
Connected.
SQL> grant references on user1.ref_table to user2;
Grant succeeded.
--- Create the second table as admin
----------------
SQL> connect admin/admin
Connected.
SQL> create table user2.oth_table (foo number, bar number);
Table created.
--- Add the constraint
----------------
SQL> alter table user2.oth_table add(constraint fk
2 foreign key (bar) references user1.ref_table(id)
3 on delete set null);
Table altered.
Short answer: CREATE TABLE
must be explictly granted to the object owner for DBMS_DATAPUMP
to be called from within a package or stored procedure.
Long Answer:
In an effort to solve this question, I interrogated the data dictionary to get all of the object and system privileges granted by the IMP_FULL_DATABASE
and EXP_FULL_DATABASE
roles (and all roles assigned to those two roles). Attempting to explicitly grant all 2683 privileges resulted in 2566 failures, but the package was able to call DBMS_DATAPUMP
successfully.
The question then became: which of the remaining 117 privileges are actually needed for DBMS_DATAPUMP
? I then grouped the remaining privileges and revoked them one group at a time (I assumed that it was a group of related permissions that would ultimately be needed). After running through nearly all of the groups, only the set of CREATE ANY
privileges remained. When I revoked that group, the package stopped working. I then granted each of those permissions, calling the package after each grant. It was finally CREATE ANY TABLE
that restored functionality to the package. A little further tinkering determined that CREATE TABLE
is, in fact, sufficient to call DBMS_DATAPUMP
from within a package.
CREATE TABLE
is the only permission that I've found needs to be granted for the functionality found in the procedure shown in the question. Other procedures/datapump settings may require additional privileges. dbms_datapump.create_job_view
, for instance, requires CREATE VIEW
. In that case, the error message when the privilege is missing is, more reasonably, ORA-01031: insufficient privileges
.
Best Answer
If the privilege has been granted directly or to a role, the grant will appear in
DBA_TAB_PRIVS
If the
grantee
is a role, you would then need to look atdba_role_privs
to see what users (or roles) have been granted that role and follow the chain if you have roles granted to other roles. If you need to account for users that have grants because of the (very dangerous)ANY
grants (i.e.EXECUTE ANY PROCEDURE
), that would require a separate query.If you want to get more sophisticated than simply doing a straight query against
dba_tab_privs
, though, you are probably better off using on of Pete Finnigan's scripts like thewho_has_priv.sql
(orwho_has_priv_procedure.sql
). Pete is probably the leading expert on Oracle security so these are much more likely to account for every possible corner case than anything I would attempt to cobble together.