Calling other user In procedure Body of one User - oracle

I am using following Query in Oracle 11g Procedures
Open cur_Test FOR
'''Select * from '|| DBUSER ||'.table_name''';
Its raising an error 'Invalid SQL Statement.'
Can we call other user's table in any user's package or procedure?

It should be like this:
Open cur_Test FOR
'Select * from '|| DBUSER ||'.table_name';
Of course you need to have select grants on that table...

Related

Error trying to use %ROWTYPE to table in a different schema in Oracle PL/SQL

I'm trying to write an Oracle PL/SQL function similar to
create or replace function fn1(p_id in number) return number is
crec otheruser.thetable%rowtype;
begin
...
end;
but I get an error saying "Identifier 'OTHERUSER.THEABLE' must be declared". This same construct works fine if I login as otheruser. I'm able to select * from otheruser.thetable so it seems to me that my account can see the table just fine. I'm thinking it's a grant issue but I don't know what it could be.
You need to either use:
GRANT SELECT ON OtherUser.TheTable TO ThisUser;
Then you can use ROWTYPE directly in ThisUser session:
DECLARE
a_row OtherUser.TheTable%ROWTYPE;
BEGIN
NULL;
END;
/
But the ThisUser will also be able to select all the data from OtherUser.TheTable.
Or, if you do not want to grant the SELECT privilege you can create a package and grant on that:
CREATE PACKAGE OtherUser.TheTable_Pkg
AS
SUBTYPE TheTable_RowType IS OtherUser.TheTable%ROWTYPE;
END;
/
GRANT EXECUTE ON OtherUser.TheTable_Pkg TO ThisUser;
Then you can do, as ThisUser:
DECLARE
a_row OtherUser.TheTable_Pkg.TheTable_RowType;
BEGIN
NULL;
END;
/
And the type can be used but the data in the table is still inaccessible.

GRANT SELECT doesn't work in altered session

I have the following situation. I need to write a procedure to give one schema access to object of the other one. The thing is that this procedure is being executed by administrative account via flyway.
I tried numerous options, but face the following:
Error starting at line : 3 in command - (my begin...end procedure)
Error report -
ORA-00942: table or view does not exist
ORA-06512: at line 3
00942. 00000 - "table or view does not exist"
My code:
ALTER SESSION SET CURRENT_SCHEMA = AppUser;
BEGIN
FOR R IN (SELECT owner, table_name FROM dba_tables WHERE owner='AppUser') LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON '||R.owner||'.'||R.table_name||' TO QAUser';
END LOOP;
END;
Neither it works w/o altering schema.
You owner is AppUser in mixed case. As such, you will need to quote it when using it in statements, otherwise Oracle will convert it to uppercase.
So you could try this:
ALTER SESSION SET CURRENT_SCHEMA = AppUser;
BEGIN
FOR R IN (SELECT owner, table_name FROM dba_tables WHERE owner='AppUser') LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON "'||R.owner||'"."'||R.table_name||'" TO "QAUser"';
END LOOP;
END;
See Oracle: What exactly do quotation marks around the table name do?

Creating an Oracle User if it doesn't already exist

I am trying to create a script that will create users if they do not already exist.
CREATE USER "Kyle" PROFILE "DEFAULT" IDENTIFIED BY "password" ACCOUNT UNLOCK
WHERE NOT IN //Also tried 'WHERE NOT EXISTS'
(
SELECT username FROM all_users WHERE username = 'Kyle'
)
The following error is given:
SQL Error: ORA-00922: missing or invalid option
I was able to do this in SQL Server 2008 by using:
IF NOT EXISTS
(SELECT name FROM master.sys.server_principals
WHERE name = 'Kyle')
BEGIN
CREATE LOGIN Kyle WITH PASSWORD = 'temppassword' MUST_CHANGE, CHECK_EXPIRATION=ON, CHECK_POLICY=ON
END
Is there a similar way in Oracle to check if a user already exists before attempting to create a new user?
The IF NOT EXISTS syntax available in SQL Server, is not available in Oracle.
In general, Oracle scripts simply execute the CREATE statement, and if the object already exist, you'll get an error indicating that, which you can ignore. This is what all the standard Oracle deployment scripts do.
However, if you really want to check for existence, and only execute if object doesn't exist, thereby avoiding the error, you can code a PL/SQL block. Write a SQL that checks for user existence, and if it doesn't exist, use EXECUTE IMMEDIATE to do CREATE USER from the PL/SQL block.
An example of such a PL/SQL block might be:
declare
userexist integer;
begin
select count(*) into userexist from dba_users where username='SMITH';
if (userexist = 0) then
execute immediate 'create user smith identified by smith';
end if;
end;
/
You need to write a pl/sql block. See an example here
You can check if the user exists in the all_users table using some pl/sql code like:
SELECT count(*) INTO v_count_user
FROM all_users
WHERE username = 'Kyle'
and then use v_count_user in an IF condition to conditionally execute the create user statement.
From the previous answers, it is clear that if not exists is not supported in Oracle. To clarify which error(s) are thrown by Oracle when attempting to create an already existing user (and as a bonus, when attempting to drop a non existing user):
drop user foo;
ORA-01918: user 'foo' does not exist
create user existing_user IDENTIFIED BY existing_user;
ORA-01920: user name 'existing_user' conflicts with another user or role name
The statements above were executed on Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
Another way to do it is to create the user in a PL/SQL block and catch the ORA-01920 error. That way, the block does not throw any errors when the user exists.
DECLARE
sqlStatement varchar2(512);
user_exists EXCEPTION;
PRAGMA EXCEPTION_INIT(user_exists, -1920);
BEGIN
sqlStatement := 'CREATE USER "Kyle" ' ||
'IDENTIFIED BY "password" ' ||
'PROFILE "Default" ' ||
'ACCOUNT UNLOCK';
EXECUTE IMMEDIATE sqlStatement;
dbms_output.put_line(' OK: ' || sqlStatement);
EXCEPTION
WHEN user_exists THEN
dbms_output.put_line('WARN: ' || sqlStatement);
dbms_output.put_line('Already exists');
WHEN OTHERS THEN
dbms_output.put_line('FAIL: ' || sqlStatement);
RAISE;
END;
/

Procedure being created but doesn't work

DECLARE
BEGIN
FOR s IN ( SELECT first_name
FROM EA_marketing_table
WHERE town = 'LONDON'
)
LOOP
EXECUTE IMMEDIATE 'CREATE USER ' ||(s.first_name)|| ' IDENTIFIED BY LOL';
dbms_output.put_line (s.first_name || ' IDENTIFIED BY LOL');
END LOOP;
END;
/
I am trying to create a user and the code above lets me create a user but when I try to create a procedure it wont work.
This is the new code
CREATE OR REPLACE PROCEDURE proc_it_development AS
first_name VARCHAR2 (25);
BEGIN
FOR r IN ( SELECT first_name
FROM EA_marketing_table
WHERE town = 'lONDON ')
LOOP
EXECUTE IMMEDIATE 'CREATE USER '||(r.first_name)|| ' IDENTIFIED BY POOP ';
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line ('r SELECT...INTO did not return any row.');
END;
/
any help please?
:)
Roles are not enabled in procedures/packages so you need to get the privilege granted to your user directly. Most likely you are connecting through a user that has been given the CREATE USER privilege via a role (eg: the DBA role?)
To see what you can do in a procedure, you can disable the active roles for your current session:
set role none
then try your first code block. If it works, it will also work in a procedure.
To create a new schema with a procedure you will need the privilege granted directly to your schema:
GRANT CREATE USER TO <your_schema>;
You should enclose the password in double-quotes, in Oracle 11 passwords are case-sensitive by default. Then you only create a user without any privilege, i.e.CREATE SESSION Privilege is missing.

Check whether a tables exist or not on another schema - ORACLE DB

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

Resources