How to solve this issue "distributed update operation failed; rollback required"? - oracle

I have a package that calls 2 procedures and I'm using dblink to call them.
I tried running first individually the procedures if it's working and they are both running.
exec proc1#dblink;
exec proc2#dblink;
So when I put them in my package, I'm getting these errors:
ORA-02055: distributed update operation failed; rollback required
ORA-02041: client database did not begin a transaction
I need to call those procedures but how?

Once you commit in the remote environment, you generally can't perform any more DML because the complexities of 2 phase commit. So if your remote procedure did:
procedure P is
begin
some DML
commit
some more DML
end
then when you call it from your local database you're going to hit this.The resolution is to take control of the commits, either by removing them in the procedure or at least making them controllable with a parameter to indicate whether its being called standalone or from a remote caller.

The problem is solved! There was a missing commit in the proc1#dblink.

Related

Is commit required in an Oracle stored procedure which is called from Java class?

I have an Oracle Stored Procedure that does some inserts and updates on a table in DB.
There is no explicit Commit or Rollback statement at the end of the procedure.
However, when I call this SP through a java class, I see that the inserts and updates are committed into the DB.
So can anyone help me understand if we really need a commit statement at the end of the stored procedure in Oracle?
I am not java experience but as far as I know when you close the connection of the database the data are committed (unless if you rollback them). Now to return into your question is when to use the commit in SP.
When you use DML(insert,update,delete) operation in the procedure on a table, the table will be Locked therefore if any other user try to access the locked table, it has to wait till you commit/rollback your operation. so if your procedure was taking time, due to a long loop or bad optimized query then the user will be blocked. So if you had a commit before the DMl, the no blocks will happen.
Other reason, is the undo tablespace, where all the data not committed will wait there till you commit them, so if for example you inserted lot of data (millions), your undo might get full depend on your size and youll get an error.
so short answer , if your procedure doesn't has lot of operations on big tables and it fast then you can pass by the commit , otherwise it better to add commits.

How to manage unit tests with rollback with SQL Developer

I'd like to test my packages that change data. Every test should stay data intanct. I recently discover Unit Test Module in SQL Developer and try to savepoint on startup and rollback at teardown but with no success. Is there a good way to do that?
My environment:
Oracle 10g DB with SQL Developer 4.2
Code:
Startup was PL/SQL script
BEGIN Savepoint sp; END;
and Teardown was PS/SQL script
BEGIN ROLLBACK to sp; END;
It took me 4 hours to discover that.
It turns out that SQL Developer has a bug!
It takes white signs/spaces after END; as a PLSQL code and puts
pls-00103 begin function pragma procedure subtype type an identifier ERROR.
My code above works like charm.
Most code that writes data uses some sort of framework that also manages transactions and commits and rollbacks. If this is the case you will need to use inverse operations to undo the updates you are testing with (i.e. test an insert operation, make your assertions, and then execute a delete operation).

How do I check whether a savepoint has been established before issuing a rollback?

I have an Oracle package which loops through a list of procedures and calls them dynamically. Prior to each procedure call, a SAVEPOINT is created, and if an exception is raised, it issues a rollback and logs the problem. A bug was recently introduced where one of the dynamic procedures had a COMMIT added to it, which when triggered, invalidates the SAVEPOINT. If that same procedure then fails (raises an exception) and the calling package's exception handler attempts to rollback, the following exception is raised inside the exception handler block:
ORA-01086: savepoint 'EXAMPLE_SAVEPOINT' never established in this session or is invalid
Now, I could put another exception handler in my exception handler, to handle this specific exception, but it would be much neater if I could do a quick check of the SAVEPOINT to see if it is valid or not immediately prior to attempting to issue the rollback. Is this possible?
I think you're going to have to forget it; sorry. Someone asked Tom Kyte this question in April 2013, his response:
2) where does oracle keep track of savepoint we create?And is SCN
being created for the savepoints created?
and we said...
...
2) a savepoint is just conceptually a pointer into your undo stream.
We do not need an SCN for it, we just need to know how far back in
your undo stream to rollback to.
Both Jonathan Lewis and Burleson don't think they're stored anywhere in the data dictionary. If you're using Workspace Manager or want to use Restore Points then the data will be stored in ALL_WM_MODIFIED_TABLES and V$RESTORE_POINT respectively, but this seems like overkill.

What can i do in Oracle in order to preserve the savepoint if internal commit occurs?

background:
i'm doing some Oracle plsql refactoring; The first think that i want to accomplish is to have unit test for the principal components.
For this i'm using ruby with the gem plsq-spec https://github.com/rsim/ruby-plsql-spec
In order to execute the tests several times, i'm using Oracle Savepoints after open the database conection, and doing a rollback to the savepoint before close the connection
Problem:
Some test can't be executed more than one time, because some procedures had internal commits.
What can i do in Oracle in order to preserve the savepoint if internal commit/rollback occurs?
With this information in the note apparently what I want is impossible
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/savepoint_statement.htm
A simple rollback or commit erases all savepoints. When you roll back
to a savepoint, any savepoints marked after that savepoint are erased.
The savepoint to which you roll back remains.
so, the only solutions are?:
modify the procedures
erase all data before execute the tests?
tks
The Flashback feature may help you here, as you can restore the database or individual tables to their state as-of a previous point in time.
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9012.htm

BEGIN - END block atomic transactions in PL/SQL

This information should be easy to find, but I haven't had any luck.
When I have a BEGIN - END block in a PL/SQL, does it behave as an atomic transaction, that will try to commit on hitting the END block and if anything goes wrong rolls back the changes?
If not, how do I make sure that the code inside the BEGIN - END block behaves like an atomic transaction and how does the block behave "by default"?
EDIT: I am running from a stored procedure and I am using an implicit block, I think.
Firstly, BEGIN..END are merely syntactic elements, and have nothing to do with transactions.
Secondly, in Oracle all individual DML statements are atomic (i.e. they either succeed in full, or rollback any intermediate changes on the first failure) (unless you use the EXCEPTIONS INTO option, which I won't go into here).
If you wish a group of statements to be treated as a single atomic transaction, you'd do something like this:
BEGIN
SAVEPOINT start_tran;
INSERT INTO .... ; -- first DML
UPDATE .... ; -- second DML
BEGIN ... END; -- some other work
UPDATE .... ; -- final DML
EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO start_tran;
RAISE;
END;
That way, any exception will cause the statements in this block to be rolled back, but any statements that were run prior to this block will not be rolled back.
Note that I don't include a COMMIT - usually I prefer the calling process to issue the commit.
It is true that a BEGIN..END block with no exception handler will automatically handle this for you:
BEGIN
INSERT INTO .... ; -- first DML
UPDATE .... ; -- second DML
BEGIN ... END; -- some other work
UPDATE .... ; -- final DML
END;
If an exception is raised, all the inserts and updates will be rolled back; but as soon as you want to add an exception handler, it won't rollback. So I prefer the explicit method using savepoints.
BEGIN-END blocks are the building blocks of PL/SQL, and each PL/SQL unit is contained within at least one such block. Nesting BEGIN-END blocks within PL/SQL blocks is usually done to trap certain exceptions and handle that special exception and then raise unrelated exceptions. Nevertheless, in PL/SQL you (the client) must always issue a commit or rollback for the transaction.
If you wish to have atomic transactions within a PL/SQL containing transaction, you need to declare a PRAGMA AUTONOMOUS_TRANSACTION in the declaration block. This will ensure that any DML within that block can be committed or rolledback independently of the containing transaction.
However, you cannot declare this pragma for nested blocks. You can only declare this for:
Top-level (not nested) anonymous PL/SQL blocks
List item
Local, standalone, and packaged functions and procedures
Methods of a SQL object type
Database triggers
Reference: Oracle
You don't mention if this is an anonymous PL/SQL block or a declarative one ie. Package, Procedure or Function.
However, in PL/SQL a COMMIT must be explicitly made to save your transaction(s) to the database. The COMMIT actually saves all unsaved transactions to the database from your current user's session.
If an error occurs the transaction implicitly does a ROLLBACK.
This is the default behaviour for PL/SQL.
The default behavior of Commit PL/SQL block:
You should explicitly commit or roll back every transaction. Whether you issue the commit or rollback in your PL/SQL program or from a client program depends on the application logic. If you do not commit or roll back a transaction explicitly, the client environment determines its final state.
For example, in the SQLPlus environment, if your PL/SQL block does
not include a COMMIT or ROLLBACK statement, the final state of your
transaction depends on what you do after running the block. If you
execute a data definition, data control, or COMMIT statement or if you
issue the EXIT, DISCONNECT, or QUIT command, Oracle commits the
transaction. If you execute a ROLLBACK statement or abort the SQLPlus
session, Oracle rolls back the transaction.
https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/sqloperations.htm#i7105

Resources