I am trying to display the two column values (grantee and granted_role) from this execute immediate statement and tried various methods but nothing seems to work.
declare
v_stmt1 varchar2(1024);
begin
for x in ( select grantee from dba_tab_privs where grantee IN (select role from dba_roles) and PRIVILEGE not in ('SELECT') group by grantee)
loop
v_stmt1 := 'select grantee,granted_role from dba_role_privs where granted_role in ('||''''||x.grantee||''''||')';
execute immediate v_stmt1;
DBMS_OUTPUT.PUT_LINE --- How to display to screen???
end loop;
end;
/
Important Note: I am writing a procedure which will display list of users who have a granted role which has privileges other than SELECT. Any help would be greatly appreciated.
There's nothing dynamic in your query, so I suggest you don't use it at all & simplify code (as a consequence):
SQL> set serveroutput on
SQL>
SQL> BEGIN
2 FOR x
3 IN (SELECT grantee, granted_role
4 FROM dba_role_privs
5 WHERE granted_role IN
6 ( SELECT grantee
7 FROM dba_tab_privs
8 WHERE grantee IN (SELECT role FROM dba_roles)
9 AND PRIVILEGE NOT IN ('SELECT')
10 GROUP BY grantee))
11 LOOP
12 DBMS_OUTPUT.put_line (x.grantee || ': ' || x.granted_role);
13 END LOOP;
14 END;
15 /
SYS: APEX_ADMINISTRATOR_READ_ROLE
SYS: ORDS_ADMINISTRATOR_ROLE
SYS: ORDS_RUNTIME_ROLE
ORDS_PUBLIC_USER: ORDS_RUNTIME_ROLE
SYS: APEX_ADMINISTRATOR_ROLE
<snip>
Related
How to change this SQL query to PL/SQL command line or code?
SELECT username, account_status FROM dba_users;
I tried
DECLARE
user_name VARCHAR2(20) := 'username';
account_status VARCHAR2(20) := 'account_status';
BEGIN
FOR user_name IN (SELECT username FROM dba_users) LOOP
FOR account_status IN (SELECT account_status FROM dba_users) LOOP
dbms_output.put_line(user_name.username || ' - ' || user_record.account_status);
END LOOP;
END LOOP;
END;
it works but the output is repeating
This is pure SQL:
SQL> select username, account_status from dba_users where rownum <= 5;
USERNAME ACCOUNT_STATUS
-------------------- --------------------
SYS OPEN
AUDSYS LOCKED
SYSTEM OPEN
SYSBACKUP LOCKED
SYSDG LOCKED
To "convert" it into PL/SQL, use one loop (why using two?):
SQL> set serveroutput on
SQL> begin
2 for cur_r in (select username, account_status from dba_users where rownum <= 5)
3 loop
4 dbms_output.put_line(cur_R.username ||' - '|| cur_r.account_status);
5 end loop;
6 end;
7 /
SYS - OPEN
AUDSYS - LOCKED
SYSTEM - OPEN
SYSBACKUP - LOCKED
SYSDG - LOCKED
PL/SQL procedure successfully completed.
Your code, fixed: if you use nested loops (once again, no need for that), you have to correlate one loop query to another - that's what you are missing - see line #4:
SQL> begin
2 for cur_user in (select username from dba_users where rownum <= 5) loop
3 for cur_acc in (select account_status from dba_users
4 where username = cur_user.username
5 )
6 loop
7 dbms_output.put_line(cur_user.username ||' - '|| cur_acc.account_status);
8 end loop;
9 end loop;
10 end;
11 /
SYS - OPEN
AUDSYS - LOCKED
SYSTEM - OPEN
SYSBACKUP - LOCKED
SYSDG - LOCKED
PL/SQL procedure successfully completed.
SQL>
Just use this block:
cl scr
set SERVEROUTPUT ON
BEGIN
FOR i IN (SELECT distinct username FROM dba_users order by username) LOOP
FOR j IN (SELECT distinct account_status FROM dba_users where username=i.username order by account_status) LOOP
dbms_output.put_line(i.username || ' - ' || j.account_status);
END LOOP;
END LOOP;
END;
Is there any possibility to revoke "delete" from one table over "any table" privilege?
My user_role has GRANT DELETE ANY TABLE TO TEST_USER_ROLE privilege.
I would like leave it except one table.
I tried with REVOKE DELETE on TEST_TABLE from TEST_USER_ROLE but I got "cannot REVOKE privileges you did not grant" error which is correct. Any advice?
Thanks!
Revoke DELETE ANY TABLE and grant DELETE, separately. A lot of grants? Certainly, but you don't have to do it manually - write query that'll create those statements for you. Or, do it in a PL/SQL procedure, in a loop (omit table you don't want to include).
Say if you need help in composing such a code.
Here's a PL/SQL procedure which does the job:
SQL> set serveroutput on
SQL>
SQL> declare
2 l_grantee varchar2(30) := 'MIKE';
3 l_str varchar2(200);
4 begin
5 for cur_r in (select table_name
6 from user_tables
7 where table_name <> 'DEPT'
8 and rownum <= 5
9 )
10 loop
11 l_str := 'grant delete on ' || cur_r.table_name || ' to ' || l_grantee;
12 dbms_output.put_line(l_str);
13 execute immediate l_str;
14 end loop;
15 end;
16 /
grant delete on DPT to MIKE
grant delete on TABLE_B to MIKE
grant delete on TABLE_A to MIKE
grant delete on EMPLOYEES to MIKE
grant delete on TABLE_NAME to MIKE
PL/SQL procedure successfully completed.
SQL>
. What does it do?
line #2, l_grantee: user I'm going to grant the privilege to
cursor FOR loop: just for example, I'll omit table dept and (to make a list shorter) grant delete for only 5 tables
line #11: compose the grant statement
line #12: display it (so that you'd have evidence of what you did)
line #13: grant!
If there are more owners included, you'd use ALL_TABLES or even DBA_TABLES instead of USER_TABLES (line #6) and include the OWNER column (because many users can have a table with the same name).
In our Oracle 12c database, I am trying to create a package that will drop and create tables as needed.
For my first test, I wrote an anonymous code block and it works fine:
begin
begin
execute immediate 'Drop Table my_table';
exception
when OTHERS then
if sqlcode = -942 then
null;
end if;
end;
begin
execute immediate 'Create Table my_table as
WITH
sub_qy AS(
SELECT DISTINCT
...
)
SELECT * FROM sub_qy';
end;
execute immediate 'GRANT SELECT ON my_table to my_role';
I then tried to create a package and put the anonymous code block in a procedure but when executing the procedure I get the error:
ORA-01031: insufficient privileges
Here is the logic:
create package my_refresh_pkg as
procedure create_first_table;
end my_refresh_pkg;
create package body my_refresh_pkg as
procedure create_first_table is
begin
begin
execute immediate 'Drop Table my_table';
exception
when OTHERS then
if sqlcode = -942 then
null;
end if;
end;
begin
execute immediate 'Create Table my_table as
WITH
sub_qy AS(
SELECT DISTINCT
...
)
SELECT * FROM sub_qy';
end;
execute immediate 'GRANT SELECT ON my_table to my_role';
end create_first_table;
end my_refresh_pkg;
I created the package in my own schema, so I am not sure why I am getting this error. Any insight would be appreciated.
Suspicious part is this:
SELECT DISTINCT
...
as it smells like a know issue with privileges. If table(s) you used in the above statement's FROM clause don't belong to you but someone else, and you acquired select (or any other) privileges via role, well - it won't work in named PL/SQL procedures. Yes, that's a stored procedure, or a function, or - a package you wrote.
Solution is to grant those privileges directly to you, not via role.
[EDIT: running your code in my database - no errors]
SQL> create or replace package my_refresh_pkg as
2 procedure create_first_table;
3 end my_refresh_pkg;
4 /
Package created.
SQL> create or replace package body my_refresh_pkg as
2 procedure create_first_table is
3 begin
4 begin
5 execute immediate 'Drop Table my_table';
6 exception
7 when OTHERS then
8 if sqlcode = -942 then
9 null;
10 end if;
11 end;
12 begin
13 execute immediate 'Create Table my_table as
14 WITH
15 sub_qy AS(
16 SELECT DISTINCT
17 job from emp
18 )
19 SELECT * FROM sub_qy';
20 end;
21 execute immediate 'GRANT SELECT ON my_table to my_role';
22 end create_first_table;
23 end my_refresh_pkg;
24 /
Package body created.
SQL> create role my_role;
Role created.
Testing:
SQL> exec my_refresh_pkg.create_first_table;
PL/SQL procedure successfully completed.
SQL> select * From my_table;
JOB
---------
CLERK
SALESMAN
PRESIDENT
MANAGER
ANALYST
SQL>
I'm trying to make a procedure which gives grants to users on a certain type of objects
Here's what I did
CREATE OR REPLACE PROCEDURE grants AS
DECLARE
Cursor c IS select OBJECT_NAME as view_name from all_objects where object_type in ('VIEW');
BEGIN
FOR tmp in c
LOOP
EXECUTE IMMEDIATE 'GRANT ALL on ' || tmp.view_name || ' TO my_users';
END LOOP;
END;
But I'm getting an 'end-of-file' symbole encountered [...]' error...
Do you guys have an idea to make this procedure work ?
Remove DECLARE:
SQL> CREATE OR REPLACE PROCEDURE grants AS
2 CURSOR c IS
3 SELECT OBJECT_NAME AS view_name
4 FROM all_objects
5 WHERE object_type IN ('VIEW');
6 BEGIN
7 FOR tmp IN c
8 LOOP
9 EXECUTE IMMEDIATE 'GRANT ALL on ' || tmp.view_name || ' TO my_users';
10 END LOOP;
11 END;
12 /
Procedure created.
How to grant permission for a user to all tables and sequences in Oracle?
Tables:
BEGIN
FOR R IN (SELECT owner, table_name FROM all_tables WHERE owner='<<REPLACE_WITH_YOUR_SCHEMA>>') LOOP
EXECUTE IMMEDIATE 'grant select on '||R.owner||'.'||R.table_name||' to <<REPLACE_WITH_USER>>';
END LOOP;
END;
Sequences:
BEGIN
FOR R IN (SELECT sequence_owner, sequence_name FROM all_sequences WHERE sequence_owner='<<REPLACE_WITH_YOUR_SCHEMA>>') LOOP
EXECUTE IMMEDIATE 'grant select on '||R.sequence_owner||'.'||R.sequence_name||' to <<REPLACE_WITH_USER>>';
END LOOP;
END;
This query can be used to set the appropriate system privileges.
GRANT SELECT ANY TABLE TO SOMEUSERNAME;
GRANT SELECT ANY SEQUENCE TO SOMEUSERNAME;
More information can be found here:
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/GRANT.html#GUID-20B4E2C0-A7F8-4BC8-A5E8-BE61BDC41AC3