0

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.
SzakiLaci
  • 347
  • 1
  • 16
  • If you're re-doing everything anyway, you should seriously consider a stateless connection, such as REST. – Jerry Dodge Sep 07 '19 at 14:37
  • As I've wrote: *we are reconstructing the "old IBX non-stop-connected" way to the "new way".* Now it's not working stable at all. I AM connecting **only to check the changes.** Only after received a **FB event.** All data stored in memory using thread safe variables. – SzakiLaci Sep 07 '19 at 14:48
  • @JerryDodge *We have tried to develop a REST api + mobile app, waisted 4 years and millions. Went all into trash. No more. We need a solution to the above problem.* – SzakiLaci Sep 07 '19 at 14:49
  • If I was in your situation, I ask myself, what would I do? The first thing I would do is change my database components. In Delphi 7, you have the choice of using IBX or DBX with Upscene Productions Firebird driver. (You can find it one the wayback machine) – Freddie Bell Sep 07 '19 at 17:19

1 Answers1

0

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.

SzakiLaci
  • 347
  • 1
  • 16
  • You won't be able to reconnect the SAME transaction previously lost because Firebird witll detect the connection lost and terminate the transaction. You have to reconnect and open a new transaction. As far as I can understand you are using long running transaction, this is a serious design flaw. Your transactions should be as short as possible. – ZeDalaye Sep 26 '19 at 14:41