问题
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
.OnConnectionLossevent 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:
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.
FLockTimeoutandLockTimeoutvariable 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.
来源:https://stackoverflow.com/questions/57834670/how-to-reconnect-to-the-same-uibdatabase-uibtransaction-after-network-loss