What is the reason for ORA-00054 error? - oracle

From Oracle's documentation:-
ORA-00054 resource busy and acquire with NOWAIT specified
Cause: Resource interested is busy.
Action: Retry if necessary.
In our code we issue a SELECT FOR UPDATE NOWAIT command to lock the row we are about to update.
Right now the logic is if it returns SQL error 54 then it is assumed that another user is trying to update that same record. Is this logic valid?
From Oracle's documentation it looks more like if the DB is overwhelmed then this might also cause this error to be thrown.
What are the possible reasons for this error, when we are only using the above SQL command?

The SELECT ... FOR UPDATE attempts to acquire an RS (Row Share) lock on the table and an X (eXclusive) lock on the row. If another session has an exclusive lock on the table (eg creating an index) or an exclusive lock on the row (update, delete, or select for update) then the query will wait for the other transaction to release the lock (commit or rollback generally) unless you have specified NOWAIT.
So one possibility is to not specify NOWAIT.
I don't recognise the situation where the database might throw this error due to being "overwhelmed".

Related

Oracle Lock , How do they differ?

What is the difference between the below two erros.as far as i understood, they happen in case of a Lock. But do you know the differene in scenarios where one might occure.
ORA-04021: timeout occurred while waiting to lock object
and
ORA-00054: resource busy and acquire with NOWAIT specified
Example for ORA-04021 might be this: there's a package in your schema. It contains a procedure which does some job that takes 15 minutes to finish. Someone runs that procedure. Meanwhile, you'd want to fix something in that package, so you edit its code and want to compile it. Well, you can't - it is being used so you'll have to wait until it is released. Oracle tells you that timeout occurred while you're waiting to lock the package and compile it.
Example for ORA-00054: there's a table. You update some values in it, but didn't commit (nor rollback) as you have to do something else as well. In another session, another user wants to alter one of table's columns (for example, enlarge its size). ALTER will then raise 0RA-00054 which says that table is busy (you're updating it in another session, right?) so you'll have to wait until transaction commits (or rollbacks).

Skipping unusable indexes causes dblink error

Every once and a while when I'm executing the following statement:
alter session set skip_unusable_indexes=true;
I'm getting the following error:
ORA-03135: connection lost contact
ORA-02063: preceding line from my_dblink
What does skipping indexes has to do with my dblink?
How can I detect the problematic index?
How can I limit the scope of the above statement only to my local indexes?
1) What does skipping indexes has to do with my dblink?
It has no relation. Please elaborate how you are getting the issue. Is
that you are login to sqlplus and as soon as you alter session, your
DB link disconnects?
2) How can I detect the problematic index?
select STATUS,index_name,table_name from user_indexes where status='UNUSABLE';
select STATUS,index_name,table_name from user_indexes where status!='VALID' and status!='N/A';
3) How can I limit the scope of the above statement only to my local indexes?
I believe you meant to say the indexes on connected database and not
on the DB link database. You can not do this. This is session or
system setting.
I suspect that this is a bug, or at least an unimplemented feature.
When you set your session to skip unusable indexes, you're modifying the query optimiser/parser behaviour, and I suspect that this modification cannot be "pushed" to the remote instance that you have made a connection to.
I also suspect that the key to avoiding this problem, if it can be avoided, is to alter the session before referencing any database links, but even then I would not be surprised if the remote database does not implement the modification, as it is effectively a different session.

alter table constraint on unlock oracle

I am trying to write a script to be executed by a client who has no real knowledge of pl/sql,
I do a bunch of transactions in PL/sql to clean up their landscape and then have to add in some constraints to keep this from happening again, I commit automatically after the cleaning, and would like to finish my PL block with adding these constraints
only issue is I have no guarantee that the tables will not be locked when trying to add constraints to them, is there a wait until unlock type of command in oracle?
thank you, new to oracle and cannot seem to find this, I have combed through a bit of API but am at the point of time sensitivity and is proving very difficult to find when i think it seems like it would be a pretty regular issue with DB management
in your pl/sql block before execute any DDL you should call via execute immedaite :
LOCK TABLE <table_name> IN EXCLUSIVE MODE WAIT <n>;
where is number of seconds to wait.
But bear in mind even if you get lock after your first ddl it will be released because DDL commits automatically. So there is no way to guarantee that list of DDL commands will be executed one-by-one as in one transaction.
The command would be:
LOCK TABLE tab IN EXCLUSIVE MODE;
This will wait indefinitely if there is another session with a similar lock (which there should not be).
You can lock a table explicitly (with "WAIT") prior to a DDL, but that won't necessarily solve all of your problems if you are worried about another session holding an exclusive lock. Sounds more like you may have experienced an ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired due to a DML transaction in another session. This will eventually finish, so issuing the above lock command prior to ALTER TABLE will help you here. Just be aware that if there is a hung session elsewhere the LOCK TABLE command can wait indefinitely unless you have set a timeout.
So lets do an example:
In session A I start a transaction on tab
SQL> INSERT INTO tab VALUES(...);
In session B I attempt to add a constraint to the table.
SQL> alter table tab add constraint uk_name unique(name);
alter table tab add constraint uk_name unique(name)
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expire
So I'd have to try again. But instead if you precede your DDL with a LOCK ... EXCLUSIVE (WAIT)
SQL> lock table tab in exclusive mode;
-- indefinite period while the session A transaction blocks session B
Then session A commits or rolls back
SQL> commit;
Session B immediately continues when we see the lock command return Table(s) locked
Table(s) Locked.
SQL> alter table tab add constraint uk_name unique(name);
Table altered. (**comment Lock is released by the implicit commit issued the DDL statement)
SQL>
Since the DDL statement releases the lock, each DDL will need to be preceded with a fresh LOCK statement. If you want to use this, I recommend adding a timeout (as suggested in comments by Justin). Lets wait up to a minute before giving up.
SQL> lock table tab in exclusive mode WAIT 60;
Although if this is an unattended script on a busy database, I'd probably go with something more than 60 seconds. Just log everything to a spool file, and check the log later for errors.
Anything more than this sort of maintenance probably requires that you quiesce your database first, else just deal with the contention on a case by case basis.

Finding all statements involved in a deadlock from an Oracle trace file?

As I understand it, the typical case of a deadlock involving row-locking requires four SQL statements. Two in one transaction to update row A and row B, and then a further two in a separate transaction to update the same rows, and require the same locks, but in the reverse order.
Transaction 1 gets the lock on row A before transaction 2 can request it, transaction 2 gets the lock on row B before transaction 1 can get it, and neither can get the remaining required locks. One or either transaction has to be rolled back, so the other can complete.
When I review an Oracle trace file after a deadlock, it only seems to highlight two queries. These seem to be the last one out of each transaction.
How can I identify the other statements involved in each transaction, or is this missing in an Oracle trace file?
I can include relevant bits of the specific trace file if required.
You're correct, in a typical row-level deadlock, you'll have session 1 execute sql_a that will lock row 1. Then session 2 will execute sql_b that will lock row 2. Then session 1 will execute sql_c to attempt to lock row 2, but session 2 has not committed, and so session 1 starts waiting. Finally, session 2 comes along, and it issues sql_d, attempting to lock row 1, but, since session 1 holds that lock, it starts waiting. Three seconds later, the deadlock is detected, and one of the sessions will catch ORA-00060 and the trace file is written.
In this scenario, the trace file will contain sql_c and sql_d, but not sql_a or sql_b.
The problem is that information just really isn't available anywhere. Consider that you execute a DML, it starts a transaction if one doesn't exist, generates a bunch of undo and redo, and the change is made. But, once that happens, the session is no longer associated with that SQL statement. There's really no clean way to go back and find that information.
sql_c and sql_d, on the other hand, are the statements that were associated with those sessions when the deadlock occurred, so, clearly, Oracle can identify them, and include that in the trace file.
So, you're correct, the information about sql_a and sql_b is not in the trace, and it's really not readily available.
Hope that helps.

Oracle triggers error are not captured while using ADODB

I have and application which uses Adodb to insert data in Oracle table(customers database).
Data is successfully inserted if there are no errors.
If there is any error like invalid datatype etc. Error is raised and captured by my application and dumped in log gile.
My customer has written their own triggers on this particular table. When a record is inserted few other checking are done be fore the data insertion
Now all fine until now.
But recently we found that many a times data is not inserted in the oracle table.
When checked in log file no error was found.
Then I logged the query which was executed.
Copied the query to oracle Sql prompt and executed it gave error of trigger.
My Issue is
Customer is not ready to share the details of trigger.
Error is not raised while inserting to oracle table so we are not able to log it or take any action.
The same qry when executed directly in oracle the trigger errors are show.
Help needed for
Why the error is not raised in ADODB
Do I have to inform customer to implement any error raising
Anything that you can suggest for resolving the issue
I have 0% to 10% knowledge of Oracle
"Copied the query to oracle Sql prompt and executed it gave error of trigger." Since the ADO session doesn't report an error, it may be that the error from the trigger is misleading. It may simply be a check on the lines of "Hey, you are not allowed to insert into this table except though the application".
"Error is not raised while inserting to oracle table so we are not able to log it or take any action."
If the error isn't raised at the time of insert, it MAY be raised at the time of committing. Deferred constraints and materialized views could give this.
Hypothetically, I could reproduce your experience as follows:
1. Create a table tab_a with a deferrable constraint initially deferred (eg val_a > 10)
2. The ADO session inserts a row violating the constraint but it dooesn't error because the constraint is deferred
3. The commit happens and the constraint violation exception fires and the transaction is rolled back instead of being committed.
So see if you are catering for the possibility of an error in the commit.
It may also be something else later in the transaction which results in a rollback of the whole transaction (eg a deadlock). Session tracing would be good. Failing that, look into a SERVERERROR trigger on the user to log the error (eg in a file, so it won't be rolled back)
http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7004.htm#i2153530
You can log your business logic in log table.
But you have to use stored procedure to log the message.
Stored procedure should have pragma Transaction such that your log data must be saved in log table.
You are trigger should have error handling - and in error handling , you have to call Logged stored procedure (which have pragma transaction)
I've never used adodb ( and I assume that is what you are using, not ADO.NET?).. But, a quick look at its references leads to this question.. Are you actually checking the return state of your query?
$ok = $DB->Execute("update atable set aval = 0");
if (!$ok) mylogerr($DB->ErrorMsg());

Resources