Execute Immediate fails even with CREATE table grant - oracle

I have a problem where I am creating a table using the execute immediate command in the stored procedure. However I get the error of "insufficient privileges". I checked other threads and made sure that the user has "CREATE TABLE" privilege granted to it. However I still keep seeing the same error.
SQL> select * from USER_SYS_PRIVS;
USERNAME PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
MYUSER CREATE VIEW NO
MYUSER UNLIMITED TABLESPACE NO
SQL> select * from session_privs;
PRIVILEGE
----------------------------------------
CREATE SESSION
UNLIMITED TABLESPACE
CREATE TABLE
CREATE CLUSTER
CREATE VIEW
CREATE SEQUENCE
CREATE PROCEDURE
CREATE TRIGGER
CREATE TYPE
CREATE OPERATOR
CREATE INDEXTYPE
11 rows selected.
The Dummy procedure I created is :
create or replace procedure sp_dummy
as
begin
execute immediate 'Create table Dummy99_99 (Dummy_Field number)';
end sp_dummy;
/
Detailed error :
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "MYUSER.SP_DUMMY", line 4
ORA-06512: at line 1
Is there something wrong I am doing ?

You only have create view granted directly to your user. The other system privileges you can see are coming from a role, and roles are disabled in definer's-rights stored procedures. Look in user_role_privs to see while roles you've been granted, and you can see which privileges each role gives you in role_sys_privs (with the role name as the grantee). There could be several layers of roles too.
You would see the same error if you did set role none before trying to create a table statically. Demo with minimal set-up:
create role myrole;
grant create session, create table, create procedure to myrole;
create user myuser identified by mypasswd;
grant myrole to myuser;
grant create view, unlimited tablespace to myuser;
Then as that user:
SQL> connect myuser/mypasswd
Connected.
SQL> select * from user_sys_privs;
USERNAME PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
MYUSER UNLIMITED TABLESPACE NO
MYUSER CREATE VIEW NO
2 rows selected.
SQL> select * from session_privs;
PRIVILEGE
----------------------------------------
CREATE SESSION
UNLIMITED TABLESPACE
CREATE TABLE
CREATE VIEW
CREATE PROCEDURE
5 rows selected.
SQL> Create table Dummy99_99 (Dummy_Field number);
Table created.
SQL> drop table Dummy99_99 purge;
Table dropped.
SQL> set role none;
Role set.
SQL> Create table Dummy99_99 (Dummy_Field number);
Create table Dummy99_99 (Dummy_Field number)
*
ERROR at line 1:
ORA-01031: insufficient privileges
And with your stored procedure version:
SQL> connect myuser/mypasswd
Connected.
SQL> create or replace procedure sp_dummy
2 as
3 begin
4 execute immediate 'Create table Dummy99_99 (Dummy_Field number)';
5 end sp_dummy;
6 /
Procedure created.
SQL> exec sp_dummy;
BEGIN sp_dummy; END;
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "MYUSER.SP_DUMMY", line 4
ORA-06512: at line 1
To be able to create the table dynamically from a stored procedure, your DBA will need to grant create table directly to your user:
grant create table to myuser;
Then trying the procedure again:
SQL> connect myuser/mypasswd
Connected.
SQL> select * from user_sys_privs;
USERNAME PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
MYUSER UNLIMITED TABLESPACE NO
MYUSER CREATE TABLE NO
MYUSER CREATE VIEW NO
SQL> exec sp_dummy;
PL/SQL procedure successfully completed.
SQL> desc Dummy99_99
Name Null? Type
----------------------------------------- -------- ----------------------------
DUMMY_FIELD NUMBER
Notice that user_sys_privs now shows that create table has been granted directly, which it didn't before, or in the question.
However, it is very unlikely you would ever really want to create objects dynamically, as the schema should be well defined and stable - changes of this type should be controlled and be part of a release process. But as an exercise, you need the direct grant.

When using execute immediate, procedure must explicitly tell oracle that it must run with privileges of a particular user.
AUTHID CURRENT_USER, to use the privileges of user running the procedure.
AUTHID DEFINER, to use the privileges of owner of the procedure.
This is done using AUTHID option while creating a procedure.
CREATE OR REPLACE PROCEDURE PROC_NAME AUTHID CURRENT_USER
IS
.....
I faced a similar issue and got the understanding from:
Execute Immediate within a stored procedure keeps giving insufficient priviliges error

If you are connected as myuser user, you should be able to create the procedure, and execute it to create the table.
The only privileges required to do the task are:
CREATE SESSION
CREATE TABLE
CREATE PROCEDURE
And then execute the procedure after connecting to the user:
SQL> CREATE USER TEST IDENTIFIED BY TEST;
User created.
SQL> GRANT CREATE SESSION, CREATE TABLE, CREATE PROCEDURE TO TEST;
Grant succeeded.
SQL> conn TEST/TEST#pdborcl;
Connected.
SQL> show user
USER is "TEST"
SQL> CREATE OR REPLACE PROCEDURE sp_dummy
2 AS
3 BEGIN
4 EXECUTE immediate 'Create table Dummy99_99 (Dummy_Field number)';
5 END sp_dummy;
6 /
Procedure created.
SQL> EXEC sp_dummy;
PL/SQL procedure successfully completed.
SQL> select * from dummy99_99;
no rows selected

The necessary concessions are as follows:
GRANT CREATE TABLE TO "USER";
GRANT EXECUTE ANY PROCEDURE TO "USER" ;

Related

How can i restrict a user from creating tables in their own schema?

My user only has the privilege to create session, manage scheduler. But I can create tables in the schema, can I change that?
Thank you.
The if the user is able to create a table, then he has more privs than you claim. Here I create a user, grant him ONLY the privs you say, then connect as that user and try to create a table:
SQL> show user
USER is "SYSTEM"
SQL> create user beetle identified by bailey;
User created.
SQL> grant create session to beetle;
Grant succeeded.
SQL> grant manage scheduler to beetle;
Grant succeeded.
SQL> select privilege
2 from dba_sys_privs
3 where grantee='BEETLE';
PRIVILEGE
----------------------------------------
MANAGE SCHEDULER
CREATE SESSION
2 rows selected.
SQL> select granted_role
2 from dba_role_privs
3 where grantee='BEETLE';
no rows selected
SQL> select owner ||'.'||table_name,
2 privilege
3 from dba_tab_privs
4 where grantee='BEETLE';
no rows selected
SQL> -- -------- create the tables
SQL> conn beetle/bailey#pdb01
Connected.
SQL> create table my_test(dob date);
create table my_test(dob date)
*
ERROR at line 1:
ORA-01031: insufficient privileges
SQL> -- -------- load tables
SQL> -- -------- Do the query
SQL> -- -------- clean up
SQL> conn system/halftrack#pdb01
Connected.
SQL> drop user beetle cascade;
User dropped.

Oracle Privileges to Use Global Temporary Table via Definer's Rights Stored Procedure

Please assume:
User A creates global temporary table gtt.
User A creates stored procedure sp with definer's rights AUTHID DEFINER. For simplicity, assume this sp simply inserts a row into gtt and selects a value from the row in gtt.
User A grants user B execute on sp.
What additional grants, if any, need to be given to users A and B so that B can successfully execute sp?
I've heard that when a global temporary table is used (e.g. data inserted), that the user using the global temporary table needs create table privilege to create the instance of the globaly temporary table in their session's memory (even though the global temporary table itself was already created). Is that true? I assumed granting select and insert on the global temporary table would have been sufficient.
Because sp is defined by A does this mean A needs create any table, so the row of data can be inserted and selected from user B's session memory?
Sorry, I don't currently have access to an Oracle instance where I have enough privileges to try this myself.
Please note, I am not trying to create the global temporary table in the stored procedure.
Using Oracle 19c Enterprise Edition.
Thank you in advance for helping me understand the privileges involved here.
What additional grants, if any, need to be given to users A and B so that B can successfully execute sp?
None.
SQL> show user
USER is "SCOTT"
SQL> create global temporary table gtt (name varchar2(20));
Table created.
SQL> create or replace procedure sp
2 authid definer
3 as
4 begin
5 insert into gtt (name) values (user);
6 end;
7 /
Procedure created.
SQL> exec sp;
PL/SQL procedure successfully completed.
SQL> select * from gtt;
NAME
--------------------
SCOTT
SQL> grant execute on sp to mike;
Grant succeeded.
Everything works so far for the GTT and SP owner. Let's see the grantee.
SQL> connect mike/lion
Connected.
SQL> exec scott.sp;
PL/SQL procedure successfully completed.
SQL> select * From scott.gtt;
select * From scott.gtt
*
ERROR at line 1:
ORA-00942: table or view does not exist
Right; as I said, no other privileges are needed - stored procedure works (i.e. didn't fail), but - as scott didn't grant any additional privileges, mike can't check gtt table's contents.
Back to scott:
SQL> connect scott/tiger
Connected.
SQL> select * From scott.gtt;
no rows selected
SQL>
But of course; that's a global temporary table - scott sees only its own data (which is now lost).
[EDIT: to answer questions you posted as comments]
mike had create table privilege; now it doesn't:
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> revoke create table from mike;
Revoke succeeded.
This piece of code is a copy/paste from above:
SQL> connect scott/tiger
Connected.
SQL> create global temporary table gtt (name varchar2(20));
Table created.
SQL> create or replace procedure sp
2 authid definer
3 as
4 begin
5 insert into gtt (name) values (user);
6 end;
7 /
Procedure created.
SQL> exec sp;
PL/SQL procedure successfully completed.
SQL> select * from gtt;
NAME
--------------------
SCOTT
SQL> grant execute on sp to mike;
Grant succeeded.
Additionally, scott now grants select on gtt to mike:
SQL> grant select on gtt to mike;
Grant succeeded.
What does mike see now?
SQL> connect mike/lion
Connected.
SQL> exec scott.sp;
PL/SQL procedure successfully completed.
SQL> select * from scott.gtt;
NAME
--------------------
MIKE
SQL>

Query about privileges in oracle

How to invoke privileges to create a view in oracle 10g enterprise edition from the user scott? I am getting insufficient privilege error message while trying to create a view for an existing table
To give privileges to create a view, You need to grant CREATE VIEW to Scott user from sysdba user as follows:
GRANT CREATE ANY VIEW TO Scott;
-- OR --
GRANT CREATE VIEW TO Scott;
TL/DR: you need CREATE VIEW system privilege and SELECT object privilege on the related table.
Actually any user having been granted CREATE VIEW with admin option can grant CREATE VIEW this include SYSDBA and SYSTEM users but also any user having DBA role. To able to create a view on a table you generally also need SELECT privilege on the table.
Example with CREATE VIEW WITH ADMIN OPTION:
SQL> --
SQL> show user;
USER is "SYS"
SQL> --
SQL> create user scott identified by "tiger";
User created.
SQL> grant create session to scott;
Grant succeeded.
SQL> --
SQL> create user myadmin identified by "myadmin" quota unlimited on users;
User created.
SQL> grant create session to myadmin;
Grant succeeded.
SQL> grant create table to myadmin;
Grant succeeded.
SQL> grant create view to myadmin with admin option;
Grant succeeded.
SQL> --
SQL> connect myadmin/myadmin
Connected.
SQL> grant create view to scott;
Grant succeeded.
SQL> create table t(x int);
Table created.
SQL> insert into t values(4);
1 row created.
SQL> commit;
Commit complete.
SQL> grant select on t to scott;
Grant succeeded.
SQL> --
SQL> connect scott/tiger
Connected.
SQL> create view v as select * from myadmin.t;
View created.
SQL> select * from v;
X
----------
4

How do I connect as newly created user through SQL Developer on Oracle Autonomous?

I have created a user(new_user) with a password.
I have granted create session to that user.
I still cannot connect to database as new_user.
ORA-01017.
I can connect as admin.
I can see the user(new_user) in the other users menu in SQL Developer.
When I go to create a table like CREATE TABLE new_user.SALES, I get ORA-01918: user 'NEW_USER' does not exist.
I can right-click and create a table.
I know I have the right password.
Sounds very much like the double quotes issue.
Here's how it is supposed to be done:
SQL> connect sys as sysdba
Enter password:
Connected.
SQL>
SQL> create user new_user identified by new_user
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;
User created.
SQL> grant create session, create table to new_user;
Grant succeeded.
SQL> connect new_user/new_user
Connected.
SQL> create table test (id number);
Table created.
This is what I suspect you did: drop the old user first:
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> drop user new_user cascade;
User dropped.
SQL>
Now, start over. Pay attention to all double quotes in the following code:
SQL> create user "new_user" identified by new_user
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;
User created.
SQL> grant create session, create table to new_user;
grant create session, create table to new_user
*
ERROR at line 1:
ORA-01917: user or role 'NEW_USER' does not exist
SQL> grant create session, create table to "new_user";
Grant succeeded.
SQL> connect new_user/new_user
ERROR:
ORA-01017: invalid username/password; logon denied
Warning: You are no longer connected to ORACLE.
SQL> connect "new_user"/new_user
Connected.
SQL> create table new_user.test (id number);
create table new_user.test (id number)
*
ERROR at line 1:
ORA-01918: user 'NEW_USER' does not exist
SQL> create table "new_user".test (id number);
Table created.
SQL>
See? If you created it using double quotes, every time you reference it, you must use double quotes.
I suggest you get rid of them (double quotes) when working with Oracle. That includes users, table names, column names, procedure names, everything.

Oracle trigger not inserting values in another table

I have SOAP_SERVICE table in which if new value gets inserted into this table then the values should be insert into SOAP_SERVICE_STATUS table also. I am writing below trigger for this which does not have any error and compiled successfully. But when i tried to insert value into SOAP_SERVICE table then the value is not getting inserted into SOAP_SERVICE_STATUS table.
create or replace TRIGGER RATOR_MONITORING.TRG_TRK_SOAP_SERVICE_STATUS
AFTER INSERT
ON RATOR_MONITORING_CONFIGURATION.SOAP_SERVICE
FOR EACH ROW
BEGIN
INSERT INTO RATOR_MONITORING.SOAP_SERVICE_STATUS (SOAP_SERVICE_STATUS_ID,SOAP_SERVICE_ID,STATUS)
VALUES (SOAP_SERVICE_STATUS_SEQ.nextval,:new.SOAP_SERVICE_ID,'N');
END;
Sorry, cannot reproduce this one:
SQL> CREATE USER RATOR_MONITORING IDENTIFIED BY "password"
2 DEFAULT TABLESPACE USERS;
User created.
SQL> CREATE USER RATOR_MONITORING_CONFIGURATION IDENTIFIED BY "password"
2 DEFAULT TABLESPACE USERS;
User created.
SQL> GRANT CONNECT TO RATOR_MONITORING, RATOR_MONITORING_CONFIGURATION;
Grant succeeded.
SQL> GRANT CREATE TABLE TO RATOR_MONITORING, RATOR_MONITORING_CONFIGURATION;
Grant succeeded.
SQL> GRANT CREATE SEQUENCE TO RATOR_MONITORING;
Grant succeeded.
SQL> GRANT CREATE ANY TRIGGER TO RATOR_MONITORING;
Grant succeeded.
SQL> ALTER USER RATOR_MONITORING QUOTA UNLIMITED ON USERS;
User altered.
SQL> ALTER USER RATOR_MONITORING_CONFIGURATION QUOTA UNLIMITED ON USERS;
User altered.
SQL> CONNECT RATOR_MONITORING_CONFIGURATION/password
Connected.
SQL> CREATE TABLE RATOR_MONITORING_CONFIGURATION.SOAP_SERVICE (SOAP_SERVICE_ID INTEGER);
Table created.
SQL> CONNECT RATOR_MONITORING/password
Connected.
SQL> CREATE TABLE RATOR_MONITORING.SOAP_SERVICE_STATUS
2 (SOAP_SERVICE_STATUS_ID INTEGER, SOAP_SERVICE_ID INTEGER, STATUS CHAR(1));
Table created.
SQL> CREATE SEQUENCE RATOR_MONITORING.SOAP_SERVICE_STATUS_SEQ;
Sequence created.
SQL> create or replace TRIGGER RATOR_MONITORING.TRG_TRK_SOAP_SERVICE_STATUS
2 AFTER INSERT
3 ON RATOR_MONITORING_CONFIGURATION.SOAP_SERVICE
4 FOR EACH ROW
5 BEGIN
6 INSERT INTO RATOR_MONITORING.SOAP_SERVICE_STATUS (SOAP_SERVICE_STATUS_ID,SOAP_SERVICE_ID,STATUS)
7 VALUES (SOAP_SERVICE_STATUS_SEQ.nextval,:new.SOAP_SERVICE_ID,'N');
8 END;
9 /
Trigger created.
SQL> CONNECT RATOR_MONITORING_CONFIGURATION/password
Connected.
SQL> INSERT INTO RATOR_MONITORING_CONFIGURATION.SOAP_SERVICE (SOAP_SERVICE_ID) VALUES (7);
1 row created.
SQL> COMMIT;
Commit complete.
SQL> CONNECT RATOR_MONITORING/password
Connected.
SQL> SELECT * FROM RATOR_MONITORING.SOAP_SERVICE_STATUS;
SOAP_SERVICE_STATUS_ID SOAP_SERVICE_ID S
---------------------- --------------- -
1 7 N
Notes:
The CREATE ANY TRIGGER privilege is necessary for RATOR_MONITORING to create a trigger on a table in another schema,
When we change connection in SQL*Plus, the database creates a new session for us to use. Changes made in one session are not visible in another session until these changes are committed.
SQL*Plus implicitly commits transactions when disconnecting. In the above example, we commit explicitly before the last CONNECT so that we are not relying on implicit behaviour.
The most probable explanation is that you select the table RATOR_MONITORING.SOAP_SERVICE_STATUS with a different connection without COMMITing the original session performing the insert in RATOR_MONITORING_CONFIGURATION.SOAP_SERVICE.
After the commit the record should be visible.
Note also that this is a side-effect of the fact that the trigger is in a different schema than the table; the user RATOR_MONITORING_CONFIGURATION can insert in the table RATOR_MONITORING.SOAP_SERVICE_STATUS even if he/she doen't have INSERT grant!
To enable this the user RATOR_MONITORING must have the privilege create any trigger - which is not always considered as best practice (as to mighty privilege) - see eg Tom Kyte

Resources