PL/SQL Procedures to create and drop tables - plsql

I run a procedure to Drop and re-create a table by using PL/SQL but it dosn't work and the table have no update on it .. the script below :
CREATE OR REPLACE procedure RUBA.pay_backup
as
r_create_table varchar(1000);
Begin
Begin
r_create_table := 'Drop table payment_backup';
Execute Immediate r_create_table;
Exception
When Others Then
Null;
End;
r_create_table := 'Create Table payment_backup as Select * from payment_table';
Execute Immediate r_create_table;
End;
/

The challenge here is that you are dealing with the security model of Oracle that normally requires direct grants vs. via a role when running in the context of a compiled PL/SQL procedure.
You are likely seeing ORA-01031: insufficient privileges.
Your user probably has CREATE TABLE granted via a role, but not directly.
Check this as follows:
-- List system privs granted via a role
select * from ROLE_SYS_PRIVS where ROLE in (select ROLE from USER_ROLE_PRIVS)
/
-- List system privs granted directly
select * from USER_SYS_PRIVS
/
There are two simple ways to make your procedure work:
Option 1
Grant CREATE TABLE directly to your user.
Connect as a DBA and do this:
GRANT CREATE TABLE TO RUBA;
Unfortunately, this is a bit of a blunt instrument and probably not what you want to do.
Option 2
Create your procedure with invoker's rights:
CREATE OR REPLACE procedure RUBA.pay_backup AUTHID CURRENT_USER
as
r_create_table varchar(1000);
Begin
Begin
r_create_table := 'Drop table payment_backup';
Execute Immediate r_create_table;
Exception
When Others Then
Null;
End;
r_create_table := 'Create Table payment_backup as Select * from payment_table';
Execute Immediate r_create_table;
End;
/
Do some experimentation to see how things behave with this version.
Note that you may run into issues if you are running this in a job or when connecting as a different user.

Related

Query outside of the transaction scope - Oracle

Is it possible to have insert statement outside of the scope of a transaction in a Stored Proc?
So there is a stored proc that writes some inserts, as part of a transaction
The reason for this is to write to Audit table and keep the audit records even if the stored proc fails or gets an exception
clarification, sorry if it was not clear, I am writing multiple audits for each action of the procedure so I can keep track what it did and what failed. not just a single Audit when there is an exception...
CREATE OR REPLACE PROCEDURE sampleProc
IS
BEGIN
start a transaction
INSERT to table 1
write to audit table about insert 1
INSERT to table 2
write to audit table about insert 2
INSERT to table 3
write to audit table about insert 3
INSERT to table 4
write to audit table about insert 4
if there is an exception - rollback except audit
all ok? commit.
END;
/
Yes, there is an option to perform actions in a separate transaction running simulteneously with your main one. See detail here
Example:
create table logs(creation_date date default sysdate, msg varchar2(4000));
create or replace procedure log_proc(sMessage varchar2)
is
pragma autonomous_transaction;
begin
insert into logs(msg)
values(sMessage);
commit; -- don't forget to commit in this separate transaction
end;
/
begin
log_proc('some message');
rollback;
end;
/
select * from logs
What you're after is PRAGMA AUTONOMOUS_TRANSACTION, which kicks off the module using it in a separate session.
Your code would be something like:
CREATE OR REPLACE PROCEDURE sample_proc
AS
procedure audit_insert (<params>)
is
pragma autonomous_transaction;
begin
<log details>
commit;
end audit_insert;
BEGIN
<INSERT to table 1>;
audit_insert(...);
<INSERT to table 2>;
audit_insert(...);
...
EXCEPTION
when others then
rollback;
raise;
END sample_proc;
/
Doing it like this would mean your audit details would be saved regardless of whether the calling code succeeds or fails.
N.B. I've created the audit_insert as a sub procedure of sample_proc. You would do better to have the code as individual procedures inside a package, rather than as one or more procedures.

What permissions are needed for PLSQL execute immediate drop index

I have a standard DB procedure to drop indexes on a table (code below) created in user1 schema. When run as user2 the "execute immediate 'drop index" fails with ORA-01418: specified index does not exist.
I don't understand how the index can be returned by the cursor, but not exist when the drop command is run.
Can someone help explain the privs user2 needs on the user1 table/indexes and what AUTHID should be used?
create or replace procedure dropIndexes(pTableName IN VARCHAR2) AUTHID
CURRENT_USER IS
CURSOR c1(pTableName VARCHAR2) IS
select index_name
from all_indexes
where table_name = pTableName;
BEGIN
FOR c1Rec IN c1(pTableName) LOOP
execute immediate 'drop index user1.'||c1Rec.index_name;
END LOOP;
END dropIndexes;
I wonder why not construct the SQL using the owner field of all_indexes. Better yet, push user1 into the query so we only get the index names that belong to user1.

bind variable substitution in oracle

The below simple procedure is suppose to provide grants to the user scott in oracle.
The value for &scott_SCHEMA is already defined in a seperate file(define_variable.sql) and the value is getting substituted correctly, but im getting the error(as specified in the bottom of the script), a help is much appreciated.
SET SERVEROUTPUT ON
declare
l_sql varchar2(3200);
begin
for i in ( select table_name as oname,'TABLE' as type from all_tables where owner='HR' AND table_name not like 'BIN$%' union all select view_name as oname,'VIEW' as type from all_views where owner='HR' and view_name not like 'BIN$%' )
loop
if i.type = 'TABLE' then
dbms_output.put_line(l_sql);
l_sql:= 'grant select,insert,update,delete on hr.'||i.oname||' to :owner with grant option';
execute immediate l_sql using '&scott_SCHEMA';
else
l_sql:= 'grant select on hr.'||i.oname||' to :owner with grant option';
end if;
end loop;
end;
/
*declare
*
ERROR at line 1:
ORA-00987: missing or invalid username(s)
ORA-06512: at line 12*
You can't use bind variables in place of identifiers (specifically schema or object names) in DDL or DML statements, they can only be used in place of value expressions.
Since you're using substitution variables, you could just place it in the sql statement itself:
l_sql:= 'grant select,insert,update,delete on hr.'||i.oname||' to &scott_SCHEMA with grant option';
and execute it with out passing it as a parameter:
execute immediate l_sql;
On a side note, your DBMS_OUTPUT line should come after you assignment to l_sql, otherwise you'll miss outputting one or more of the statements being processed. A good place would be between the assignment statement and the execute statement.

ORA-01031: insufficient privileges at "SYS.DBMS_SESSION" when using a package on 11g

I have a package with a procedure to create context and set the value to context. It works very well on 10g but on 11g I get the following error also with DBA role.
ORA-01031: insufficient privileges
ORA-06512: at "SYS.DBMS_SESSION", line 101
ORA-06512: at "REDIS_DATA.DYNAMICSQL_CONTEXT", line 7
ORA-06512: at "REDIS_DATA.FESTSTELLUNG_GETOVERVIEW", line 99
The package is build as follow:
-- DYNAMICSQL_CONTEXT specification
CREATE OR REPLACE PACKAGE REDIS_DATA.DYNAMICSQL_CONTEXT
AS
PROCEDURE CONTEXT_SETPARAM(p_name IN VARCHAR2,
p_value IN VARCHAR2);
END DYNAMICSQL_CONTEXT;
And the body:
CREATE OR REPLACE PACKAGE BODY REDIS_DATA.DYNAMICSQL_CONTEXT
IS
PROCEDURE CONTEXT_SETPARAM(p_name IN VARCHAR2,
p_value IN VARCHAR2)
IS
BEGIN
DBMS_SESSION.SET_CONTEXT('parameter', p_name, p_value);
END CONTEXT_SETPARAM;
END DYNAMICSQL_CONTEXT;
It will be called like this
IF p_ISTADMIN = 0
THEN
DYNAMICSQL_CONTEXT.CONTEXT_SETPARAM('pREVISORID', p_REVISORID);
p__wherePart := p__wherePart || 'AND ((p.ISSECURE = 1 AND p.ID IN (select PARENTOBJECT from PRUEFUNG_BETEILIGTE where PROPERTY = SYS_CONTEXT(''parameter'', ''pREVISORID''))) OR (p.ISSECURE = 0)) ';
END IF;
the context will be used from several stored procedures. How to build this to work on both platforms????
As addition here the privilegs of the schema user:
system privilege on 10g where it works:
ALTER SESSION
CREATE ANY CONTEXT
CREATE CLUSTER
CREATE INDEXTYPE
CREATE OPERATOR
CREATE PROCEDURE
CREATE SEQUENCE
CREATE SESSION
CREATE SYNONYM
CREATE TABLE
CREATE TRIGGER N
CREATE TYPE N
CREATE VIEW N
DEBUG ANY PROCEDURE N
DEBUG CONNECT SESSION
I tried this privilegs on 11g but it did not work. So I gave the schema user the role DBA. But this did not work also.
I too faced the same few days back but solve it bit differently. In my case, calling DB user had every privilege required including EXECUTE and DBMS_SESSION.
You don't need to create or initialise every time if you create CONTEXT like following. Pls see sample statement below:
CREATE OR REPLACE CONTEXT parameter USING DYNAMICSQL_CONTEXT **ACCESSED GLOBALLY**;

Dynamic SQL and Cursor related issue

I have declared cursor and used in the procedure body, then I have dynamic sql statement which creates a table on the fly. After that I need to access the same cursor which i declared.
When I try to open the cursor before the execution of dynamic sql statement its working fine.
When I try to open the cursor after the execution of dynamic sql statement its not opening and cursor.
Please help me.
Thank you.
create or replace procedure(columns varchar2)
is
column_names varchar2(100);
sql_query varchar2(200);
begin
select pk_cols into column_names
from rules where rule_column=columns;
sql_query:='create global temporary table ('||column_names||')';
execute immediate sql_query;
end;
Creating the table is DDL which in Oracle results in an implicit commit, ending your transaction.
To solve this problem you could create the table inside an autonomous transaction:
-- open cursor
declare
pragma autonomous_transaction;
begin
execute immediate 'create table ...';
end;
-- do more with your cursor
For more information about autonomous transactions, see this overview on Tim Hall's excellent site.

Resources