Is it normal for an oracle view to loose all its grants when modifying the source SQL?
I am using SQL Developer if that has anything to do with it.
First of all, you don't have "grants" - "grant" is an operation. You have "roles" and "privileges".
Second, views have neither roles nor privileges themselves - schemas do have. Basically, a self-descriptive command is: grant select on view_1 to schema_1.
Third, schemas do not lose their privileges if you create or replace your view. Here's a quick sample:
11:03:07 #> conn system/sys#oars_sandbox
Connected.
11:03:15 SYSTEM#oars_sandbox> create user test1 identified by test1;
User created.
11:03:39 SYSTEM#oars_sandbox> create user test2 identified by test2;
User created.
11:03:48 SYSTEM#oars_sandbox> create view test1.view1 as select * from dual;
View created.
11:04:03 SYSTEM#oars_sandbox> grant select on test1.view1 to test2;
Grant succeeded.
11:04:15 SYSTEM#oars_sandbox> select grantee, owner, table_name, privilege, grantor from dba_tab_privs where grantee = 'TEST2';
GRANTEE OWNER TABLE_NAME PRIVILEGE GRANTOR
------------------------------ ------------------------------ ------------------------------ ---------------------------------------- ------------------------------
TEST2 TEST1 VIEW1 SELECT TEST1
11:05:13 SYSTEM#oars_sandbox> create or replace view test1.view1 as select * from dual;
View created.
11:05:24 SYSTEM#oars_sandbox> select grantee, owner, table_name, privilege, grantor from dba_tab_privs where grantee = 'TEST2';
GRANTEE OWNER TABLE_NAME PRIVILEGE GRANTOR
------------------------------ ------------------------------ ------------------------------ ---------------------------------------- ------------------------------
TEST2 TEST1 VIEW1 SELECT TEST1
However, it is quite possible that SQL developer invokes drop view first instead of create or replace. In this case, your privileges are automatically removed.
11:05:26 SYSTEM#oars_sandbox> drop view test1.view1;
View dropped.
11:10:21 SYSTEM#oars_sandbox> select grantee, owner, table_name, privilege, grantor from dba_tab_privs where grantee = 'TEST2';
no rows selected
11:10:24 SYSTEM#oars_sandbox> create or replace view test1.view1 as select * from dual;
View created.
11:10:26 SYSTEM#oars_sandbox> select grantee, owner, table_name, privilege, grantor from dba_tab_privs where grantee = 'TEST2';
no rows selected
Related
I use the below to grant select permission to amy on table1:
grant select schema.table1 to amy;
However, the below does not work:
grant select on schema.* to amy;
the error is
ORA-00903: invalid table name
Please advise what is wrong in my command. What I want is grant select to amy on ALL tables.
thanks
The syntax for the GRANT command (as of Oracle 21c) makes it clear that the granted item can only be a specific object:
on_object_clause:
The best you can do is create a role and grant the role to Amy, but you will still have to grant privileges on each individual table to the role.
create role analyst;
grant analyst to amy;
grant read on hr.countries to analyst;
grant read on hr.departments to analyst;
grant read on hr.employees to analyst;
To create a role and grant it to amy:
create role select_all_tables;
grant select_all_tables to amy;
alter user amy default role select_all_tables;
Use the following query to generate a script, which you can copy/paste and run to complete all the grants:
select 'grant select on '|| owner || '.' || table_name ||' to select_all_tables;'
from dba_tables where owner='SCHEMA';
copy and paste the output, and execute it as as script.
grant select on schema.table1 to select_all_tables;
grant select on schema.table2 to select_all_tables;
...
If you would rather grant the privileges directly and not use a role, alter the script query:
select 'grant select on '|| owner || '.' || table_name ||' to amy;'
from dba_tables where owner='SCHEMA';
and then run the output as a script:
grant select on schema.table1 to amy;
grant select on schema.table2 to amy;
...
grant select on table to public;
But be careful when you do that -- make sure it's what you really want to do.
I use the query CTAS to create a new table, however, when CTAS has finished, other users canĀ“t select the new table, but they had access to the old, Is it a way to pass all the users and groups to the new table? because the old table will be deleted.
"A way" is to grant (at least) select privileges to all those users.
If you used a role and granted select privilege to that role, and then granted role to those users, things would be quite simpler - just grant select privilege on the new table to the same role, and everyone will "see" it.
Otherwise, you can write query to create those grant statements for you.
For example, in Scott's schema there's the EMP table. I've previously granted privileges on it to other users in my database, and now I'm going to create a "new" CTAS table and grant privileges to the same set of users.
SQL> create table my_new_table as select * from emp;
Table created.
SQL> select 'grant select on my_new_table to ' || grantee ||';' run_me
2 from all_tab_privs_made
3 where owner = 'SCOTT'
4 and table_name = 'EMP';
RUN_ME
---------------------------------------------------------------
grant select on my_new_table to SYS;
grant select on my_new_table to SUPERUSER;
grant select on my_new_table to MY_ROLE;
grant select on my_new_table to MIKE;
Now simply copy/paste the above bunch of grant statements:
SQL> grant select on my_new_table to SYS;
Grant succeeded.
SQL> grant select on my_new_table to SUPERUSER;
Grant succeeded.
SQL> grant select on my_new_table to MY_ROLE;
Grant succeeded.
SQL> grant select on my_new_table to MIKE;
Grant succeeded.
SQL>
If there's zillion of users, PL/SQL option would be simpler as it would do everything for you (i.e. no copy/pasting):
SQL> begin
2 for cur_r in (select grantee
3 from all_tab_privs_made
4 where owner = 'SCOTT'
5 and table_name = 'EMP'
6 )
7 loop
8 execute immediate 'grant select on my_new_table to ' || cur_r.grantee;
9 end loop;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
If you create a table using CTAS from an existing one, the new one is a new segment, therefore it lacks of privileges. You need to recover the permissions granted to the old table and granting to the new one. For that you can use several alternatives ( dbms_metadata, dynamic sql ).
For the purposes , I'd do it like this
SQL> CREATE TABLE T2 AS SELECT * FROM T1 ;
SQL> begin
dbms_metadata.set_transform_param (dbms_metadata.session_transform,
'SQLTERMINATOR', true);
dbms_metadata.set_transform_param (dbms_metadata.session_transform, 'PRETTY',
true);
end;
/
select replace(dbms_metadata.get_dependent_ddl('OBJECT_GRANT', 'T1', 'OWNER_OF_T1' ),'T1','T2') AS ddl
from dual;
The first part is for creating in a nice format the list of necessary grants. The second part retrieves all the privileges granted to T1 and generates the list of grants statements for running to the T2 table. Then you only need to run the list of grants
As I said, there are several alternatives to do this.
Regards
If I'm creating a table in user A.
How user B can query that table if I didn't gave it any privs?
In that code, I'm creating table general.privs_test from DBA user named "DBA_MAINT".
After that, I'm switching to another user and try to query the table.
There is no exception, even there is no grant on that table.
SQL> select user from dual;
USER
------------------------------
DBA_MAINT
SQL> create table general.privs_test(id number);
Table created.
SQL> conn dp99712a
Enter password:
Connected.
SQL> select user from dual;
USER
------------------------------
DP99712A
SQL> select * from general.privs_test;
no rows selected
SQL> desc all_tab_privs;
Name Null? Type
----------------------------------------- -------- ----------------------------
GRANTOR NOT NULL VARCHAR2(30)
GRANTEE NOT NULL VARCHAR2(30)
TABLE_SCHEMA NOT NULL VARCHAR2(30)
TABLE_NAME NOT NULL VARCHAR2(30)
PRIVILEGE NOT NULL VARCHAR2(40)
GRANTABLE VARCHAR2(3)
HIERARCHY VARCHAR2(3)
SQL> select grantee,table_schema,table_name,privilege, grantable from all_tab_pr
ivs where table_name = 'PRIVS_TEST';
no rows selected
My version is ORacle 11g.
As the table is freshly created without any privileges, the user dp99712a must have a system privilege that lets see him/her all tables. This privilege is called SELECT ANY TABLE and is granted normally to the role DBA.
To find out if this is the case, connect as user dp99712a and query:
SELECT * FROM session_privs WHERE PRIVILEGE = 'SELECT ANY TABLE';
To find out all the users and roles that have this privilege, you can use:
SELECT DISTINCT grantee
FROM dba_sys_privs
WHERE PRIVILEGE LIKE 'SELECT ANY TABLE%' ORDER BY 1;
1/ To my knowledge, direct privilege grant and ROLE grant and PUBLIC grant are independent, meaning all 3 can carry themselves the same privilege. Revoking from one does not interfere with that privilege still staying with the user.
Meaning if we
GRANT SELECT ON T TO userA
GRANT SELECT ON T TO roleA; GRANT roleA to userA
GRANT SELECT on T TO PUBLIC
Revoking one or two of the 3 Grants leaves the userA with the SELECT privilege.
How about ALL PRIVILEGES, does it overlap with any of these 3 zones ? If we have the 3 grants above and the following
GRANT ALL PRIVILEGES on T to userA;
and then we
REVOKE ALL PRIVILEGES on T to userA;
which one of the 3 grants will be additionally removed ? Does it behave the same for system privilege and object privileges ?
2/ There is a GRANT ANY PRIVILEGE and GRANT ALL PRIVILEGE*S*. Are they the same ?
As per the docs "Oracle Database provides the ALL PRIVILEGES shortcut for granting all the system privileges listed in Table 18-1, except the SELECT ANY DICTIONARY privilege." Your examples are not system privileges so there is no overlap. https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9013.htm
As for GRANT ANY PRIVILEGE, this grants the user the ability to in turn grant a system privilege to other users. For example:
dba#db> GRANT GRANT ANY PRIVILEGE to some_user;
grant succeeded
reconnect as some_user. This user can now pass on system grants to some_other_user.
some_user#db> GRANT COMMENT ANY TABLE to some_other_user;
grant succeeded
This seems to be like a privilege you want to use when you want to give a user partial dba privileges and should be used with care.
In contrast ALL PRIVILEGES is more like a macro that grants all of the individual system privileges at once so
GRANT ALL PRIVILEGES to some_user;
would be like running grant statements for all system privileges (and there are many):
GRANT ADVISOR TO some_user;
GRANT ADMINISTER SQL TUNING SET TO some_user;
GRANT ADMINISTER ANY SQL TUNING SET TO some_user;
GRANT CREATE ANY SQL PROFILE TO some_user;
GRANT DROP ANY SQL PROFILE TO some_user;
GRANT ALTER ANY SQL PROFILE TO some_user;
etc...
EDIT:
Further in the link above, under the grant_object_privileges section there is also:
ALL [PRIVILEGES]
Specify ALL to grant all the privileges for the object that you have
been granted with the GRANT OPTION. The user who owns the schema
containing an object automatically has all privileges on the object
with the GRANT OPTION. The keyword PRIVILEGES is provided for semantic
clarity and is optional.
If you do something like
GRANT ALL PRIVILEGES on some_table TO some_user;
that user gets all of these table privileges (at least this is the list I get in 12c):
FLASHBACK
DEBUG
QUERY REWRITE
ON COMMIT REFRESH
READ
REFERENCES
UPDATE
SELECT
INSERT
INDEX
DELETE
ALTER
For sequences you get:
SELECT
ALTER
(And other object types will have their own list.)
So, it's just like ALL PRIVILEGES for system privileges in that it's a shortcut for granting all of the object privileges for the type of object specified; there isn't one "ALL PRIVILEGES" privilege that you get. For tables it's like typing in the grant statements for the 12 privileges listed above:
GRANT FLASHBACK on ...
GRANT DEBUG on ...
GRANT QUERY REWRITE on ...
Each one of these privileges can be individually revoked. So if you did:
REVOKE INSERT, UPDATE, DELETE on some_table FROM some_user;
you would still have the 9 other privileges from the above table privileges.
If you use "ALL PRIVILEGES" with REVOKE:
REVOKE ALL PRIVILEGES on some_table FROM some_user;
it will take away whatever table privileges some_user had remaining on some_table in the above list.
So, to make a long story longer, here's a SQL example to show the answer to your original question (the owner of table T is USERT):
SQL> create table t (a varchar2(1));
Table created.
SQL> grant select on t to userA;
Grant succeeded.
SQL> select grantor
2 , grantee
3 , table_schema
4 , table_name
5 , privilege
6 from all_tab_privs
7 where table_name = 'T'
8 order by grantee;
GRANTOR GRANTEE TABLE_SCHEMA TABLE_NAME PRIVILEGE
---------- ---------- ------------ ---------- --------------------
USERT USERA USERT T SELECT
SQL>
SQL> grant select on t to roleA;
Grant succeeded.
SQL> select grantor
2 , grantee
3 , table_schema
4 , table_name
5 , privilege
6 from all_tab_privs
7 where table_name = 'T'
8 order by grantee;
GRANTOR GRANTEE TABLE_SCHEMA TABLE_NAME PRIVILEGE
---------- ---------- ------------ ---------- --------------------
USERT ROLEA USERT T SELECT
USERT USERA USERT T SELECT
SQL> grant select on t to public;
Grant succeeded.
SQL> select grantor
2 , grantee
3 , table_schema
4 , table_name
5 , privilege
6 from all_tab_privs
7 where table_name = 'T'
8 order by grantee;
GRANTOR GRANTEE TABLE_SCHEMA TABLE_NAME PRIVILEGE
---------- ---------- ------------ ---------- --------------------
USERT PUBLIC USERT T SELECT
USERT ROLEA USERT T SELECT
USERT USERA USERT T SELECT
SQL> grant all privileges on t to userA;
Grant succeeded.
SQL> select grantor
2 , grantee
3 , table_schema
4 , table_name
5 , privilege
6 from all_tab_privs
7 where table_name = 'T'
8 order by grantee;
GRANTOR GRANTEE TABLE_SCHEMA TABLE_NAME PRIVILEGE
---------- ---------- ------------ ---------- --------------------
USERT PUBLIC USERT T SELECT
USERT ROLEA USERT T SELECT
USERT USERA USERT T INDEX
USERT USERA USERT T INSERT
USERT USERA USERT T ALTER
USERT USERA USERT T SELECT
USERT USERA USERT T FLASHBACK
USERT USERA USERT T DELETE
USERT USERA USERT T REFERENCES
USERT USERA USERT T READ
USERT USERA USERT T ON COMMIT REFRESH
USERT USERA USERT T QUERY REWRITE
USERT USERA USERT T DEBUG
USERT USERA USERT T UPDATE
14 rows selected.
SQL> REVOKE ALL PRIVILEGES on T from userA;
Revoke succeeded.
SQL> select grantor
2 , grantee
3 , table_schema
4 , table_name
5 , privilege
6 from all_tab_privs
7 where table_name = 'T'
8 order by grantee;
GRANTOR GRANTEE TABLE_SCHEMA TABLE_NAME PRIVILEGE
---------- ---------- ------------ ---------- --------------------
USERT PUBLIC USERT T SELECT
USERT ROLEA USERT T SELECT
So the REVOKE ALL PRIVILEGES command removed all of the direct grants on table T from userA, but that user would still have SELECT privileges through the grant select to roleA (assuming userA has been granted the role) or the grant select to public.
What is a SQL statement to find out which Schema owns an Oracle table?
To see information about any object in the database, in your case USER_TABLES use:
select * from all_objects where object_name = 'USER_TABLES';
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME
SYS USER_TABLES 3922 VIEW 24-MAY-13 24-MAY-13
USER_TABLES is a dictionary view. All dictionary views are owned by SYS.
SELECT OWNER FROM DBA_TABLES WHERE TABLE_NAME = '<your table>'
If you don't have privilege to DBA_TABLES use ALL_TABLES.
Here are the queries:
SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME='<TABLE_NAME>'; -- There is no owner column in this view
SELECT OWNER, TABLE_NAME FROM ALL_TABLES WHERE OWNER='<OWNER_NAME>' AND TABLE_NAME='<TABLE_NAME>';
SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE OWNER='<OWNER_NAME>' AND TABLE_NAME='<TABLE_NAME>';
Also you can query USER_OBJECTS, ALL_OBJECTS, DBA_OBJECTS using OBJECT_TYPE='TABLE' and OWNER= '<OWNER_NAME>' and OBJECT_NAME='<TABLE_NAME>'
There are 3 views, which can give that information:
USER_TABLES, if the login schema is the owner of the table
ALL_TABLES, if the login schema have permission on the table or owner of the table or have SELECT_CATALOG role
DBA_TABLES, if the login schema have SELECT_CATALOG role or any other role which have SELECT_CATALOG role