How to reconnect to the same UIBDatabase + UIBTransaction after network-loss?

881 Views Asked by At

We have a Delphi7 + UIB + Firebird 2.5 application for pizzerias, working rock stable on wired networks.
But on wifi, (working with Win8/Win10 TabletPCs,) if the connection is broken, UIBDatabase can not reconnect itself automatically.

(We are currently reconstructing the whole APP to remove "IBX leftovers", but after upgrading UIB to the latest version, problems seems to be even worse!)

After a tipical connection loss, an error msg. is:

Project ...exe raised exception class EUIBError with message 'connection rejected by remote interface
Connection not established
GDS Code: 335544421 - SQL Code: -923 - Error Code: 101'. Process stopped. 

Even if I try to close the current connection with .IsConnected:=False or .CancelAbort It can not reconnect again any more:

Project ...exe raised exception class EUIBError with message 'invalid statement handle
Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements
GDS Code: 335544485 - SQL Code: -901 - Error Code: 165'. Process stopped. Use Step or Run to continue.

So whatever we do, we can not reconnect!

The worst case is when the TabletPC goes into sleep mode, because the connection is definitely broken, but the component thinks it's still online. It takes minimum of 8 seconds for it to realize the query can not be executed.

We've tried to start a TTimer before to force cancel the operation after 2000ms, but that event never gets fired.

So I wonder:

  • Is there a way to handle these cases properly?
  • Nobody else has problems like this? (Red every related topic here, found only 1 similar with 0 solution.)
  • Is the current UIB component downloadable from here not stable? (Had' hard time to compile under D7 because of many SynEdit incompatibility errors!)
  • Why is .OnConnectionLoss event fired only after I'm trying to reconnect again?
  • Is it possible to reconnect to the:
    SAME transaction again,
    finish the query
    and Commit & close properly?
    (Since we can read the transaction ID from Firebird.) ... so the server won't need to hold it open for 2+ hours.
1

There are 1 best solutions below

1
On

Error 1:
Accidentally typed tpConsistency instead of tpConcurrency at 1 place of ca.50.
That LOCK-ed the whole table, so it was impossible to connect back

Error 2:
It is recommended to set myTransaction.DefaultAction := etmRollback;

Error 3:

The UIB code is wrong at uiblib.pas.

  • FLockTimeout and LockTimeout variable must be integer!
  • FIXED parametering code:
    function CreateTRParams(Options: TTransParams; const LockRead, LockWrite: string{$IFDEF FB20_UP}; LockTimeout: integer{$ENDIF}): RawByteString;
    ...
      begin
      {$IFDEF FB20_UP}
      if LockTimeout = 0 then
          Exclude(Options, tpLockTimeout)
      else begin // -1 = infinite,   1..2048M = seconds
          Exclude(Options, tpnoWait);
          Include(Options, tpWait );
          Include(Options, tpLockTimeout);
      end;
      {$ENDIF}
      if Options = [tpConcurrency,tpWait,tpWrite] then
        result := ''
      else
        begin
          Result := isc_tpb_version3;
          for tp := Low(TTransParam) to High(TTransParam) do
            if (tp in Options) then
            begin
              case tp of
                tpLockRead   : ParseStrOption(tpc[tp], AnsiString(LockRead));
                tpLockWrite   : ParseStrOption(tpc[tp], AnsiString(LockWrite));
              {$IFDEF FB20_UP}
                tpLockTimeout : 
    //old code: PAnsiChar(@LockTimeout)[0] + PAnsiChar(LockTimeout)[1]; << [1] causing AV error
                  case LockTimeout of
                    -1     : Result := Result + tpc[tp] + #4#127#255#255#255;
    //               0     : Result := Result + tpc[tp] + #1#0; // this would be invalid
                    1..255: Result := Result + tpc[tp] + #1 + AnsiChar(Byte( LockTimeout and $FF));
                  else //256..32k
                            Result := Result + tpc[tp] + #2 + AnsiChar(Byte((LockTimeout div $FF) and $FF)) + AnsiChar(Byte(LockTimeout and $FF));
                  end;
              {$ENDIF}
              else
                Result := Result + tpc[tp];
              end;
            end;
        end;
    end;

Feature request 4
Did not find any solution to reconnect to the SAME transaction previously lost.