Grant read access using for loop - sql

QUERY
BEGIN
FOR R IN (SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = 'ONAME')
LOOP
GRANT SELECT ON R.TABLE_NAME TO UNAME;
END LOOP;
END;
/
I want to grant read access of tables in ONAME to UNAME. But, I've the following errors:
PLS-00103: Encountered the symbol "GRANT" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with
<<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
Please help me. Thanks in advance.

In Oracle, you can't do any DDL statements directly in PL/SQL. You have to use EXECUTE IMMEDIATE to execute them, e.g.:
FOR R IN (SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = 'ONAME')
LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON '||R.TABLE_NAME||' TO UNAME';
END LOOP;

Related

Grant all on procedures to user

When i execute the following Statement by substituting object_type to table [OBJECT_TYPE='TABLE'], it executes successfully, by when i try it to procedure like the following, it returns error: table or view does not exit.
BEGIN
FOR R IN (SELECT OWNER, OBJECT_NAME FROM ALL_OBJECTS WHERE owner = 'MY_SCHEMA' AND OBJECT_TYPE='PROCEDURE') LOOP
execute IMMEDIATE 'GRANT ALL ON '|| R.OWNER ||'.'||R.OBJECT_NAME ||' TO MyUser';
END LOOP;
END;
Note: when i also try to execute as single statement it runs successfully.
GRANT ALL ON MY_SCHEMA.ProcedureName TO MyUser;
So what is difference, and why does not work on procedures.
try to show all the statements and then run all of them. one of it will definitely give you that error!
Try this:
SET serveroutput ON;
DECLARE
v_sql VARCHAR2(4000);
BEGIN
FOR R IN
(SELECT OWNER,
OBJECT_NAME
FROM ALL_OBJECTS
WHERE owner = 'MY_SCHEMA'
AND OBJECT_TYPE='PROCEDURE'
)
LOOP
v_sql:= 'GRANT ALL ON '|| R.OWNER ||'.'||R.OBJECT_NAME ||' TO MyUser';
dbms_output.put_line(v_sql);
END LOOP;
END;
and then run all those statements, in order to find the exact statement that gives you error.

Oracle SQL - If Exists, Drop Table & Create

Can some one please guide me what's wrong with this query? In SQL Server we just check the presence of the Object_ID of a table to drop it and re-create it. I am new to Oracle and wrote this query:
declare Table_exists INTEGER;
BEGIN
Select count(*) into Table_exists from sys.all_tables where table_name='TABLENAME1';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
Table_Exists :=0;
if(table_exists)=1
Then
Execute Immediate 'Drop Table TABLENAME1;'
'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;
I get the output - ANONYMOUS BLOCK COMPLETED, but the table is not created. The table was previously existing, so I dropped it to check if the PL/SQL is actually creating the table, but NO. What is wrong here? What am I missing? Please guide.
When you are using all_tables filter the results for your
schema by adding where owner = 'your_schema'
or use sys.user_tables
ALL_TABLES describes the relational tables accessible to the current user
USER_TABLES describes the relational tables owned by the current user.
When use execute_emmidiate remove the ; from the query;
Modified query;
DECLARE
Table_exists INTEGER;
BEGIN
Select count(*) into Table_exists from sys.user_tables where table_name='TABLENAME1';
--or
--Select count(*) into Table_exists from sys.all_tables
--where table_name='TABLENAME1' and owner = 'your_DB';
if table_exists = 1 Then
Execute Immediate 'Drop Table TABLENAME1';
Execute Immediate 'Create Table TABLENAME1(num number)';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1(num number)';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;
First note:
Select count(*) into Table_exists
from sys.all_tables
where table_name = 'TABLENAME1';
will always return one row. You don't need the exception handling.
My best guess is that you have more than one table called TABLENAME1. Run this query to find out:
Select *
from sys.all_tables
where table_name = 'TABLENAME1';
Oracle stores tables from all owners that you can access. You might also want to check OWNER_NAME in the where clause.
However, you seem to understand exception handling. So, just drop the table, ignore any errors, and then recreate the table.
The EXCEPTION clause lasts till the next END and not just the next statement. If you want to continue after catching the exception you need to add an additional BEGIN/END:
declare
Table_exists INTEGER;
BEGIN
BEGIN
Select count(*) into Table_exists from sys.all_tables where table_name='TABLENAME1';
EXCEPTION
WHEN NO_DATA_FOUND THEN
Table_Exists :=0;
END;
if(table_exists)=1 Then
Execute Immediate 'Drop Table TABLENAME1;'
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;
As pointed out by Gordon, the EXCEPTION clause is not really needed in this case since count(*) will always return one row. So the following is sufficient:
declare
Table_exists INTEGER;
BEGIN
Select count(*) into Table_exists from sys.all_tables where table_name='TABLENAME1';
if(table_exists)=1 Then
Execute Immediate 'Drop Table TABLENAME1;'
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;

How do I pass user login name to a function and delete that user from database in oracle

Here is the code:
create or replace procedure getuser(User_ID In VARCHAR2)Is
Username varchar2(30);
cursor c1(Userid VARCHAR2) --Cursor o store the row
IS SELECT USERNAME FROM ALL_USERS WHERE USERNAME = Userid;
BEGIN
Open c1(User_id);
loop
FETCH c1 INTO USERNAME;
EXIT WHEN C1%NOTFOUND;
END LOOP;
execute immediate 'drop' || USERNAME;
CLOSE c1;
END;
/
execute system.getuser('STUDENT_0602053');
the error that am getting is invalid sql statement when i execute the stored procedure
execute system.getuser('STUDENT_0602053');
It should be
EXECUTE IMMEDIATE 'drop user '||username;
You may also want:
EXECUTE IMMEDIATE 'drop user '||username||' cascade';
Or the user won't be dropped if they own any objects.
Also, are you logged in as the user SYSTEM?
just a guess - there might be more issues...
but this line needs a space..
execute immediate 'drop' || USERNAME;
should be
execute immediate 'drop ' || USERNAME;

ORA-00933: SQL command not properly ended

I'm getting this error in Oracle:
ORA-00933: SQL command not properly ended
for
DROP SEQUENCE IF EXISTS ownername.seq_name;
Why am I seeing this?
the IF EXISTS clause doesn't exist in the DROP SEQUENCE command in Oracle.
You could use a PLSQL block to ignore the error:
SQL> DECLARE
2 sequence_doesnt_exist EXCEPTION;
3 PRAGMA EXCEPTION_INIT(sequence_doesnt_exist, -2289);
4 BEGIN
5 EXECUTE IMMEDIATE 'DROP SEQUENCE seq_name';
6 EXCEPTION
7 WHEN sequence_doesnt_exist THEN NULL;
8 END;
9 /
PL/SQL procedure successfully completed
The problem is "if exists" does not work in Oracle. Use:
drop sequence ownername.seq_name;
As others mentioned, the IF EXISTS doesn't work on the DROP SEQUENCE command.
To test for the existence of a sequence, you need to check the appropriate view:
USER_SEQUENCES
SELECT *
FROM USER_SEQUENCES
WHERE sequence_name = ?
DBA_SEQUENCES
SELECT *
FROM DBA_SEQUENCES
WHERE sequence_name = ?
ALL_SEQUENCES
SELECT *
FROM ALL_SEQUENCES
WHERE sequence_name = ?
Example:
BEGIN
FOR i IN (SELECT sequence_name
FROM USER_SEQUENCES
WHERE sequence_name = ?)
LOOP
EXECUTE IMMEDIATE ('DROP SEQUENCE '|| i.sequence_name);
END LOOP;
END;
Try this:
DECLARE
iNum NUMBER DEFAULT 0;
BEGIN
SELECT COUNT(1)
INTO iNum
FROM ALL_SEQUENCES
WHERE SEQUENCE_OWNER='<OWNER_NAME>'
AND SEQUENCE_NAME = '<YOUR_SEQUENCE_NAME>';
IF iNum> 0 THEN
EXECUTE IMMEDIATE 'DROP SEQUENCE <OWNER_NAME>.<YOUR_SEQUENCE_NAME>';
END IF;
END;

Execute Immediate within a stored procedure keeps giving insufficient priviliges error

Here is the definition of the stored procedure:
CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR) IS
BEGIN
DECLARE v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM all_tables
WHERE owner = schema
AND table_name = tblToDrop;
IF v_cnt > 0 THEN
EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
END IF;
END;
END;
Here is the call:
CALL usp_dropTable('SOMESCHEMA', 'SOME_TABLE');
For some reason, I keep getting insufficient privileges error for the EXECUTE IMMEDIATE command. I looked online and found out that the insufficient privileges error usually means the oracle user account does not have privileges for the command used in the query that is passes, which in this case is DROP. However, I have drop privileges. I am really confused and I can't seem to find a solution that works for me.
Thanks to you in advance.
SOLUTION:
As Steve mentioned below, Oracle security model is weird in that it needs to know explicitly somewhere in the procedure what kind of privileges to use. The way to let Oracle know that is to use AUTHID keyword in the CREATE OR REPLACE statement. If you want the same level of privileges as the creator of the procedure, you use AUTHID DEFINER. If you want Oracle to use the privileges of the user currently running the stored procedure, you want to use AUTHID CURRENT_USER. The procedure declaration looks as follows:
CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR)
AUTHID CURRENT_USER IS
BEGIN
DECLARE v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM all_tables
WHERE owner = schema
AND table_name = tblToDrop;
IF v_cnt > 0 THEN
EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
END IF;
END;
END;
Thank you everyone for responding. This was definitely very annoying problem to get to the solution.
Oracle's security model is such that when executing dynamic SQL using Execute Immediate (inside the context of a PL/SQL block or procedure), the user does not have privileges to objects or commands that are granted via role membership. Your user likely has "DBA" role or something similar. You must explicitly grant "drop table" permissions to this user. The same would apply if you were trying to select from tables in another schema (such as sys or system) - you would need to grant explicit SELECT privileges on that table to this user.
You should use this example with AUTHID CURRENT_USER :
CREATE OR REPLACE PROCEDURE Create_sequence_for_tab (VAR_TAB_NAME IN VARCHAR2)
AUTHID CURRENT_USER
IS
SEQ_NAME VARCHAR2 (100);
FINAL_QUERY VARCHAR2 (100);
COUNT_NUMBER NUMBER := 0;
cur_id NUMBER;
BEGIN
SEQ_NAME := 'SEQ_' || VAR_TAB_NAME;
SELECT COUNT (*)
INTO COUNT_NUMBER
FROM USER_SEQUENCES
WHERE SEQUENCE_NAME = SEQ_NAME;
DBMS_OUTPUT.PUT_LINE (SEQ_NAME || '>' || COUNT_NUMBER);
IF COUNT_NUMBER = 0
THEN
--DBMS_OUTPUT.PUT_LINE('DROP SEQUENCE ' || SEQ_NAME);
-- EXECUTE IMMEDIATE 'DROP SEQUENCE ' || SEQ_NAME;
-- ELSE
SELECT 'CREATE SEQUENCE COMPTABILITE.' || SEQ_NAME || ' START WITH ' || ROUND (DBMS_RANDOM.VALUE (100000000000, 999999999999), 0) || ' INCREMENT BY 1'
INTO FINAL_QUERY
FROM DUAL;
DBMS_OUTPUT.PUT_LINE (FINAL_QUERY);
cur_id := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.parse (cur_id, FINAL_QUERY, DBMS_SQL.v7);
DBMS_SQL.CLOSE_CURSOR (cur_id);
-- EXECUTE IMMEDIATE FINAL_QUERY;
END IF;
COMMIT;
END;
/
you could use "AUTHID CURRENT_USER" in body of your procedure definition for your requirements.
Alternatively you can grant the user DROP_ANY_TABLE privilege if need be and the procedure will run as is without the need for any alteration. Dangerous maybe but depends what you're doing :)