troubleshooting a oracle stored procedure - sql

Suppose I have to write an oracle stored procedure with a huge number of DML operations. I need to design it as if it fails at any point I should be able to find which particular statement caused the error. One way I know is to use an exception with each of the DML statement in the procedure but I think it is not a feasible option. Is there anyway to probably write to a log file which particular statement caused the error and what error just like in Unix scripting we use $? command to determine the status of last executed command?

Here's an approach you use:
declare
vStge VARCHAR2(100);
begin
vStage := 'Start';
--DML 1;
vSTage := 'Next';
--DML 2;
.
.
.
.
vSTage := 'DOne';
exception
when others then
pr_log_error ($$PLSQL_UNIT, vStage ); -- In this sp write to a log table using autonomous txn
raise; -- or not?
end;
A tidier way would be to put each DML in a sub-procedure of its own, and have a "Start" and "End" log to a log table via a call to a stored proc with an autonomous transaction.

Related

Unable to create DB2 Procedure through command line

I am trying to create a procedure to do a blanket revoking of executeauth for procedures from a schema. This is in line with trying to secure a non-restricted database.
CREATE PROCEDURE PROC_REV
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE v_NAME VARCHAR(400);
FOR v1 AS
c1 CURSOR FOR
select specificname from SYSCAT.ROUTINEAUTH where grantee='PUBLIC' and schema='SYSPROC' and routinetype='P'
DO
SET v_NAME = specificname;
SET v_GrantQuery = 'revoke execute on specific procedure '|| v_NAME ||' from PUBLIC';
EXECUTE IMMEDIATE v_GrantQuery;
END FOR;
END#
and this is the command I run to process the file with the code above.
db2 -td# -svf RoutineAuthRevoke.db2
However, I keep running into this error
SQL0553N An object cannot be created with the schema name "SYSFUN ". LINE NUMBER=1. SQLSTATE 42939
I'm fairly new to DB2 and this is my first foray into writing db2 procedure scripts. Would anyone be able to spot the "SYSFUN " because I sure as hell can't. The only other way I can revoke 310 entries from SYSPROC for PUBLIC is through a batch file and I figured, procedures might be a cleaner way of achieving this. I would really appreciate any help with either this error or with the code itself.
A number of problems.
You can't create a routine in the SYSFUN schema as the error message shows. You get this message because the statement VALUES CURRENT SCHEMA returns SYSFUN in your session. You must either run the SET SCHEMA SOME_VALID_SCHEMA_NAME statement before CREATE or use fully qualified routine name like SOME_VALID_SCHEMA_NAME.PROC_REV.
Variable v_GrantQuery is not defined in the routine.
According to the syntax of REVOKE (routine privileges) statement, you should generate the REVOKE statement using fully qualified routine name and with RESTRICT clause at the end. The easiest way to do it with a compound statement (you don't need to create a routine for that):
BEGIN
FOR v1 AS
select 'REVOKE EXECUTE ON SPECIFIC PROCEDURE "' || schema ||'"."'|| specificname || '" FROM PUBLIC RESTRICT' AS STMT
from SYSCAT.ROUTINEAUTH
where grantee='PUBLIC' and schema='SYSPROC' and routinetype='P'
DO
EXECUTE IMMEDIATE v1.STMT;
END FOR;
END#

Run related or same procedures in oracle database simultaneously to not interfering with each other

I have a software for creating especial reports that run procedures in oracle database but the problem is:
when we create a report it uses some procedures and truncate and fill some tables, if we create another report at the same time it caused an error because it needs my table information that are truncated with another procedure. So I am looking for a technique or query to handle this problem and create the second report just after the first report finishing all the procedures that it use in the state that user do not notice anything. In this case the time that the second report is going to be create is more than the first report that it is alright.
You can use DBMS_LOCK.ALLOCATE_UNIQUE package in order to synchronize your applications and enforcing sequential processing.
DECLARE
l_status number;
l_lock_handle varchar2(128);
l_lock_request integer;
BEGIN
DBMS_LOCK.ALLOCATE_UNIQUE ( lockname => 'NAME_OF_YOUR_LOCK', lockhandle => l_lock_handle);
l_status := DBMS_LOCK.REQUEST(lockhandle => l_lock_handle, timeout => 15);
if (l_status = 0) then
-- Plase your code here
-- Only one thread can work here
l_lock_request := DBMS_LOCK.release(l_lock_handle);
else
-- handle other lock statuses...
end if;
END;
You can read more about DBMS_LOCK here.

Creating databases in for loop, injecting iterator of loop to database name

I would like to create four databases in for-loop. However, I got an error. Could you help me to resolve this problem ?
DO $$
BEGIN
FOR counter IN 1..2 LOOP
CREATE DATABASE 'database_name_%', counter;
END LOOP;
END; $$
ERROR: syntax error at or near "'Counter: %'"
LINE 4: CREATE DATABASE 'Counter: %', counter;
From documentation for the CREATE DATABASE command:
CREATE DATABASE cannot be executed inside a transaction block.
And since:
PostgreSQL actually treats every SQL statement as being executed within a transaction. If you do not issue a BEGIN command, then each individual statement has an implicit BEGIN and (if successful) COMMIT wrapped around it. A group of statements surrounded by BEGIN and COMMIT is sometimes called a transaction block
You can't create database in functions. So even if you can handle current problem, you won't be able to execute this function.

Commit transactions if no error,rollback if error occured in Oracle SQL* plus

Following is small block of code i use to deploy the SQL scripts in my databases. I'm just wondering if i can automate this task of commit or rollback based in the result.
disc
connect username/password#database
spool D:\Deployments\path\to\logfile\logfile.log
#D:\Deployments\path\to\script\sqlquery_script.sql
If the sql script is ran successfully with out any errors means I want the system to Commit it automatically and in case any error is occcured all teh transactions should be rollbacked (Note that my sql script has many update statements)
When I use WHENEVER SQLERROR EXIT SQL.CODE ROLLBACK; the SQL* plus window is closed without showing any error.
Please help to resolve this.
You don't say what your script is. How about putting it inside a PL/SQL anonymous block?
BEGIN
... updates here ...
COMMIT;
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
RAISE;
END;
/
Probably you can give call to a procedure or in the Sql script you give call to procedure
exec procedureName(parameter1,parameter2);
Keep this statement in your sql file
and in case of exception keep this statement along with the above statement
EXCEPTION
WHEN x_Error THEN
ROLLBACK ;

ORACLE Batching DDL statements within a Execute Immediate

I'm trying to run multiple ddl statements within one Execute Immediate statement.
i thought this would be pretty straight forward but it seems i'm mistaken.
The idea is this:
declare v_cnt number;
begin
select count(*) into v_cnt from all_tables where table_name='TABLE1' and owner = 'AMS';
if v_cnt = 0 then
execute immediate 'CREATE TABLE TABLE1(VALUE VARCHAR2(50) NOT NULL) ALTER TABLE TABLE1 ADD (MYVAL2 NVARCHAR2(10))';
end if;
end;
however this results in an error
ORA-00911: invalid character
ORA-06512: at line 10
Each of the statements within the batch run fine if i execute them by themselves. and if i take this statement and execute it, it will run fine (with the ; between the 2 statements). If i remove the ; between statements i get a different error about invalid option
the plan is that i'll be able to build a table, export the table schema for this table including all it's alter statements, and then run the batch against another system as part of an install/update process.
So, how do i batch these DDL statements within a single execute immediate? Or is there a better way to do what i'm needing?
I'm a bit of a Oracle newb, i must admit. Thank you all for your patience.
The semicolon is not part of Oracle's SQL syntax. SQL*Plus and other client side tools use semicolon to signal the end of a SQL Statement, but the server doesn't see it.
We can force SQL*Plus to pass the semicolon to the DB:
SQL> set sqlterminator off
SQL> select * from user_tables;
2 /
select * from user_tables;
*
ERROR at line 1:
ORA-00911: invalid character
If i take this statement and execute it, it will run fine (with the ; between the 2 statements) The client tool you are using, breaks it into two calls to the DB.
So, I don't think it is possible to pass multiple statements inside an execute immediate.
I suppose one could call execute immediate with a string containing an anonymous PL/SQL block, with individual calls to execute immediate inside it ... and I don't know what the point of doing that would be. ;)
Why do you need a single EXECUTE IMMEDIATE call? Surely just do it as 2 calls?
Bear in mind that each DDL statement contains an implicit COMMIT, so there's no concurency benefit to doing it as a single call.
Also, why not just set up the table correctly in the first call? You could do...
CREATE TABLE TABLE1(VALUE VARCHAR2(50) NOT NULL, MYVAL2 NVARCHAR2(10))
...instead of needing 2 calls.
Also, have you looked at DBMS_METADATA... it can generate DDL for objects such as tables for you.