Subject Re: [IBO] Record In Limbo ... what's it mean?
Author Helen Borrie
At 06:52 AM 19/03/2009, you wrote:
>
>> > ISC_ERROR_CODE: 335544459
>> > ISC_ERROR_MESSAGE: "record from transaction 690824 is stuck in limbo".
>> >
>> > NOW ... my REAL question ... if this happens again, is there any
>> > facility, either within the Firebird native tools, or in DB Workbench,
>> > that I can use to clear the hung record and restore a table to
>> > functionality? Preferably without loss of other data...???
>
>Jason,
>You might want to check out Helen Borrie's reply to me (the one
>previous, dtd 3/3). I think she nailed the possible root cause --
>loss of connection during a cross-db transaction. I was using an IBO
>Datapump to mass-transfer data from our CONSTITUENT.FDB to
>AUCTIONTRACKER.FDB.
>
>Per Helen's recommendation, I used Firebird's GFIX utility from the
>command line to commit the limbo record(s) and get the DB functioning
>again. This is a bit tedious, as the busted transaction actually
>leaves limbo records on both sides; it takes a couple of steps from
>the command line to fix ... which means if it happens to a user, I
>have to get a backup of the user's data files, work my magic to clear
>the limbo records, then send the files back to the user. Not exactly
>a happy path.
>
>So ... I'm wondering if there's anything I can do with an IBO object
>from Delphi to do what GFIX does??? I'm a bit out of my element, here.

A privileged user (SYSDBA or the database owner) can access the Services API, which has functions to do what gfix does, including manage limbo transactions. Install Lorenzo Mengoni's IBOAdmin components in a folder inside your IBO installation. The component of interest is TIBOValidationService.

Unfortunately these are not documented anywhere except in the Developer's Guide of InterBase 7 and later (and even there, not brilliantly!).

Here's a "lift" from the IB 7 doc re the equivalent IBX component, TIBValidationService:

Displaying limbo transaction information
Use the FetchLimboTransaction method along with theLimboTransactions option to retrieve a record of all current limbo transactions. The following code snippet will display the contents of the TLimboTransactionInfo record, provided that there are any limbo transactions to display.
try
Options := [LimboTransactions];
FetchLimboTransactionInfo;
for I := 0 to LimboTransactionInfoCount - 1 do
begin
with LimboTransactionInfo[i] do
begin
Memo1.Lines.Add('Transaction ID: ' + IntToStr(ID));
Memo1.Lines.Add('Host Site: ' + HostSite);
Memo1.Lines.Add('Remote Site: ' + RemoteSite);
Memo1.Lines.Add('Remote Database Path: ' + RemoteDatabasePath);
//Memo1.Lines.Add('Transaction State: ' + TransactionState);
Memo1.Lines.Add('-----------------------------------');
end;
end;
finally
.....
Resolving limbo transactions
You can correct transactions in a limbo state using the GlobalAction property of the TIBValidationService to perform one of the following actions of type
TTransactionGlobalAction on the database specified by the DatabaseName property:
................
Table 18.6 TIBValidationService actions
Action Meaning
CommitGlobal Commits the limbo transaction specified by ID or commits
all limbo transactions
RollbackGlobal Rolls back the limbo transaction specified by ID or rolls
back all limbo transactions
RecoverTwoPhaseGlobal Performs automated two-phase recovery, either for a
limbo transaction specified by ID or for all limbo
transactions
NoGlobalAction Takes no action
................
For example, to set the global action using radio buttons:
with IBValidationService1 do
try
if RadioButton1.Checked then GlobalAction := (CommitGlobal);
if RadioButton2.Checked then GlobalAction := (RollbackGlobal);
if RadioButton3.Checked then GlobalAction := (RecoverTwoPhaseGlobal);
if RadioButton4.Checked then GlobalAction := (NoGlobalAction);

If you're happy to use a prebuilt utility, I'm sure you'll find implementations in Database Workbench or IBExpert.