There are two users 'USER1' and 'USER2'.Mysql > create a function in 'USER2' that uses dynamic SQL to create a materialized view log for tableA. ORA-01031 error is reported.Insufficient permissions.
So I gave the following permissions to each user using the SYS user, but it didn't work.
GRANT CREATE TABLE TO USER1;
GRANT CREATE ANY TABLE TO USER1;
GRANT CREATE MATERIALIZED VIEW TO USER1;
GRANT CREATE ANY MATERIALIZED VIEW TO USER1;
GRANT CREATE TABLE TO USER2;
GRANT CREATE ANY TABLE TO USER2;
GRANT CREATE MATERIALIZED VIEW TO USER2;
GRANT CREATE ANY MATERIALIZED VIEW TO USER2;
function WriteLogInit() RETURN VARCHAR2 IS
TYPE i_cursor_type IS REF CURSOR;
my_cursor i_cursor_type;
v_ln number(5) := 0;
sqlstr VARCHAR2(3000);
begin
select count(1)
into v_ln
from ALL_MVIEW_LOGS
where master = upper('tableA')
and log_owner = upper('USER1');
if v_ln > 0 then
execute immediate 'drop materialized view log on USER1.tableA';
end if;
sqlstr := 'create materialized view log on USER1.tableA
with rowid,sequence including new values';
execute immediate sqlstr;
RETURN '1';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE || '---' || SQLERRM);
RAISE_APPLICATION_ERROR(-20012, 'ERROR:create materialized view log erroļ¼');
end;
The documentation says:
If you are creating a materialized view log for a table in another user's schema, then you must have the CREATE ANY TABLE and COMMENT ANY TABLE system privileges, as well as either the READ or SELECT object privilege on the master table or the READ ANY TABLE or SELECT ANY TABLE system privilege.
You haven't said that USER2 can already select from the table, but it's kind of implied. But in the privileges you've shown being added, you haven't included COMMENT ANY TABLE, so you can also run:
GRANT COMMENT ANY TABLE TO USER2;
Related
i have a trigger in different and want execute procedure for different schema to extract the data.
executing procedure with parameter in trigger is not working.
create or replace TRIGGER TRIGER_LEAD_INSERT
AFTER INSERT ON AT_NEO_CM.LEAD_INFORMATION
FOR EACH ROW
DECLARE
--PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF :new.LEAD_REFERENCE_NUMBER IS NOT NULL THEN
AT_NEO_CAS_LMS.PKG_LEAD_DATA.USP_INSERT_NEWAPP(:NEW.LEAD_REFERENCE_NUMBER,:NEW.ID );
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO LEADDATA VALUES( :NEW.ID, :NEW.LEAD_REFERENCE_NUMBER,2322, 'NO DATA FOUND');
END TRIGER_LEAD_INSERT;
Using a another table in procedure with same primary key which passed in procedure as parameter.
To call a procedure from another schema, you just need to set the right grants:
CREATE USER u1 IDENTIFIED BY u1 QUOTA 1M ON USERS;
CREATE USER u2 IDENTIFIED BY u2 QUOTA 1M ON USERS;
GRANT CONNECT, RESOURCE TO u1;
GRANT CONNECT, RESOURCE TO u2;
User u1 has a procedure p1 and grants it to user u2:
CREATE PROCEDURE p1(p NUMBER) AS BEGIN NULL; END p1;
GRANT EXECUTE ON p1 TO u2;
User u2 can now execute this procedure:
CONNECT u2/u2;
EXEC u1.p1(1);
or use it in a trigger:
CREATE TABLE t2 (id NUMBER);
CREATE OR REPLACE TRIGGER tr2 AFTER INSERT ON t2
FOR EACH ROW
BEGIN
IF :new.id IS NOT NULL THEN
u1.p1(:new.id);
END IF;
END tr2;
/
I have created a user (say DROP_PARTITION_USER) to drop partitions of a table. The table is owned by different user (say NORMAL_USER).
Currently, I have granted DROP ANY TABLE and ALTER ANY TABLE privileges to DROP_PARTITION_USER. When DROP_PARTITION_USER executes following statement, it gets executed successfully.
ALTER TABLE SCHEMANAME.TABLENAME DROP PARTITION <PARTITION_NAME> UPDATE GLOBAL INDEXES;
But, DROP ANY TABLE and ALTER ANY TABLE allows DROP_PARTITION_USER to drop and alter any table under any schema [https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9013.htm ].
Is there any way in Oracle to restrict drop and alter table under specific schema?
The common way to solve this is to create a procedure owned by NORMAL_USER to drop one of the partitions of one of it's tables.
Then you GRANT EXECUTE on this procedure to DROP_PARTITION_USER.
You'll need no extra privileges.
CREATE OR REPLACE PROCEDURE my_drop_partition (p_table_name VARCHAR2, p_partition_name VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE '||p_table_name||' DROP PARTITION '||p_partition_name;
END my_drop_partition;
/
GRANT EXECUTE ON my_drop_partition TO drop_partition_user;
You can use a DDL trigger to capture such attempts and take whatever action you like. For example
SQL> CREATE OR REPLACE TRIGGER STOP_THAT_STUFF
2 before create or alter or drop on database
3 begin
4 if ora_dict_obj_owner in ('SCOTT') and
5 ora_sysevent in ('DROP','ALTER') and
6 ora_dict_obj_name = 'MY_TABLE'
7 then
8 raise_application_error(-20000,'What the hell are you thinking!!!!');
9 end if;
10 end;
11 /
Trigger created.
SQL>
SQL> conn scott/tiger
Connected.
SQL> create table scott.my_table(x int );
Table created.
SQL> create table scott.my_other_table(x int);
Table created.
SQL> drop table my_other_table;
Table dropped.
SQL> drop table my_table;
drop table my_table
*
ERROR at line 1:
ORA-04088: error during execution of trigger 'SYS.STOP_THAT_STUFF'
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: What the hell are you thinking!!!!
ORA-06512: at line 6
SQL> desc my_table
Name Null? Type
----------------------------------------------------------------------- -------- ----------------
X NUMBER(38)
Is it possible to parameterize schema and table names used in queries within stored procedures using dynamic synonyms?
What we have tried is
setting parameters in a name/value pair table
reading those parameters at run time to determine schema (and table names), as the targets change based on the mode of the
application
dropping any existing synonym and recreating for the schema and tables
referencing the synonyms in the queries
The reason we are attempting this approach is because the queries to be executed are merge statements that are hundreds of lines long, not suited for dynamic SQL.
Maybe you can cover your problem when you use Invoker Rights for your procedure. Have a look at this example:
CREATE USER SCOTT_1 IDENTIFIED BY "tiger";
GRANT UNLIMITED TABLESPACE TO SCOTT_1;
CREATE USER SCOTT_2 IDENTIFIED BY "tiger";
GRANT UNLIMITED TABLESPACE TO SCOTT_2;
CREATE TABLE SCOTT_1.EMP (EMP_NAME VARCHAR2(30));
CREATE TABLE SCOTT_2.EMP (EMP_NAME VARCHAR2(30));
INSERT INTO SCOTT_1.EMP VALUES ('Schema 1');
INSERT INTO SCOTT_2.EMP VALUES ('Schema 2');
COMMIT;
CREATE SYNONYM EMP FOR SCOTT_1.EMP; -- Just needed to compile the procedure
CREATE OR REPLACE FUNCTION GetSchema(p_schema IN VARCHAR2) RETURN VARCHAR2
AUTHID CURRENT_USER
AS
res VARCHAR2(30);
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = ' || p_schema;
SELECT EMP_NAME
INTO res
FROM EMP;
-- Just switch back to own schema to avoid unexpected behaviors
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = '||USER;
RETURN res;
END;
/
SELECT GetSchema('SCOTT_1') FROM dual;
GETSCHEMA('SCOTT_1')
---------------------------------
Schema 1
1 row selected.
SELECT GetSchema('SCOTT_2') FROM dual;
GETSCHEMA('SCOTT_2')
---------------------------------
Schema 2
1 row selected.
I've a stored procedure created by EMP_DBA and part of the query will check whether the existing tables exist or not, if exist then drop table. This query works fine if I connect as EMP_DBA, now I want to run this stored procedure with other account let say USER1 and I've grant all the necessary rights to USER1. How to rewrite below statement in order count return 1 if the table MARKET_DATA exist in schema EMP_DBA ?
BEGIN
SELECT COUNT(*) INTO c
FROM all_tables
WHERE
table_name = 'MARKET_DATA' AND OWNER = 'EMP_DBA';
IF C = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE MARKET_DATA';
--exception when others then null;
END IF;
"I've grant all the necessary rights to USER1"
This is a slightly worrying statement. What do you mean by all the necessary rights ? The only appropriate right is execute on a stored procedure owned by EMP_DBA. That procedure should encapsulate everything. EMP_DBA doesn't (or shouldn't) want USER1to drop their tables independently. Besides it isn't possible to grant DDL statements on specific objects, or even specific schemas. And DROP ANY is a powerful privilege to hand out.
The best way to write the stored procedure is to use definer's rights (which is the default). This ensures that the code is executed with the privileges of the stored procedure's owner, not those of the executing user. That your code doesn't work - presumably because you haven't specified the table owner - suggests you haven't got your security model quite right.
In my version I've used ALL_TABLES just like you did, to show the difference between CURRENT_USER and SESSION_USER, but actually USER_TABLES would work just as well.
create or replace procedure recreate_tab
(p_tab_name in all_tables.table_name%type)
authid definer
is
n pls_integer;
begin
select count(*)
into n
from all_tables
where owner = (sys_context('userenv','current_user'))
and table_name = p_tab_name;
if n = 1
then
-- no need to specify schema because it's the procedure owner
execute immediate 'drop table '|| p_tab_name;
end if;
execute immediate 'create table '||p_tab_name
||' ( id number, descr varchar2(30))';
-- grant rights on the new table to the user executing the procedure
execute immediate 'grant select on '||p_tab_name||' to '
|| sys_context('userenv','session_user');
end recreate_tab;
/
grant execute on recreate_tab to user1
/
So. Nothing up my sleeve ...
SQL> conn user1/user1
Connected.
SQL> select count(*) from t42
2 /
select count(*) from t42
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select count(*) from emp_dba.t42
2 /
COUNT(*)
----------
56179
SQL> exec emp_dba.recreate_tab('T42')
PL/SQL procedure successfully completed.
SQL> select count(*) from emp_dba.t42
2 /
COUNT(*)
----------
0
SQL>
Your select is correct. You should rewrite the EXECUTE IMMEDIATE to do
DROP TABLE EMP_DBA.MARKET_DATA
I've got a lot of tables in a tablespace, nearly 100. I have to grant Select, Insert, Update privileges on all those tables to a user. Is it possible? When I write:
GRANT USE OF TABLESPACE MYTABLESPACE TO USERNAME
I get oracle error "invalid or missing privilege"
USE OF TABLESPACE is not a documented option, where did you find that?
You can do this to allow a user to create objects in a tablespace:
alter user username quota [amount] on mytablespace;
To grant select, insert, update and delete on objects you have to run a separate grant command for each table:
grant select, insert, update, delete on mytable1 to username;
....
Use the data dictionary view dba_tables (resp. all_tables, if you cannot access dba_tables):
declare
l_SQL varchar2(4000);
begin
for cur in (
select * from dba_tables where tablespace_name = 'mytablespace')
loop
l_sql := 'grant select, insert, update on ' || cur.owner || '.' || cur.table_name || ' to myuser';
--dbms_output.put_line(l_SQL || ';');
execute immediate l_SQL;
end loop;
end;
If you just want to generate a script, comment out the execute immediate and un-comment the dbms_output.