Решение проблем дисконнекта в IBX


базируется на переписке ThreeDHead и Vlad Filippov:

 окончательный вариант для IBX 6.03 выглядит так:

//--------------------------------------------
//IBCustomDataSet.pas
//--------------------------------------------

procedure TIBCustomDataSet.DoBeforeTransactionEnd(Sender: TObject);
begin
  if Active then
    Active := False;
  if FQSelect <> nil then
  try                   // <--- My changes
    FQSelect.FreeHandle;
  except                // <--- My changes
  end;                  // <--- My changes
  if FQDelete <> nil then
  try                   // <--- My changes
    FQDelete.FreeHandle;
  except                // <--- My changes
  end;                  // <--- My changes
  if FQInsert <> nil then
  try                   // <--- My changes
    FQInsert.FreeHandle;
  except                // <--- My changes
  end;                  // <--- My changes
  if FQModify <> nil then
  try                   // <--- My changes
    FQModify.FreeHandle;
  except                // <--- My changes
  end;                  // <--- My changes
  if FQRefresh <> nil then
  try                    // <--- My changes
    FQRefresh.FreeHandle;
  except                 // <--- My changes
  end;                   // <--- My changes
  FInternalPrepared := false;
  if Assigned(FBeforeTransactionEnd) then
    FBeforeTransactionEnd(Sender);
end;

procedure TIBCustomDataSet.InternalClose;
begin
  if Assigned(Transaction) then
    Transaction.CheckAutoStop;
  try              // <--- My changes
    FQSelect.Close;
  except           // <--- My changes
  end;             // <--- My changes
  ClearBlobCache;
  FreeRecordBuffer(FModelBuffer);
  FreeRecordBuffer(FOldBuffer);
  FCurrentRecord := -1;
  FOpen := False;
  FRecordCount := 0;
  FDeletedRecords := 0;
  FRecordSize := 0;
  FBPos := 0;
  FOBPos := 0;
  FCacheSize := 0;
  FOldCacheSize := 0;
  FBEnd := 0;
  FOBEnd := 0;
  ReallocMem(FBufferCache, 0);
  ReallocMem(FOldBufferCache, 0);
  BindFields(False);
  FUpdatesPending := false;
  if DefaultFields then
    DestroyFields;
end;

//--------------------------------------------
IBSQL.pas
//--------------------------------------------

procedure TIBSQL.FreeHandle;
var
  isc_res: ISC_STATUS;
begin
  try
    { The following two lines merely set the SQLDA count
     variable FCount to 0, but do not deallocate
     That way the allocations can be reused for
     a new query sring in the same SQL instance }
    FSQLRecord.Count := 0;
    FSQLParams.Count := 0;
    if (FHandle <> nil) and (not CheckStatusVector([isc_network_error]))
then  // <--- My changes (NB)
    begin
      isc_res :=
        Call(isc_dsql_free_statement(StatusVector, @FHandle, DSQL_drop),
False);
      if (StatusVector^ = 1) and (isc_res > 0) and (isc_res <>
isc_bad_stmt_handle) and
         (isc_res <> isc_lost_db_connection) then
        IBDataBaseError;
    end;
  finally
    FPrepared := False;
    FHandle := nil;
  end;
end;

//--------------------------------------------
//IBDatabase.pas
//--------------------------------------------

procedure TIBDatabase.InternalClose(Force: Boolean);
var
  i: Integer;
begin
  CheckActive;
  { Tell all connected transactions that we're disconnecting.
    This is so transactions can commit/rollback, accordingly
  }
  for i := 0 to FTransactions.Count - 1 do
  begin
    try
      if FTransactions[i] <> nil then
        Transactions[i].BeforeDatabaseDisconnect(Self);
    except
      if not Force then
        raise;
    end;
  end;
  for i := 0 to FSQLObjects.Count - 1 do
  begin
    try
      if FSQLObjects[i] <> nil then
      try                                        // <--- My changes
        SQLObjects[i].DoBeforeDatabaseDisconnect;
      except                                     // <--- My changes
      end;                                       // <--- My changes
    except
      if not Force then
        raise;
    end;
  end;

  if (not HandleIsShared) then               // <--- My changes (NB)
  begin                                      // <--- My changes (NB)
    if (not CheckStatusVector([isc_network_error])) and //<--- My changes
(NB)
       (Call(isc_detach_database(StatusVector,@FHandle),False) > 0) and
//<--- My changes (NB)
       (not Force) then                      // <--- My changes (NB)
      IBDataBaseError;
  end                                        // <--- My changes (NB)
  else
  begin
    FHandle := nil;
    FHandleIsShared := False;
  end;

  if not (csDesigning in ComponentState) then
    MonitorHook.DBDisconnect(Self);

  for i := 0 to FSQLObjects.Count - 1 do
    if FSQLObjects[i] <> nil then
      SQLObjects[i].DoAfterDatabaseDisconnect;
end;

procedure TIBTransaction.EndTransaction(Action: TTransactionAction;
  Force: Boolean);
var
  status: ISC_STATUS;
  i: Integer;
begin
  CheckInTransaction;
  case Action of
    TARollback, TACommit:
    begin
      if (HandleIsShared) and
         (Action <> FDefaultAction) and
         (not Force) then
        IBError(ibxeCantEndSharedTransaction, [nil]);
      for i := 0 to FSQLObjects.Count - 1 do
        if FSQLObjects[i] <> nil then
        try                                    // <--- My changes
          SQLObjects[i].DoBeforeTransactionEnd;
        except                                 // <--- My changes
        end;                                   // <--- My changes

...................далее без изменений