switching user session in pl/sql script - sql

set serveroutput on;
declare
username1 varchar2(40);
cnt number;
hello varchar2(20);
c sys_refcursor;
begin
select sys_context('userenv','session_user') into username1 from dual;
select lower(username1) into username1 from dual;
select count(lower(username)) into cnt from karuna.tableusers where lower(username)=username1;
if cnt=1 then
dbms_output.put_line('username found');
execute immediate 'connect karuna/password ';
open c for 'select item_name from sells12 where item_id=12';
fetch c into hello;
dbms_output.put_line(hello);
close c;
else
dbms_output.put_line('u dont have previllege to access database');
----raise_application_error(-20001,'error out');
end if;
end;
/
I want to switch session user but I am getting error at connect karuna/karuna line

Look at Oracle's feature n-tier (proxy) authentication. Maybe it's not what you need. Oracle offers you:
n-tier auth
set role statement (to get more privs. from password "protected" roles)
alter session set current_schema=KARUMA. This will not switch your username/privs but the default schema.
The right choice really depends on your needs.

you have to give dba privilege to connect from your user to KARUMA user or CONNECT privilege.
please follow this link
http://docs.oracle.com/cd/B28359_01/java.111/b31224/proxya.htm

Related

Oracle: grant to role if role exists

How to execute
GRANT SELECT ON <ownschema>.<sometable> TO <somerole>;
but backing off gracefully if somerole does not exist. The user executing the statement is a standard user (think SCOTT) without any special privileges.
Version: Oracle Database 19 or later
I don't think you can.
If you're running it at SQL level, then Oracle will raise an error if role doesn't exist.
If you want to check whether it exists, you'll need some kind of a PL/SQL procedure (which is not a problem), but - DBA should grant you select privilege on dba_roles so that you could check it. Then, if it exists, you'd grant that privilege; otherwise, return some kind of an information (dbms_output.put_line in my example is pretty much stupid; it wouldn't be visible out of SQL*Plus, SQL Developer, TOAD and similar), but you got the idea, I hope.
Something like this:
create or replace procedure p_grant_to_role (par_role in varchar2) is
l_cnt number;
begin
select count(*)
into l_cnt
from dba_roles
where role_name = par_role;
if l_cnt > 0 then
execute immediate 'grant select on emp to ' || par_role;
else
dbms_output.put_line('Role does not exist');
end if;
end;
/
It all depends on the tool, but you can do something like this (very crude as usually you should have better exception handling):
begin
execute immediate 'grant .....';
exception
when others then null;
end;

How to listed all the tables of a User in a database? n

Hi so i have the following plan :
i want to Write a script, which calls another script. A parameter V_USERNAME should be passed from the 1st script to the 2nd script.( Using the keyword DEFINE)
My code look like :
##C:\Users\pe.k\Documents\script2.sql &p_v_username
set serveroutput on
define p_v_username = "user";
In the 2nd script all tables of the user should be output. (Using the key word EXECUTE IMMEDIATE and a cursor).
The output control is to be done via a parameter in the script or when calling the script.
Example call:
SQL> #start_script1 MML
declare
&p_v_username varchar2(100);
v_result varchar2(100);
cursor cp_username (&p_v_username varchar2)
is
select owner, table_name
from all_tables
where owner = &p_v_username
order by owner, table_name;
begin
dbms_output.put_line('Alle Tabellen der User'); --l_username);
open cp_username(&p_v_username);
--loop
--fetch cp_username into v_result;
-- dbms_output.put_line(v_result);
--end loop;
close cp_username;
end;
/
And i have the errors and i am lost. I dont know how to do it
Your second procedure should be something like this:
BEGIN
DBMS_OUTPUT.PUT_LINE('Alle Tabellen der User'); --l_username);
FOR TABS IN (
SELECT OWNER, TABLE_NAME
FROM ALL_TABLES
WHERE OWNER = '&P_V_USERNAME'
ORDER BY OWNER, TABLE_NAME
) LOOP
DBMS_OUTPUT.PUT_LINE(TABS.TABLE_NAME);
END LOOP;
END;
/
In order to print the output generated by the DBMS_OUTPUT package from PL/SQL, make sure to set serveroutput on

How to get user of a schema with sql/plsql

I am login with a user abc in a database xyz with Oracle SQL Developer. How can I get the usernames of the schema through which I am logged in?
I believe by usernames you mean operating system usernames. Username in Oracle database (and SQL Developer), is a synonym to the schema name.
So in your case, your schema called abc. Now assume your operating system username is 'John', and you want to know other users who are connected to the schema 'abc', then you can run the query:
SELECT osuser
FROM v$session
WHERE schemaname = 'abc';
Refer to this post for more details
If you just want to know the list of users in the schema you are in, try this:
SELECT * FROM all_users
If you do not change current schema the following code will be fine:
-- In PLSQL
DECLARE
vv_SchemaName VARCHAR2(100);
BEGIN
vv_SchemaName := Sys_Context('USERENV','CURRENT_SCHEMA');
dbms_output.put_line(vv_SchemaName);
END;
-- IN SQL
SELECT Sys_Context('USERENV','CURRENT_SCHEMA') FROM DUAL
Current_schema is a bit different from LOGGED USER see the example:
-- The output will be:
-- Current schema:LOGGED_SCHEMA session user:LOGGED_SCHEMA
-- Current schema:CHANGED_SCHEMA session user:LOGGED_SCHEMA
-- When you are connected to LOGGED_SCHEMA and have CHANGED_SCHEMA.
DECLARE
vv_SchemaName VARCHAR2(100);
vv_SessionUser VARCHAR2(100);
BEGIN
vv_SchemaName := Sys_Context('USERENV','CURRENT_SCHEMA');
vv_SessionUser := Sys_Context('USERENV','SESSION_USER' );
dbms_output.put_line('Current schema:' || vv_SchemaName || ' session user:' || vv_SessionUser);
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA=CHANGED_SCHEMA';
vv_SchemaName := Sys_Context('USERENV','CURRENT_SCHEMA');
vv_SessionUser := Sys_Context('USERENV','SESSION_USER' );
dbms_output.put_line('Current schema:' || vv_SchemaName || ' session user:' || vv_SessionUser);
END;
So If you plan to connect to one user and work on another one than depending on your needs using Sys_Context('USERENV','SESSION_USER' ) may be a better option.

Create or replace role?

How do you create or replace a role (that might or might not exist) in Oracle? For example, the following does not work:
CREATE OR REPLACE ROLE role_name;
GRANT SELECT ON SCM1_VIEW_OBJECT_VW TO role_name;
Any way to do this without PL/SQL?
Solution
A combination of the given answers and a pragma control accomplishes this task for Oracle 10g.
CREATE OR REPLACE PROCEDURE create_role( role_name IN VARCHAR2 ) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'CREATE ROLE '||role_name;
EXCEPTION
WHEN OTHERS THEN
-- ORA-01921: If The role name exists, ignore the error.
IF SQLCODE <> -01921 THEN
RAISE;
END IF;
END create_role;
Test
This sequence works:
DROP ROLE role_name;
CREATE ROLE role_name;
CALL create_role( 'role_name' );
CALL create_role( 'role_name' );
The final create role statement fails, as expected:
DROP ROLE role_name;
CALL create_role( 'role_name' );
CREATE ROLE role_name;
Best practice is to attempt the creation of the role, then handle the appropriate exception gracefully if it occurs; this means you don't need to run potentially expensive data dictionary queries:
begin
execute immediate 'create role role_name';
exception
when others then
--"ORA-01921: role name 'x' conflicts with another user or role name"
if sqlcode = -01921 then
null;
else
raise;
end if;
end;
And yes, you need PL/SQL to do this - it's the best tool for this job, anyway.
DECLARE
v_dummy NUMBER;
BEGIN
SELECT 1
INTO v_dummy
FROM dba_roles
WHERE role = 'MY_ROLE_NAME';
EXCEPTION
WHEN no_data_found THEN
EXECUTE IMMEDIATE 'CREATE ROLE my_role_name';
END;
/
There is no syntax for "create or replace" for roles. Not sure of your version of Oracle but this hasn't changed much that I can recall. http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_6012.htm
You can grant select to the role multiple times and it will accept the grant every time provided the role exists.
You could do an anonymous block and ignore the execption if the role already exists or something else where you see if the role exists by querying DBA_ROLES.

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 :)