Can I undo a rollback in sqlplus? - sql

I somehow thought rollback means undo the last action. This is what I did:
SQL> update owns
2 set DRIVER_ID=99999999
3 ^[[A^Z;
4 rows updated.
SQL> select * from owns;
DRIVER_ID LICENSE
-------------------- ----------
99999999 ABC222
99999999 MSA369
99999999 MZZ2828
99999999 ZGA123
SQL> rollback
2 ;
Rollback complete.
SQL> select * from owns;
no rows selected
Is everything gone forever? All my data too? Thanks for any advice and help

what you show is not complete... before that UPDATE you must have done something else like an INSERT...
There is no rollback of the rollback if that is what you are asking... the only way you will get this "undone" is to re-execute all statements executed between the last commit before the rollback and that rollback (in the same order!)...
Another option would exist IF your Oracle DB has an active Flashback area - then you could "rewind" the whole DB to the point in time just before you issued the rollback...

Related

Undo/RollBack latest query

While updating my table tblTransaction I enter this code by mistake
update tblTransaction
set Total = 1100
And now all the value in that column has become 1100. Then I tried this code to rollback
BEGIN TRANSACTION
rollback transaction;
Even though rollback code was executed but it didn't Work. So, how can I revert this total column value to it's previous value?

Does SELECT start transaction in PL/SQL

I was told that following code won't help me to check duplicity, because result might be different before SELECT and UPDATE statement.
PROCEDURE AddNew(Pname VARCHAR2, Pcountry VARCHAR2)
AS
already_exists BOOLEAN;
BEGIN
SELECT COUNT(*)>0 INTO already_exists FROM Publishers WHERE name=Pname;
IF already_exists THEN
RAISE_APPLICATION_ERROR(-20014,'Publisher already exists!');
END IF;
INSERT INTO Publishers(id,name,country)
VALUES (NewPublisherId(),Pname,Pcountry);
END;
This post claims that SELECT starts a transaction:
Why do I get an open transaction when just selecting from a database View?
This part of documentation suggests otherwise:
A transaction implicitly begins with any operation that obtains a TX
lock:
When a statement that modifies data is issued
When a SELECT ... FOR UPDATE statement is issued
When a transaction is explicitly started with a SET TRANSACTION statement or the DBMS_TRANSACTION package
So? Does SELECT start a transaction or not?
The latter is true: https://docs.oracle.com/cloud/latest/db112/SQLRF/statements_10005.htm#SQLRF01705
A transaction implicitly begins with any operation that obtains a TX
lock:
When a statement that modifies data is issued
When a SELECT ... FOR UPDATE statement is issued
When a transaction is explicitly started with a SET TRANSACTION statement or the DBMS_TRANSACTION package
But it really does not matter, from the point of view of the main problem - to see if the record already exists in the database. Even if the transaction is explicitely startet using SET TRANSACTION ..., your code simply does not detect duplicate transactions !
Just do a simple test manually simulating the procedure in two simultaneous sessions and you will see:
CREATE TABLE Publishers(
id int,
name varchar2(100)
);
Let say that in session #1 the procedure begins at 8:00:00.0000:
SQL> Set transaction name 'session 1';
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Let say that in session #2 the same procedure begins at 8:00:00.0020, just after the insert was made in session 1, but still before the session#1 commits:
SQL> Set transaction name 'session 2';
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
The transaction #2 does not see uncommited changes done by the session 1, so the session 2 assumess that there is no record John, so it also inserts it to the table:
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Now the session 1 commits:
SQL> Commit;
Commit complete.
and a few milliseconds later the session2 commits too:
SQL> Commit;
Commit complete.
And the final result is - a duplicated record even though the transaction has been explicitelly started:
select * from publishers;
ID NAME
---------- ----------------------------------------------------------------------------------------------------
1 John
1 John
========== EDIT =================
You can avoid the duplicity by executing statement SET TRANSACTION
ISOLATION LEVEL SERIALIZABLE in the beginning. – #Draex_
Many think that ISOLATION LEVEL SERIALIZABLE will solve the problem magically. Unfortunately, it will not help.
Let's see how it works on a simple example:
Session #1
SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Session #2
SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Session #1 again:
SQL> commit;
Commit complete.
SQL> select * from publishers;
ID NAME
---------- --------
1 John
and back to session #2
SQL> commit;
Commit complete.
SQL> select * from publishers;
ID NAME
---------- --------
1 John
1 John
As you can see, the magic of ISOLATION LEVEL SERIALIZABLE did not work.

How can I lock a single row in Oracle SQL

It seems simple but I struggle with it. The question is how can I lock for example a single row from the table JOBS with JOB_ID = IT_PROG. I want to do it, because I want to try an exception from a procedure, where it displays you a message when you try to update a locked row. Thanks in advance for your time.
You may lock the record as described in other answers, but you will not see any exception while UPDATEing this row.
The UPDATE statement will wait until the lock will be released, i.e. the session with SELECT ... FOR UPDATE commits. After that the UPDATE will be performed.
The only exeption you can manage is DEADLOCK, i.e.
Session1 SELECT FOR UPDATE record A
Session2 SELECT FOR UPDATE record B
Session1 UPDATE record B --- wait as record locked
Session2 UPDATE record A --- deadlock as 1 is waiting on 2 and 2 waiting on 1
AskTom has an example of what you're trying to do:
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4515126525609
From AskTom:
declare
resource_busy exception;
pragma exception_init( resource_busy, -54 );
success boolean := False;
begin
for i in 1 .. 3
loop
exit when (success);
begin
select xxx from yyy where .... for update NOWAIT;
success := true;
exception
when resource_busy then
dbms_lock.sleep(1);
end;
end loop;
if ( not success ) then
raise_application_error( -20001, 'row is locked by another session' );
end if;
end;
This attempts to get a lock, and if it can't get one (i.e. ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired is raised) it will raise an error.
It's not possible to manually lock a row in Oracle. You can manually lock an object,though. Exclusive lock is placed on the row automatically when performing DML operations to ensure that no other sessions could update the same row or any other DDL operations could drop that row- other sessions can read it any time.
The first session to request the lock on the rows gets it and any other sessions requesting write access must wait.
If you don't want to be get locked ,that means , if you don't want to wait , you can use
Select .... For update ( nowait / wait(n) ) ( skiplocked) statement

Why should we use rollback in sql explicitly?

I'm using PostgreSQL 9.3
I have one misunderstanding about transactions and how they work. Suppose we wrapped some SQL operator within a transaction like the following:
BEGIN;
insert into tbl (name, val) VALUES('John', 'Doe');
insert into tbl (name, val) VALUES('John', 'Doee');
COMMIT;
If something goes wrong the transaction will automatically be rolled back. Taking that into account I can't get when should we use ROLLBACK explicitly? Could you get an example when it's necessary?
In PostgreSQL the transaction is not automatically rolled back on error.
It is set to the aborted state, where further commands will fail with an error until you roll the transaction back.
Observe:
regress=> BEGIN;
BEGIN
regress=> LOCK TABLE nosuchtable;
ERROR: relation "nosuchtable" does not exist
regress=> SELECT 1;
ERROR: current transaction is aborted, commands ignored until end of transaction block
regress=> ROLLBACK;
ROLLBACK
This is important, because it prevents you from accidentally executing half a transaction. Imagine if PostgreSQL automatically rolled back, allowing new implicit transactions to occur, and you tried to run the following sequence of statements:
BEGIN;
INSERT INTO archive_table SELECT * FROM current_tabble;
DELETE FROM current_table;
COMMIT;
PostgreSQL will abort the transaction when it sees the typo current_tabble. So the DELETE will never happen - all statements get ignored after the error, and the COMMIT is treated as a ROLLBACK for an aborted transaction:
regress=> BEGIN;
BEGIN
regress=> SELECT typo;
ERROR: column "typo" does not exist
regress=> COMMIT;
ROLLBACK
If it instead automatically rolled the transaction back, it'd be like you ran:
BEGIN;
INSERT INTO archive_table SELECT * FROM current_tabble;
ROLLBACK; -- automatic
BEGIN; -- automatic
DELETE FROM current_table;
COMMIT; -- automatic
... which, needless to say, would probably make you quite upset.
Other uses for explicit ROLLBACK are manual modification and test cases:
Do some changes to the data (UPDATE, DELETE ...).
Run SELECT statements to check results of data modification.
Do ROLLBACK if results are not as expected.
In Postgres DB you can do this even with DDL statements (CREATE TABLE, ...)

searching for a word in all triggers in a schema - oracle

I'm having problems running my application - Oracle is raising an
ORA-04092: cannot COMMIT in a trigger issue.
Now I am trying to find the trigger which contains commit statement. Is it possible to find the trigger which has the commit statement in all `dba_triggers'?
select * from dba_triggers statement
gives me all dba triggers. Now I have to search these triggers with the word commit.
If you get the full error stack, you should be able to see what line of what trigger is throwing the error. That's the most efficient approach. For example, if you create a trigger that commits and run an INSERT, the stack trace will show you what line of what trigger caused the error.
SQL> create table t (
2 col1 number
3 );
Table created.
SQL> ed
Wrote file afiedt.buf
1 create trigger trg_t
2 before insert on t
3 for each row
4 begin
5 commit;
6* end;
SQL> /
Trigger created.
SQL> begin
2 insert into t values( 1 );
3 end;
4 /
begin
*
ERROR at line 1:
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "SCOTT.TRG_T", line 2
ORA-04088: error during execution of trigger 'SCOTT.TRG_T'
ORA-06512: at line 2
You can search the source for all triggers looking for a particular string. Something like this will look for the literal "COMMIT" in any trigger in whatever schemas you specify.
SELECT name, text, line
FROM dba_source
WHERE owner IN (<<schemas you want to search>>)
AND upper(text) like '%COMMIT%';
On the other hand, there is a strong probability that the trigger that is failing is calling a stored procedure and it is the stored procedure that is committing. So searching the source of your triggers may not be beneficial.
You could potentially mitigate that by doing a recursive query on DBA_DEPENDENCIES (or ALL_DEPENDENCIES or USER_DEPENDENCIES depending on your privilege level and the scope of what you want to search for) to find all of the procedures that are potentially called from any trigger and to search the source of all of those procedures from DBA_SOURCE. But that's going to be much more complex than simply examining the full error stack.