Rollback form one database to other database in oracle - oracle

I'm have two database DB1 and DB2, using the following stored procedure to archive datas form one database to another database
CREATE OR REPLACE PROCEDURE "DB1"."ARCHIVE"(FROM_ARCHIVE timestamp, TO_ARCHIVE timestamp)
AS
v_err_num NUMBER;
v_err_msg VARCHAR2(200);
CURSOR MY_CURSOR IS
SELECT
ID,A,B,C
FROM
TABLE1 WHERE A >= FROM_ARCHIVE AND A <= TO_ARCHIVE
BEGIN
FOR MY_LOOP IN MY_CURSOR
LOOP
BEGIN
INSERT
INTO
DB2.TABLE2
(
A,B,C
)
VALUES
(
MY_LOOP.A,MY_LOOP.B,MY_LOOP.C
);
END;
END LOOP;
FOR MY_LOOP IN MY_CURSOR
LOOP
BEGIN
DELETE FROM TABLE1 Where A = MY_LOOP.ID;
END;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;--if exception occures the rollback happening for the DB1 database only and not happening for DB2
COMMIT;
END;
here if exception occurs in the TABLE1 delete statement then rollback happening for the DB1 database only and not happening for DB2
is there any way to do the rollback for the particular DB2 database
Please help me solve this Thanks in advance

create a savepoint before the insert on db2 and executed my rollback to that specific savepoint this solved the issue
Special thanks to #Jorge Campos

The 'Stop and rollback on error' option does not work when deploying multiple PL/SQL routines (stored procedures, user-defined functions, and packages) against an Oracle database server.
Do not deploy multiple PL/SQL routines against Oracle using the 'Stop and rollback on error' error handling option.
If routines that are deployed need to be updated or dropped because of an encountered error,
do so after the deployment process completes by identifying the affected routines in the SQL results view and dropping and re-deploying routines, as required.

Related

Oracle Transactions PLSQL

I am working on PLSQL based Procedures in Oracle 11g & 12c.
I want to keep logs of table name and row count when I issue commit command in one of my procedure/function.
This is for audit logs.
Can you please suggest how do I accomplish this?
Your PL/SQL code will need to keep track of its activity and log it. There is no way to ask Oracle "how many rows are you committing right now and to which tables?"
So, e.g.,
DECLARE
l_row_count NUMBER;
BEGIN
UPDATE table_1 SET column_a = 'whatever' WHERE column_b = 'some condition';
l_row_count := SQL%ROWCOUNT;
INSERT INTO my_audit ( action, cnt ) VALUES ('Updated table_1', l_row_count);
-- Notice the audit is part of the transaction; if I don't commit the UPDATE,
-- I won't commit the log of the update.
-- ... do other similar updates / inserts / deleted, using SQL%ROWCOUNT to
-- to determine the number of rows affected and log each one ...
COMMIT;
END;
Again, it is not practical to do a bunch of DML statements (inserts, updates, deletes) and then ask Oracle after the fact "what I have done so far in this transaction?" You need to record it as you go.

How to call Oracle stored procedure from azure data factory v2

My requirement is copy data from Oracle to SQL Server. Before copying from Oracle database, I need to update the Oracle table using procedure which has some logic.
How do I execute Oracle stored procedure from Azure datafactory?
I referred to this thread
if I use EXECUTE PROC_NAME (PARAM); in preCopy script it's failing with following error
Failure happened on 'Source' side.
ErrorCode=UserErrorOdbcOperationFailed,
Type=Microsoft.DataTransfer.Common.Shared.HybridDeliveryException
Message=ERROR [42000] [Microsoft][ODBC Oracle Wire Protocol driver]
[Oracle]ORA-00900: invalid SQL statement
Source=Microsoft.DataTransfer.ClientLibrary.Odbc.OdbcConnector,
Type=System.Data.Odbc.OdbcException
Message=ERROR [42000] [Microsoft][ODBC Oracle Wire Protocol driver]
[Oracle]ORA-00900: invalid SQL statement,Source=msora28.dll
Could anyone help on this?
Note: I am using self-hosted runtime environment for data factory
thanks!!
I used a Lookup Activity and a SELECT statement of DUAL TABLE. Due to the stored procedures can not be call from a statement SELECT. I created an oracle function and the function calls the stored procedure. The function returns a value and this value is received by the lookup activity.
When you define the function, you have to add the statement PRAGMA AUTONOMOUS_TRANSACTION. This is because Oracle does not allow to execute DML instructions with a SELECT statement by default. Then, you need to define that DML instructions in the Stored Procedure will be an autonomous transaction.
--Tabla
CREATE TABLE empleados(
emp_id NUMBER(9),
nombre VARCHAR2(100),
CONSTRAINT empleados_pk PRIMARY KEY(emp_id),
);
create or replace procedure insert_empleado (numero in NUMBER, nombre in VARCHAR2) is
begin
INSERT INTO empleados (emp_id, nombre)
Values(numero, nombre);
COMMIT;
end;
create or replace function funcinsert_empleado (numero in NUMBER, nombre in VARCHAR2)
return VARCHAR2
is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert_empleado (numero, nombre);
return 'done';
end;
--statement in query of lookup
SELECT funcinsert_empleado ('1', 'Roger Federer')
FROM DUAL;
Example lookup
This is example in Spanish. https://dev.to/maritzag/ejecutar-un-stored-procedure-de-oracle-desde-data-factory-2jcp
In Oracle, EXECUTE X(Y) is a SQL*Plus-specific command shortcut for the PL/SQL statement BEGIN X(Y); END;. Since you are not using SQL*Plus, try the BEGIN/END syntax.
In case you only want to execute the DML query using the Azure Data Factory without procedure on oracle database :-
I have another solution where you can use the copy activity with the pre-copy feature of sink in-spite of lookup activity.
For this approach just follow the below steps :-
Keep both the source table and sink table as same ( Let say table A ) using the same linked service.
In sink use the pre-copy script feature and keep the DML (Insert/Update/Delete ) query that you want to perform over the table B.( This table is not necessary to be same as table A )
In case you want to avoid the copy of data to same table you can select query option in the source part and provide a where clause which is not going to satisfy and hence no copy of data will happen .
or you can create a table temp with one column and one row .
I have tested both the options and it works ... good part of above solution is you can avoid the procedure or function creation and maintenance .

How to create and drop a table inside Oracle function?

I have the function in which I need to drop and create tables. In the example below I try to create the table but it fails
CREATE OR REPLACE FUNCTION DEVTEST
RETURN NUMBER
IS
COMMAND VARCHAR2(256);
ID VARCHAR2(128);
NAME VARCHAR2(128);
TMP_LIST VARCHAR2(128);
BEGIN
ID := '12345';
NAME := 'ABCdef';
TMP_LIST := 'tmpTest';
command := 'create table ' || TMP_LIST || ' ( USER_ID VARCHAR2(11), USER_NAME VARCHAR2(36))';
DBMS_OUTPUT.PUT_LINE('command = ' || command);
EXECUTE IMMEDIATE command;
return 0;
END;
I call the function:
select NSB_DEVTEST() from dual
And get the error:
ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML ORA-06512: at "DEV1_SERVER.DEVTEST", line 15
How do I correct this to create/drop a table inside a function?
My server details:
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production
CORE 10.2.0.5.0 Production
TNS for Solaris: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production
The problem is not with the function but with it being called from a SQL statement rather than from a pl/sql block.
A SELECT statement in SQL is equivalent to a READ operation that comes with read consistency. It cannot make any changes to the database. The database should always be the same before and after the "READ" operation completed, otherwise it would be a WRITE operation and the entire database consistency would go havoc.
Also, like the error says, DDL operations do a COMMIT behind the scenes before they start. Any read consistent operation should never do any COMMITS and write to the database without the user knowing.
You can instead call the function from pl/sql like this -
DECLARE
l_result NUBMER;
BEGIN
l_result := DEVTEST;
DBMS_OUTPUT.PUT_LINE(l_number);
END;
Still I would prefer writing a procedure for this, so others don't get confused by why this can't be called from SQL. The general rule that I follow for myself is that - Functions "get" things and Procedures "do" things (like DML).
The answer to your question is: don't. Production code, on the whole, shouldn't be creating tables on the fly. If you need a table to hold data temporarily, then create a Global Temporary Table (GTT) once and have your code refer to it.
The reason why you're getting that error (apart from it being self-evident from the error message) is because you're calling the function from within a SQL statement. You can't do that; you'd have to call it directly in PL/SQL.
I'm curious as to why you think this approach is a good, feasible approach, and also what you're going to be doing with the table once you've created it.
Your code is perfect no problem in the code . the problem is while you try to execute
you can only execute a pure function in select statement, which means a function without ddl & dml . ( if you use pragma autonomous_transaction while performing dml inside a function then you can use it in select statement ). When function has DDL command you can never ever execute it in select statement , but instead you can only execute it in PLSQL block like this
declare
a number;
begin
a:= devtest;
end;
/
and you can check your table
select * from tmptest;

Oracle - Update statement in Stored Procedure does not work once in a while

We have a stored procedure that inserts data into a table from some temporary tables in oracle database. There is an update statement after the insert that updates a flag in the same table based on certain checks. At the end of the stored procedure commit happens.
The problem is that the update works on 95% cases but in some cases it fails to update. When we try to run it again without changing anything, it works. Even trying to execute the same stored procedure on the same data at some other time, works perfectly. I haven't found any issues in the logic in the stored procedure. I feel there is some database level issue which we are not able to find (maybe related to concurrency). Any ideas on this would be very helpful.
Without seeing the source code we will just be guessing. The most obvious suggestion that I can think of is that it hits an exception somewhere along the way in some cases and never gets as far as the commit. Another possibility is that there is a lock on the table during execution when it fails.
Probably the best thing to investigate further would be to add an exception handler that writes the exceptions to some table or file and see what error is raised e.g.
-- create a logging table
create table tmp_error_log (timestamp timestamp(0), Error_test varchar2(1000));
-- add a variable to your procedure declaration
v_sql varchar2(1000);
-- add an exception handler just before the final end; statement on your procedure
exception
when others then
begin
v_sql := 'insert into tmp_error_log values(''' ||
to_char(sysdate, 'DD-MON-YYYY HH24:MI:SS') || ''', ''' || SQLERRM || ''')';
dbms_output.put_line(v_sql);
execute immediate v_sql;
commit;
end;
-- see what you get in the table
select * from tmp_error_log;

Alternative for 'ddl_lock_timeout' in oracle 10g

In oracle 11g it's allowed to set session and system parameter, which's called ddl_lock_timeout. It's very useful when you need to execute some statement and resources are highly used (in order to avoid ORA-00054 exception).
But the case is that there's no such a parameter in 10g.
Of course, I'm able to use such a cosntruction as:
DECLARE START_DATE DATE := SYSDATE;
BEGIN
LOOP
IF SYSDATE>START_DATE+30/60/60/24 THEN
EXIT;
END IF;
BEGIN
<some statement>
EXIT;
EXCEPTION WHEN OTHERS THEN
IF sqlcode != -54 THEN
RAISE;
END IF;
END;
END LOOP;
END;
And by using it, I will try to execute the statement for 30 seconds in a cycle, but the thing here is that the statement is executed many many times and could cause some troubles (i'm not sure but I feel it somehow), but using ddl_lock_timeout the statement is executed only once and then waits for resources which is much fluffier.
Any ideas?
This is an explanation of why LOCK TABLE does not necessarily work.
LOCK TABLE - trick may not be working in all situations.
Session 1: Session 2:
create table table1(a number);
insert into table1 values(1);
commit;
update table1 set a = 2;
lock table table1 in exclusive mode;
<waits...>
commit;
"Table(s) Locked."
update table1 set a = 3; <-- notice session 1 goes in queue now.
DDL fails with "resource busy with NOWAIT".
Reason is DDL first commit the previous transaction
before executing the DDL. And when it commits
session 1 gets the lock as it was already in queue.

Resources