Without using GRANT SELECT ANY TABLE, how would I grant access to all tables from only one schema.
Example:
There are three users. u1, u2, u3.
u1 need access to all the tables that u2 has but doesn't need access to tables that u3 has.
I could loop through all the tables and grant them individually.
But what about new tables that u2 creates later. u1 needs those tables too.
How could I automatically grant those new tables as well?
I believe you can do this with an AFTER CREATE trigger. The following example doesn't handle all your U1/U2/U3 logic - you'll have to add that - but it should give you the basic idea:
CREATE TRIGGER AUTO_GRANT
AFTER CREATE ON SCHEMA
BEGIN
IF ORA_DICT_OBJ_TYPE = 'TABLE' THEN
EXECUTE IMMEDIATE 'GRANT SELECT ON ' || ora_dict_obj_owner || '.' ||
ora_dict_obj_name ' TO U1';
END IF;
END AUTO_GRANT;
Docs here.
Best of luck.
Related
i need to use synonym as variable in a block. I have 2 different schemas with same tables on them and job that switches between schemas making one active. Now I want to write a block checking which schema is active with ALL_SYNONYMS and using result as part of a query.
Here is example:
DECLARE
OWNER VARCHAR2(15);
BEGIN
SELECT TABLE_OWNER
INTO OWNER
FROM ALL_SYNONYMS
WHERE TABLE_NAME = 'MY_TABLE1';
SELECT *
FROM OWNER.MY_TABLE2 ;
END;
But I’m getting ORA-06550 table or view does not exist, and when i run query itself where i put value from ALL_SYNONYMS it returns result.
Any idea how to fix this?
Thanks
You are attempting using symptoms incorrectly. Synonyms are used so you do not need to know which is active. According to the documentation:
Synonyms provide both data independence and location transparency.
Synonyms permit applications to function without modification
regardless of which user owns the table or view and regardless of
which database holds the table or view.
You just use the synonym instead of the object itself.
create table evens( id integer generated always as identity
, val integer
) ;
create table odds( id integer generated always as identity
, val integer
) ;
insert all
when mod(val,2) = 0 then into evens(val)
when mod(val,2) = 1 then into odds(val)
select level val
from dual connect by level <= 10;
-- create the synonym then use it in Select;
create or replace synonym current_even_odd for evens;
select * from current_even_odd;
-- now change the synonym, then run the EXACT same query.
create or replace synonym current_even_odd for odds;
select * from current_even_odd;
In this case it is not quite without modification, you need to change the synonym, But it seems you are trying that already.
Note: You cannot create a synonym for a schema but must point it to a specific object.
I attempted a db<>fiddle for the above, but it appears it is having problems at the moment.
I agree with Belayer that the synonym should provide a layer of abstraction on your tables and your procedure shouldn't need to know what the schema is. But the "table or view does not exist" error is likely an issue related to privileges and definer's rights versus invoker's rights.
To directly reference an object in a procedure, the procedure's schema must have a direct grant to the table. However, an ad hoc query only needs a role with privileges on the object. This is why the SQL will work in your IDE but not in the procedure. Ensure the code that modifies objects and switches synonyms is granting privileges to both roles and directly to schemas.
If direct grants are not possible, you will need to modify the procedure to use AUTHID CURRENT_USER and change the SQL statements to use dynamic SQL - which can be a huge pain. For example:
create or replace procedure test_procedure authid current_user is
v_count number;
begin
execute immediate
q'[
select count(*)
from some_table
]'
into v_count;
end test_procedure;
/
If you really do need to manually switch between schemas, then you may want to consider using something like execute immediate 'alter session set current_schema=schema1'; in the procedure and using dynamic SQL for all of the querying.
Disclaimer: I do not venture into the realm of database administration often, and usually stick to data analytics. However, I am trying to educate myself and build my DBA skillset on a small sample database I've created. I am NOT trying to edit anything in production.
This is an extension of this question:
How do I show running processes in Oracle DB?
I would like to create a view for my users that shows a read-only copy of all processes running on my database (similar to what you can do in the terminal of a linux operating system).
I do NOT want to give my users the ability to alter or kill processes that do not belong to them, I just want to give them the ability to easily see how busy the database server is at any given time (I.E.-"read-only" access).
I know to run the below command and allow users to access the view, I need to modify the database permissions. Is there a permission I can enable on the user accounts that will allow them to "select * from WHAT_IS_RUNNING_ON_DB", but not alter/kill processes that they don't own?
CREATE VIEW WHAT_IS_RUNNING_ON_DB AS
SELECT
sess.process, sess.status, sess.username, sess.schemaname,
sql.sql_text
FROM v$session sess,
v$sql sql
WHERE sql.sql_id(+) = sess.sql_id
AND sess.type = 'USER'
AND sess.status = 'ACTIVE'
If you only want them to view what is running, simply:
grant select on v$session to USER1;
grant select on v$sql to USER1;
Then create the view in their schemas. Alternatively, if you don't want them querying on these v$ views directly (because you want to hide the other columns or you only want to keep the code for the view all in one place), you can create a user, grant the above to this new user, create the view in that schema, then grant whoever select against the view.
I do NOT want to give my users the ability to alter or kill processes
that do not belong to them
Although you didn't explicitly ask for it, I interpret this as, you may want to grant users the ability to kill processes that they do own.
Asktom has a good article how to do this:
Create the following procedure in that high privileged user's schema:
create or replace procedure kill_session( p_sid in varchar2,
p_serial# in varchar2)
is
cursor_name pls_integer default dbms_sql.open_cursor;
ignore pls_integer;
BEGIN
select count(*) into ignore
from V$session
where username = USER
and sid = p_sid
and serial# = p_serial# ;
if ( ignore = 1 )
then
dbms_sql.parse(cursor_name,
'alter system kill session '''
||p_sid||','||p_serial#||'''',
dbms_sql.native);
ignore := dbms_sql.execute(cursor_name);
else
raise_application_error( -20001,
'You do not own session ''' ||
p_sid || ',' || p_serial# ||
'''' );
end if;
END;
/
The owner of this procedure needs to have
o SELECT on v_$session granted to them by SYS. This grant must be
directly to them, not via a role.
o ALTER SYSTEM granted directly to them -- not via a role.
You would then grant execute on this procedure to anyone you want. It
would allow them to kill any session they own (running under their
username). You would probably want to "grant select on v_$session"
when connected as SYS to these people as well so they can 'see' the
v$session dynamic performance view to get their sid/serial# pairs
I use the SQL Developer to connect with Oracle.
I try to "automate" the rights, that means that I do not need all the time to type in every GRANT comment for every table and every user. So my idea was to make three tables. One owns the table names which exists in the database, and a tablegroup. One owns all the users and one the rights with rightgroups.
Now I try to automate it, to put it in one grant. Like:
GRANT (Select rights from DB_Rights where rightgroup = 1)
ON (Select tables from DB_Tables where Tablegroup = 1) to (User)
But it didn't work. Where is my mistake? Or isn't this possible? Is there another option to "automate" it?
The solution could be similar to this. You still have to write the right SELECT query but you should get an idea how it works.
BEGIN
FOR aGRANT IN (
Select rights, tables, User_NAME
from DB_Rights
CROSS JOIN DB_Tables
where Tablegroup = 1 AND rightgroup = 1 AND Tablegroup = 1)
LOOP
EXECUTE IMMEDIATE 'GRANT '||aGRANT.rights||' ON '||aGRANT.tables||' TO '||aGRANT.User_NAME;
END LOOP;
END;
In order to verify your command replace EXECUTE IMMEDIATE ... by DBMS_OUTPUT.PUT_LINE(...);
In general consider the usage of ROLES as suggested by tbone. However, there are situations where ROLES are not applicable or end up in "automate grants for ROLES" instead of "automate grants for USERS"
I have 3 schema's in my database:
Colldesk - Main account
Local_it - Local account for developments
User - User account
Now I am writing a procedure to grant people access based on their job. Depending on their job, they need select, or select, update, insert and delete privileges on certain tables.
I know that usually you create roles for this, but I can't (DBA's are external, and they don't like roles.......)
When running the procure, I am inserting the new user, and which department they belong to. If the department is IT_SUPPORT for example, they will need to be able to update tables in the account account and the local_it account. My procedure is located in the local_it account.
Now, when I am trying to run a script like:
for x in (select *
from all_objects
where owner in ('COLLDESK','LOCAL_IT')
and object_type in ('TABLE','VIEW')
and object_name not in ('IFM_letter_data','IFM_letter_data_V2')
order by owner asc)
loop
execute immediate 'grant update on ' || x.owner || '.' || x.object_name || ' to ' || v_user;
end loop;
I am getting an error, saying that I have insufficient privileges. Is it possible to grant update privileges on a table in a different schema? I am able to grant select privileges.
Thanks a lot in advance
Look at this: You have a friend that you trust and you gave him a key to your appartment.
Are you OK if your friend will give a copy of your key to his friend?
It might be NO, it might be YES.
When you want to grant permissions to a user you may say that it is OK for that user to share access with the others.
So, in your case:
User with tables should grant you access to her tables, with permissions to share:
grant update on my_table to you with grant option
Then you can manage access to that table.
This question already has answers here:
Grant Select on all Tables Owned By Specific User
(5 answers)
Closed 5 years ago.
The situation is I have two schemas: A and B. I have a restricted user that I need to give a privilege do SELECT queries in B schema and just it. How can I grant this user?
You can't.
The best you can do is grant user a 'select' privilege each table in schema b.
this query will generate the commands you'll need:
select 'grant select on A.'||table_name||' to B;'
from dba_Tables
where owner = 'A';
The problem with this, is in the case you will want to add new table to A. then you'll have to grant the privilege on it separately. it will not do it automatically..
You may find you do not have access to dba_tables,
The following block of code run in the owning schema (a) will grant permissions to all tables, to the user b
BEGIN
FOR t IN (SELECT * FROM user_tables)
LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON ' || t.table_name || ' TO b';
END LOOP;
END;