ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabase.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBDatabase.pas (file contents):
Revision 5 by tony, Fri Feb 18 16:26:16 2011 UTC vs.
Revision 35 by tony, Tue Jan 26 14:38:47 2016 UTC

# Line 24 | Line 24
24   {       Corporation. All Rights Reserved.                                }
25   {    Contributor(s): Jeff Overcash                                       }
26   {                                                                        }
27 + {    IBX For Lazarus (Firebird Express)                                  }
28 + {    Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29 + {    Portions created by MWA Software are copyright McCallum Whyman      }
30 + {    Associates Ltd 2011                                                 }
31 + {                                                                        }
32   {************************************************************************}
33  
34   unit IBDatabase;
# Line 33 | Line 38 | unit IBDatabase;
38   interface
39  
40   uses
41 < {$IFDEF LINUX }
37 <  unix,
38 < {$ELSE}
39 < {$DEFINE HAS_SQLMONITOR}
41 > {$IFDEF WINDOWS }
42    Windows,
43 + {$ELSE}
44 +  unix,
45   {$ENDIF}
46 <  Dialogs, Controls, StdCtrls, SysUtils, Classes, Forms, ExtCtrls, IBHeader, IBExternals, DB,
47 <  IB, DBLoginDlg;
46 >  SysUtils, Classes, FPTimer, IBHeader, IBExternals, DB,
47 >  IB, CustApp;
48  
49   const
50    DPBPrefix = 'isc_dpb_';
# Line 151 | Line 155 | type
155    { TIBDatabase }
156    TIBDataBase = class(TCustomConnection)
157    private
158 +    FAllowStreamedConnected: boolean;
159      FHiddenPassword: string;
160      FIBLoaded: Boolean;
161      FOnLogin: TIBDatabaseLoginEvent;
162 +    FSQLHourGlass: Boolean;
163      FTraceFlags: TTraceFlags;
164      FDBSQLDialect: Integer;
165      FSQLDialect: Integer;
# Line 172 | Line 178 | type
178      FDefaultTransaction: TIBTransaction;
179      FInternalTransaction: TIBTransaction;
180      FStreamedConnected: Boolean;
181 <    FTimer: TTimer;
181 >    FTimer: TFPTimer;
182      FUserNames: TStringList;
183      FDataSets: TList;
184 +    FLoginCalled: boolean;
185 +    FCharSetSizes: array of integer;
186 +    FCharSetNames: array of string;
187      procedure EnsureInactive;
188      function GetDBSQLDialect: Integer;
189      function GetSQLDialect: Integer;
# Line 189 | Line 198 | type
198      function GetTransaction(Index: Integer): TIBTransaction;
199      function GetTransactionCount: Integer;
200      function Login: Boolean;
201 +    procedure LoadCharSetInfo;
202      procedure SetDatabaseName(const Value: TIBFileName);
203      procedure SetDBParamByDPB(const Idx: Integer; Value: String);
204      procedure SetDBParams(Value: TStrings);
# Line 205 | Line 215 | type
215      procedure DoConnect; override;
216      procedure DoDisconnect; override;
217      function GetConnected: Boolean; override;
218 <    procedure Loaded; override;
218 >    procedure CheckStreamConnect;
219 >    procedure HandleException(Sender: TObject);
220      procedure Notification( AComponent: TComponent; Operation: TOperation); override;
221      function GetDataset(Index : longint) : TDataset; override;
222      function GetDataSetCount : Longint; override;
223 <
223 >    procedure ReadState(Reader: TReader); override;
224 >    procedure SetConnected (Value : boolean); override;
225    public
226      constructor Create(AOwner: TComponent); override;
227      destructor Destroy; override;
# Line 246 | Line 258 | type
258  
259    published
260      property Connected;
261 <    property StreamedConnected;
261 >    property AllowStreamedConnected: boolean read FAllowStreamedConnected
262 >             write FAllowStreamedConnected;
263      property DatabaseName: TIBFileName read FDBName write SetDatabaseName;
264      property Params: TStrings read FDBParams write SetDBParams;
265      property LoginPrompt default True;
# Line 254 | Line 267 | type
267                                                   write SetDefaultTransaction;
268      property IdleTimer: Integer read GetIdleTimer write SetIdleTimer;
269      property SQLDialect : Integer read GetSQLDialect write SetSQLDialect default 3;
270 +    property SQLHourGlass: Boolean read FSQLHourGlass write FSQLHourGlass default true;
271      property DBSQLDialect : Integer read FDBSQLDialect;
272      property TraceFlags: TTraceFlags read FTraceFlags write FTraceFlags;
273      property AfterConnect;
# Line 271 | Line 285 | type
285  
286    TIBTransaction = class(TComponent)
287    private
288 +    FAfterDelete: TNotifyEvent;
289 +    FAfterEdit: TNotifyEvent;
290 +    FAfterExecQuery: TNotifyEvent;
291 +    FAfterInsert: TNotifyEvent;
292 +    FAfterPost: TNotifyEvent;
293 +    FAfterTransactionEnd: TNotifyEvent;
294 +    FBeforeTransactionEnd: TNotifyEvent;
295      FIBLoaded: Boolean;
296      FCanTimeout         : Boolean;
297      FDatabases          : TList;
298 +    FOnStartTransaction: TNotifyEvent;
299      FSQLObjects         : TList;
300      FDefaultDatabase    : TIBDatabase;
301      FHandle             : TISC_TR_HANDLE;
# Line 282 | Line 304 | type
304      FStreamedActive     : Boolean;
305      FTPB                : PChar;
306      FTPBLength          : Short;
307 <    FTimer              : TTimer;
307 >    FTimer              : TFPTimer;
308      FDefaultAction      : TTransactionAction;
309      FTRParams           : TStrings;
310      FTRParamsChanged    : Boolean;
311 +    FInEndTransaction   : boolean;
312 +    FEndAction          : TTransactionAction;
313 +    procedure DoBeforeTransactionEnd;
314 +    procedure DoAfterTransactionEnd;
315 +    procedure DoOnStartTransaction;
316 +    procedure DoAfterExecQuery(Sender: TObject);
317 +    procedure DoAfterEdit(Sender: TObject);
318 +    procedure DoAfterDelete(Sender: TObject);
319 +    procedure DoAfterInsert(Sender: TObject);
320 +    procedure DoAfterPost(Sender: TObject);
321      procedure EnsureNotInTransaction;
322      procedure EndTransaction(Action: TTransactionAction; Force: Boolean);
323      function GetDatabase(Index: Integer): TIBDatabase;
# Line 327 | Line 359 | type
359      function AddDatabase(db: TIBDatabase): Integer;
360      function FindDatabase(db: TIBDatabase): Integer;
361      function FindDefaultDatabase: TIBDatabase;
362 +    function GetEndAction: TTransactionAction;
363      procedure RemoveDatabase(Idx: Integer);
364      procedure RemoveDatabases;
365      procedure CheckDatabasesInList;
# Line 348 | Line 381 | type
381      property DefaultAction: TTransactionAction read FDefaultAction write SetDefaultAction default taCommit;
382      property Params: TStrings read FTRParams write SetTRParams;
383      property OnIdleTimer: TNotifyEvent read FOnIdleTimer write FOnIdleTimer;
384 <  end;
384 >    property BeforeTransactionEnd: TNotifyEvent read FBeforeTransactionEnd
385 >                                             write FBeforeTransactionEnd;
386 >    property AfterTransactionEnd: TNotifyEvent read FAfterTransactionEnd
387 >                                            write FAfterTransactionEnd;
388 >    property OnStartTransaction: TNotifyEvent read FOnStartTransaction
389 >                                              write FOnStartTransaction;
390 >    property AfterExecQuery: TNotifyEvent read FAfterExecQuery
391 >                                              write FAfterExecQuery;
392 >    property AfterEdit: TNotifyEvent read FAfterEdit write FAfterEdit;
393 >    property AfterDelete: TNotifyEvent read FAfterDelete write FAfterDelete;
394 >    property AfterInsert: TNotifyEvent read FAfterInsert write FAfterInsert;
395 >    property AfterPost: TNotifyEvent read FAfterPost write FAfterPost;
396 >  end;
397 >
398 >  TTransactionEndEvent = procedure(Sender:TObject; Action: TTransactionAction) of object;
399 >  TBeforeDatabaseConnectEvent = procedure (Sender: TObject; DBParams: TStrings;
400 >                              var DBName: string) of object;
401  
402    { TIBBase }
403  
# Line 357 | Line 406 | type
406      connections. }
407    TIBBase = class(TObject)
408    protected
409 +    FBeforeDatabaseConnect: TBeforeDatabaseConnectEvent;
410      FDatabase: TIBDatabase;
411      FIndexInDatabase: Integer;
412      FTransaction: TIBTransaction;
# Line 364 | Line 414 | type
414      FOwner: TObject;
415      FBeforeDatabaseDisconnect: TNotifyEvent;
416      FAfterDatabaseDisconnect: TNotifyEvent;
417 +    FAfterDatabaseConnect: TNotifyEvent;
418      FOnDatabaseFree: TNotifyEvent;
419 <    FBeforeTransactionEnd: TNotifyEvent;
419 >    FBeforeTransactionEnd: TTransactionEndEvent;
420      FAfterTransactionEnd: TNotifyEvent;
421      FOnTransactionFree: TNotifyEvent;
422  
423 +    procedure DoBeforeDatabaseConnect(DBParams: TStrings;
424 +                              var DBName: string); virtual;
425 +    procedure DoAfterDatabaseConnect; virtual;
426      procedure DoBeforeDatabaseDisconnect; virtual;
427      procedure DoAfterDatabaseDisconnect; virtual;
428      procedure DoDatabaseFree; virtual;
429 <    procedure DoBeforeTransactionEnd; virtual;
429 >    procedure DoBeforeTransactionEnd(Action: TTransactionAction); virtual;
430      procedure DoAfterTransactionEnd; virtual;
431      procedure DoTransactionFree; virtual;
432      function GetDBHandle: PISC_DB_HANDLE; virtual;
# Line 384 | Line 438 | type
438      destructor Destroy; override;
439      procedure CheckDatabase; virtual;
440      procedure CheckTransaction; virtual;
441 +    procedure DoAfterExecQuery(Sender: TObject); virtual;
442 +    procedure DoAfterEdit(Sender: TObject); virtual;
443 +    procedure DoAfterDelete(Sender: TObject); virtual;
444 +    procedure DoAfterInsert(Sender: TObject); virtual;
445 +    procedure DoAfterPost(Sender: TObject); virtual;
446 +    function GetCharSetSize(CharSetID: integer): integer;
447 +    function GetDefaultCharSetSize: integer;
448 +    function GetCharSetName(CharSetID: integer): string;
449 +    function GetDefaultCharSetName: string;
450 +    procedure HandleException(Sender: TObject);
451 +    procedure SetCursor;
452 +    procedure RestoreCursor;
453    public
454 +    property BeforeDatabaseConnect: TBeforeDatabaseConnectEvent read FBeforeDatabaseConnect
455 +                                                 write FBeforeDatabaseConnect;
456 +    property AfterDatabaseConnect: TNotifyEvent read FAfterDatabaseConnect
457 +                                                write FAfterDatabaseConnect;
458      property BeforeDatabaseDisconnect: TNotifyEvent read FBeforeDatabaseDisconnect
459                                                     write FBeforeDatabaseDisconnect;
460      property AfterDatabaseDisconnect: TNotifyEvent read FAfterDatabaseDisconnect
461                                                    write FAfterDatabaseDisconnect;
462      property OnDatabaseFree: TNotifyEvent read FOnDatabaseFree write FOnDatabaseFree;
463 <    property BeforeTransactionEnd: TNotifyEvent read FBeforeTransactionEnd write FBeforeTransactionEnd;
463 >    property BeforeTransactionEnd: TTransactionEndEvent read FBeforeTransactionEnd write FBeforeTransactionEnd;
464      property AfterTransactionEnd: TNotifyEvent read FAfterTransactionEnd write FAfterTransactionEnd;
465      property OnTransactionFree: TNotifyEvent read FOnTransactionFree write FOnTransactionFree;
466      property Database: TIBDatabase read FDatabase
# Line 408 | Line 478 | procedure GenerateTPB(sl: TStrings; var
478  
479   implementation
480  
481 < uses IBIntf,{$IFDEF HAS_SQLMONITOR}IBSQLMonitor,{$ENDIF} IBCustomDataSet, IBDatabaseInfo, IBSQL, IBUtils, typInfo;
481 > uses IBIntf, IBSQLMonitor, IBCustomDataSet, IBDatabaseInfo, IBSQL, IBUtils,
482 >     typInfo;
483  
484   { TIBDatabase }
485  
486 < constructor TIBDatabase.Create(AOwner: TComponent);
486 > constructor TIBDataBase.Create(AOwner: TComponent);
487 > {$ifdef WINDOWS}
488 > var acp: uint;
489 > {$endif}
490   begin
491    inherited Create(AOwner);
492    FIBLoaded := False;
# Line 423 | Line 497 | begin
497    FTransactions := TList.Create;
498    FDBName := '';
499    FDBParams := TStringList.Create;
500 +  FSQLHourGlass := true;
501 +  if (AOwner <> nil) and
502 +     (AOwner is TCustomApplication) and
503 +     TCustomApplication(AOWner).ConsoleApplication then
504 +    LoginPrompt := false;
505 +  {$ifdef UNIX}
506 +  if csDesigning in ComponentState then
507 +    FDBParams.Add('lc_ctype=UTF8');
508 +  {$else}
509 +  {$ifdef WINDOWS}
510 +  if csDesigning in ComponentState then
511 +  begin
512 +    acp := GetACP;
513 +    if (acp >= 1250) and (acp <= 1254) then
514 +      FDBParams.Values['lc_ctype'] := Format('WIN%d',[acp]);
515 +  end;
516 +  {$endif}
517 +  {$endif}
518    FDBParamsChanged := True;
519    TStringList(FDBParams).OnChange := DBParamsChange;
520    TStringList(FDBParams).OnChanging := DBParamsChanging;
# Line 431 | Line 523 | begin
523    FUserNames := nil;
524    FInternalTransaction := TIBTransaction.Create(self);
525    FInternalTransaction.DefaultDatabase := Self;
526 <  FTimer := TTimer.Create(Self);
526 >  FTimer := TFPTimer.Create(Self);
527    FTimer.Enabled := False;
528    FTimer.Interval := 0;
529    FTimer.OnTimer := TimeoutConnection;
# Line 439 | Line 531 | begin
531    FSQLDialect := 3;
532    FTraceFlags := [];
533    FDataSets := TList.Create;
534 +  CheckStreamConnect;
535   end;
536  
537 < destructor TIBDatabase.Destroy;
537 > destructor TIBDataBase.Destroy;
538   var
539    i: Integer;
540   begin
# Line 467 | Line 560 | begin
560    inherited Destroy;
561   end;
562  
563 < function TIBDatabase.Call(ErrCode: ISC_STATUS;
564 <  RaiseError: Boolean): ISC_STATUS;
563 > function TIBDataBase.Call(ErrCode: ISC_STATUS; RaiseError: Boolean
564 >   ): ISC_STATUS;
565   begin
566    result := ErrCode;
567    FCanTimeout := False;
# Line 476 | Line 569 | begin
569      IBDataBaseError;
570   end;
571  
572 < procedure TIBDatabase.CheckActive;
572 > procedure TIBDataBase.CheckActive;
573   begin
574    if StreamedConnected and (not Connected) then
575      Loaded;
# Line 484 | Line 577 | begin
577      IBError(ibxeDatabaseClosed, [nil]);
578   end;
579  
580 < procedure TIBDatabase.EnsureInactive;
580 > procedure TIBDataBase.EnsureInactive;
581   begin
582    if csDesigning in ComponentState then
583    begin
# Line 493 | Line 586 | begin
586    end
587   end;
588  
589 < procedure TIBDatabase.CheckInactive;
589 > procedure TIBDataBase.CheckInactive;
590   begin
591    if FHandle <> nil then
592      IBError(ibxeDatabaseOpen, [nil]);
593   end;
594  
595 < procedure TIBDatabase.CheckDatabaseName;
595 > procedure TIBDataBase.CheckDatabaseName;
596   begin
597    if (FDBName = '') then
598      IBError(ibxeDatabaseNameMissing, [nil]);
599   end;
600  
601 < function TIBDatabase.AddSQLObject(ds: TIBBase): Integer;
601 > function TIBDataBase.AddSQLObject(ds: TIBBase): Integer;
602   begin
603    result := 0;
604    if (ds.Owner is TIBCustomDataSet) then
605 <  {$IFDEF LINUX}
513 <      FDataSets.Add(TDataSet(ds.Owner));
514 <  {$ELSE}
515 <      RegisterClient(TDataSet(ds.Owner));
516 <  {$ENDIF}
605 >    FDataSets.Add(ds.Owner);
606    while (result < FSQLObjects.Count) and (FSQLObjects[result] <> nil) do
607      Inc(result);
608    if (result = FSQLObjects.Count) then
# Line 522 | Line 611 | begin
611      FSQLObjects[result] := ds;
612   end;
613  
614 < function TIBDatabase.AddTransaction(TR: TIBTransaction): Integer;
614 > function TIBDataBase.AddTransaction(TR: TIBTransaction): Integer;
615   begin
616    result := FindTransaction(TR);
617    if result <> -1 then
# Line 539 | Line 628 | begin
628      FTransactions[result] := TR;
629   end;
630  
631 < procedure TIBDatabase.DoDisconnect;
631 > procedure TIBDataBase.DoDisconnect;
632   begin
633    if Connected then
634      InternalClose(False);
635    FDBSQLDialect := 1;
636 +  SetLength(FCharSetSizes,0);
637 +  SetLength(FCharSetNames,0);
638   end;
639  
640 < procedure TIBDatabase.CreateDatabase;
640 > procedure TIBDataBase.CreateDatabase;
641   var
642    tr_handle: TISC_TR_HANDLE;
643   begin
# Line 559 | Line 650 | begin
650      True);
651   end;
652  
653 < procedure TIBDatabase.DropDatabase;
653 > procedure TIBDataBase.DropDatabase;
654   begin
655    CheckActive;
656    Call(isc_drop_database(StatusVector, @FHandle), True);
657   end;
658  
659 < procedure TIBDatabase.DBParamsChange(Sender: TObject);
659 > procedure TIBDataBase.DBParamsChange(Sender: TObject);
660   begin
661    FDBParamsChanged := True;
662   end;
663  
664 < procedure TIBDatabase.DBParamsChanging(Sender: TObject);
664 > procedure TIBDataBase.DBParamsChanging(Sender: TObject);
665   begin
666    EnsureInactive;
667    CheckInactive;
668   end;
669  
670 < function TIBDatabase.FindTransaction(TR: TIBTransaction): Integer;
670 > function TIBDataBase.FindTransaction(TR: TIBTransaction): Integer;
671   var
672    i: Integer;
673   begin
# Line 589 | Line 680 | begin
680      end;
681   end;
682  
683 < function TIBDatabase.FindDefaultTransaction(): TIBTransaction;
683 > function TIBDataBase.FindDefaultTransaction: TIBTransaction;
684   var
685    i: Integer;
686   begin
# Line 607 | Line 698 | begin
698    end;
699   end;
700  
701 < procedure TIBDatabase.ForceClose;
701 > procedure TIBDataBase.ForceClose;
702   begin
703    if Connected then
704      InternalClose(True);
705   end;
706  
707 < function TIBDatabase.GetConnected: Boolean;
707 > function TIBDataBase.GetConnected: Boolean;
708   begin
709    result := FHandle <> nil;
710   end;
711  
712 < function TIBDatabase.GetSQLObject(Index: Integer): TIBBase;
712 > function TIBDataBase.GetSQLObject(Index: Integer): TIBBase;
713   begin
714    result := FSQLObjects[Index];
715   end;
716  
717 < function TIBDatabase.GetSQLObjectCount: Integer;
717 > function TIBDataBase.GetSQLObjectCount: Integer;
718   var
719    i: Integer;
720   begin
# Line 632 | Line 723 | begin
723      Inc(result);
724   end;
725  
726 < function TIBDatabase.GetDBParamByDPB(const Idx: Integer): String;
726 > function TIBDataBase.GetDBParamByDPB( const Idx: Integer): String;
727   var
728    ConstIdx, EqualsIdx: Integer;
729   begin
# Line 655 | Line 746 | begin
746      result := '';
747   end;
748  
749 < function TIBDatabase.GetIdleTimer: Integer;
749 > function TIBDataBase.GetIdleTimer: Integer;
750   begin
751    result := FTimer.Interval;
752   end;
753  
754 < function TIBDatabase.GetTransaction(Index: Integer): TIBTransaction;
754 > function TIBDataBase.GetTransaction(Index: Integer): TIBTransaction;
755   begin
756    result := FTransactions[Index];
757   end;
758  
759 < function TIBDatabase.GetTransactionCount: Integer;
759 > function TIBDataBase.GetTransactionCount: Integer;
760   var
761    i: Integer;
762   begin
# Line 675 | Line 766 | begin
766        Inc(result);
767   end;
768  
769 < function TIBDatabase.IndexOfDBConst(st: String): Integer;
769 > function TIBDataBase.IndexOfDBConst(st: String): Integer;
770   var
771    i, pos_of_str: Integer;
772   begin
# Line 691 | Line 782 | begin
782    end;
783   end;
784  
785 < procedure TIBDatabase.InternalClose(Force: Boolean);
785 > procedure TIBDataBase.InternalClose(Force: Boolean);
786   var
787    i: Integer;
788   begin
# Line 730 | Line 821 | begin
821      FHandleIsShared := False;
822    end;
823  
733  {$IFDEF HAS_SQLMONITOR}
824    if not (csDesigning in ComponentState) then
825      MonitorHook.DBDisconnect(Self);
736  {$ENDIF}
826  
827    for i := 0 to FSQLObjects.Count - 1 do
828      if FSQLObjects[i] <> nil then
829        SQLObjects[i].DoAfterDatabaseDisconnect;
830   end;
831  
832 < procedure TIBDatabase.Loaded;
832 > procedure TIBDataBase.LoadCharSetInfo;
833 > var Query: TIBSQL;
834 >    i: integer;
835 > begin
836 >  if not FInternalTransaction.Active then
837 >    FInternalTransaction.StartTransaction;
838 >  Query := TIBSQL.Create(self);
839 >  try
840 >    Query.Database := Self;
841 >    Query.Transaction := FInternalTransaction;
842 >    Query.SQL.Text := 'Select RDB$CHARACTER_SET_ID, RDB$BYTES_PER_CHARACTER, RDB$CHARACTER_SET_NAME ' +
843 >                      'From RDB$CHARACTER_SETS Order by 1 DESC'; {do not localize}
844 >    Query.Prepare;
845 >    Query.ExecQuery;
846 >    if not Query.EOF then
847 >    begin
848 >      SetLength(FCharSetSizes,Query.FieldByName('RDB$CHARACTER_SET_ID').AsInteger + 1);
849 >      SetLength(FCharSetNames,Query.FieldByName('RDB$CHARACTER_SET_ID').AsInteger + 1);
850 >      for i := 0 to Length(FCharSetSizes) - 1 do FCharSetSizes[i] := 1;
851 >      repeat
852 >        FCharSetSizes[Query.FieldByName('RDB$CHARACTER_SET_ID').AsInteger] :=
853 >                 Query.FieldByName('RDB$BYTES_PER_CHARACTER').AsInteger;
854 >        FCharSetNames[Query.FieldByName('RDB$CHARACTER_SET_ID').AsInteger] :=
855 >                 Query.FieldByName('RDB$CHARACTER_SET_NAME').AsString;
856 >        Query.Next;
857 >      until Query.EOF;
858 >    end;
859 >  finally
860 >    Query.free;
861 >    FInternalTransaction.Commit;
862 >  end;
863 > end;
864 >
865 > procedure TIBDataBase.CheckStreamConnect;
866   var
867    i: integer;
868   begin
869    try
870 <    if StreamedConnected and (not Connected) then
870 >    if not (csDesigning in ComponentState) and StreamedConnected and (not Connected) then
871      begin
750      inherited Loaded;
872        for i := 0 to FTransactions.Count - 1 do
873          if  FTransactions[i] <> nil then
874          begin
# Line 767 | Line 888 | begin
888      end;
889    except
890      if csDesigning in ComponentState then
891 <      Application.HandleException(Self)
891 >      HandleException(Self)
892      else
893        raise;
894    end;
895   end;
896  
897 < procedure TIBDatabase.Notification( AComponent: TComponent;
898 <                                        Operation: TOperation);
897 > procedure TIBDataBase.HandleException(Sender: TObject);
898 > var aParent: TComponent;
899 > begin
900 >  aParent := Owner;
901 >  while aParent <> nil do
902 >  begin
903 >    if aParent is TCustomApplication then
904 >    begin
905 >      TCustomApplication(aParent).HandleException(Sender);
906 >      Exit;
907 >    end;
908 >    aParent := aParent.Owner;
909 >  end;
910 >  SysUtils.ShowException(ExceptObject,ExceptAddr);
911 > end;
912 >
913 > procedure TIBDataBase.Notification(AComponent: TComponent;
914 >   Operation: TOperation);
915   var
916    i: Integer;
917   begin
# Line 788 | Line 925 | begin
925    end;
926   end;
927  
928 < function TIBDatabase.Login: Boolean;
928 > function TIBDataBase.Login: Boolean;
929   var
930    IndexOfUser, IndexOfPassword: Integer;
931    Username, Password, OldPassword: String;
# Line 812 | Line 949 | var
949    end;
950  
951   begin
952 <  if Assigned(FOnLogin) then
952 >  Result := false;
953 >  if FLoginCalled then Exit;
954 >  FLoginCalled := true;
955 >  try
956 >  if Assigned(FOnLogin) and not (csDesigning in ComponentState) then
957    begin
958      result := True;
959      LoginParams := TStringList.Create;
# Line 826 | Line 967 | begin
967      end;
968    end
969    else
970 +  if assigned(IBGUIInterface) then
971    begin
972      IndexOfUser := IndexOfDBConst(DPBConstantNames[isc_dpb_user_name]);
973      if IndexOfUser <> -1 then
# Line 840 | Line 982 | begin
982                                           Length(Params[IndexOfPassword]));
983        OldPassword := password;
984      end;
985 <    result := LoginDialogEx(DatabaseName, Username, Password, False);
985 >    result := IBGUIInterface.LoginDialogEx(DatabaseName, Username, Password, False);
986      if result then
987      begin
988        if IndexOfUser = -1 then
# Line 857 | Line 999 | begin
999            HidePassword;
1000        end;
1001      end;
1002 +  end
1003 +  else
1004 +  if LoginPrompt then
1005 +     IBError(ibxeNoLoginDialog,[]);
1006 +  finally
1007 +    FLoginCalled := false
1008    end;
1009   end;
1010  
1011 < procedure TIBDatabase.DoConnect;
1011 > procedure TIBDataBase.DoConnect;
1012   var
1013    DPB: String;
1014    TempDBParams: TStrings;
1015 <
1015 >  I: integer;
1016 >  aDBName: string;
1017   begin
1018    CheckInactive;
1019    CheckDatabaseName;
# Line 874 | Line 1023 | begin
1023      FDBParamsChanged := True;
1024    end;
1025    { Use builtin login prompt if requested }
1026 <  if LoginPrompt and not Login then
1026 >  if (LoginPrompt or (csDesigning in ComponentState)) and not Login then
1027      IBError(ibxeOperationCancelled, [nil]);
1028 <  { Generate a new DPB if necessary }
1029 <  if (FDBParamsChanged) then
1030 <  begin
1031 <    FDBParamsChanged := False;
1032 <    if (not LoginPrompt) or (FHiddenPassword = '') then
1033 <      GenerateDPB(FDBParams, DPB, FDPBLength)
1034 <    else
1035 <    begin
1036 <      TempDBParams := TStringList.Create;
1037 <      try
1038 <       TempDBParams.Assign(FDBParams);
1039 <       TempDBParams.Add('password=' + FHiddenPassword);
1040 <       GenerateDPB(TempDBParams, DPB, FDPBLength);
1041 <      finally
1042 <       TempDBParams.Free;
1043 <      end;
1044 <    end;
1045 <    IBAlloc(FDPB, 0, FDPBLength);
1046 <    Move(DPB[1], FDPB[0], FDPBLength);
1028 >
1029 >  TempDBParams := TStringList.Create;
1030 >  try
1031 >   TempDBParams.Assign(FDBParams);
1032 >   aDBName := FDBName;
1033 >   {Opportunity to override defaults}
1034 >   for i := 0 to FSQLObjects.Count - 1 do
1035 >   begin
1036 >       if FSQLObjects[i] <> nil then
1037 >         SQLObjects[i].DoBeforeDatabaseConnect(TempDBParams,aDBName);
1038 >   end;
1039 >
1040 >   { Generate a new DPB if necessary }
1041 >   if (FDBParamsChanged or (TempDBParams.Text <> FDBParams.Text)) then
1042 >   begin
1043 >     FDBParamsChanged := False;
1044 >     if (not LoginPrompt and not (csDesigning in ComponentState)) or (FHiddenPassword = '') then
1045 >       GenerateDPB(TempDBParams, DPB, FDPBLength)
1046 >     else
1047 >     begin
1048 >        TempDBParams.Add('password=' + FHiddenPassword);
1049 >        GenerateDPB(TempDBParams, DPB, FDPBLength);
1050 >     end;
1051 >     IBAlloc(FDPB, 0, FDPBLength);
1052 >     Move(DPB[1], FDPB[0], FDPBLength);
1053 >   end;
1054 >  finally
1055 >   TempDBParams.Free;
1056    end;
1057 <  if Call(isc_attach_database(StatusVector, Length(FDBName),
1058 <                         PChar(FDBName), @FHandle,
1057 >  if Call(isc_attach_database(StatusVector, Length(aDBName),
1058 >                         PChar(aDBName), @FHandle,
1059                           FDPBLength, FDPB), False) > 0 then
1060    begin
1061      FHandle := nil;
1062      IBDataBaseError;
1063    end;
1064 +  if not (csDesigning in ComponentState) then
1065 +    FDBName := aDBName; {Synchronise at run time}
1066    FDBSQLDialect := GetDBSQLDialect;
1067    ValidateClientSQLDialect;
1068 <  {$IFDEF HAS_SQLMONITOR}
1068 >  for i := 0 to FSQLObjects.Count - 1 do
1069 >  begin
1070 >      if FSQLObjects[i] <> nil then
1071 >        SQLObjects[i].DoAfterDatabaseConnect;
1072 >  end;
1073    if not (csDesigning in ComponentState) then
1074      MonitorHook.DBConnect(Self);
1075 <  {$ENDIF}
1075 >  LoadCharSetInfo;
1076   end;
1077  
1078 < procedure TIBDatabase.RemoveSQLObject(Idx: Integer);
1078 > procedure TIBDataBase.RemoveSQLObject(Idx: Integer);
1079   var
1080    ds: TIBBase;
1081   begin
# Line 921 | Line 1085 | begin
1085      FSQLObjects[Idx] := nil;
1086      ds.Database := nil;
1087      if (ds.owner is TDataSet) then
924    {$IFDEF LINUX}
1088        FDataSets.Remove(TDataSet(ds.Owner));
926    {$ELSE}
927      UnregisterClient(TDataSet(ds.Owner));
928    {$ENDIF}
1089    end;
1090   end;
1091  
1092 < procedure TIBDatabase.RemoveSQLObjects;
1092 > procedure TIBDataBase.RemoveSQLObjects;
1093   var
1094    i: Integer;
1095   begin
# Line 937 | Line 1097 | begin
1097    begin
1098      RemoveSQLObject(i);
1099      if (TIBBase(FSQLObjects[i]).owner is TDataSet) then
940    {$IFDEF LINUX}
1100        FDataSets.Remove(TDataSet(TIBBase(FSQLObjects[i]).owner));
942    {$ELSE}
943      UnregisterClient(TDataSet(TIBBase(FSQLObjects[i]).owner));
944    {$ENDIF}
1101    end;
1102   end;
1103  
1104 < procedure TIBDatabase.RemoveTransaction(Idx: Integer);
1104 > procedure TIBDataBase.RemoveTransaction(Idx: Integer);
1105   var
1106    TR: TIBTransaction;
1107   begin
# Line 959 | Line 1115 | begin
1115    end;
1116   end;
1117  
1118 < procedure TIBDatabase.RemoveTransactions;
1118 > procedure TIBDataBase.RemoveTransactions;
1119   var
1120    i: Integer;
1121   begin
# Line 967 | Line 1123 | begin
1123      RemoveTransaction(i);
1124   end;
1125  
1126 < procedure TIBDatabase.SetDatabaseName(const Value: TIBFileName);
1126 > procedure TIBDataBase.SetDatabaseName( const Value: TIBFileName);
1127   begin
1128    if FDBName <> Value then
1129    begin
# Line 977 | Line 1133 | begin
1133    end;
1134   end;
1135  
1136 < procedure TIBDatabase.SetDBParamByDPB(const Idx: Integer; Value: String);
1136 > procedure TIBDataBase.SetDBParamByDPB( const Idx: Integer; Value: String);
1137   var
1138    ConstIdx: Integer;
1139   begin
# Line 996 | Line 1152 | begin
1152    end;
1153   end;
1154  
1155 < procedure TIBDatabase.SetDBParams(Value: TStrings);
1155 > procedure TIBDataBase.SetDBParams(Value: TStrings);
1156   begin
1157    FDBParams.Assign(Value);
1158   end;
1159  
1160 < procedure TIBDatabase.SetDefaultTransaction(Value: TIBTransaction);
1160 > procedure TIBDataBase.SetDefaultTransaction(Value: TIBTransaction);
1161   var
1162    i: Integer;
1163   begin
# Line 1019 | Line 1175 | begin
1175    FDefaultTransaction := Value;
1176   end;
1177  
1178 < procedure TIBDatabase.SetHandle(Value: TISC_DB_HANDLE);
1178 > procedure TIBDataBase.SetHandle(Value: TISC_DB_HANDLE);
1179   begin
1180    if HandleIsShared then
1181      Close
# Line 1029 | Line 1185 | begin
1185    FHandleIsShared := (Value <> nil);
1186   end;
1187  
1188 < procedure TIBDatabase.SetIdleTimer(Value: Integer);
1188 > procedure TIBDataBase.SetIdleTimer(Value: Integer);
1189   begin
1190    if Value < 0 then
1191      IBError(ibxeTimeoutNegative, [nil])
# Line 1048 | Line 1204 | begin
1204        end;
1205   end;
1206  
1207 < function TIBDatabase.TestConnected: Boolean;
1207 > function TIBDataBase.TestConnected: Boolean;
1208   var
1209    DatabaseInfo: TIBDatabaseInfo;
1210   begin
# Line 1069 | Line 1225 | begin
1225    end;
1226   end;
1227  
1228 < procedure TIBDatabase.TimeoutConnection(Sender: TObject);
1228 > procedure TIBDataBase.TimeoutConnection(Sender: TObject);
1229   begin
1230    if Connected then
1231    begin
# Line 1084 | Line 1240 | begin
1240    end;
1241   end;
1242  
1243 < function TIBDatabase.GetIsReadOnly: Boolean;
1243 > function TIBDataBase.GetIsReadOnly: Boolean;
1244   var
1245    DatabaseInfo: TIBDatabaseInfo;
1246   begin
# Line 1102 | Line 1258 | begin
1258    DatabaseInfo.Free;
1259   end;
1260  
1261 < function TIBDatabase.GetSQLDialect: Integer;
1261 > function TIBDataBase.GetSQLDialect: Integer;
1262   begin
1263    Result := FSQLDialect;
1264   end;
1265  
1266 < procedure TIBDatabase.SetSQLDialect(const Value: Integer);
1266 >
1267 > procedure TIBDataBase.SetSQLDialect( const Value: Integer);
1268   begin
1269    if (Value < 1) then IBError(ibxeSQLDialectInvalid, [nil]);
1270    if ((FHandle = nil) or (Value <= FDBSQLDialect))  then
# Line 1116 | Line 1273 | begin
1273      IBError(ibxeSQLDialectInvalid, [nil]);
1274   end;
1275  
1276 < function TIBDatabase.GetDBSQLDialect: Integer;
1276 > function TIBDataBase.GetDBSQLDialect: Integer;
1277   var
1278    DatabaseInfo: TIBDatabaseInfo;
1279   begin
# Line 1126 | Line 1283 | begin
1283    DatabaseInfo.Free;
1284   end;
1285  
1286 < procedure TIBDatabase.ValidateClientSQLDialect;
1286 > procedure TIBDataBase.ValidateClientSQLDialect;
1287   begin
1288    if (FDBSQLDialect < FSQLDialect) then
1289    begin
# Line 1136 | Line 1293 | begin
1293    end;
1294   end;
1295  
1296 < procedure TIBDatabase.ApplyUpdates(const DataSets: array of TDataSet);
1296 > procedure TIBDataBase.ApplyUpdates( const DataSets: array of TDataSet);
1297   var
1298    I: Integer;
1299    DS: TIBCustomDataSet;
# Line 1162 | Line 1319 | begin
1319    TR.CommitRetaining;
1320   end;
1321  
1322 < procedure TIBDatabase.CloseDataSets;
1322 > procedure TIBDataBase.CloseDataSets;
1323   var
1324    i: Integer;
1325   begin
# Line 1171 | Line 1328 | begin
1328        DataSets[i].close;
1329   end;
1330  
1331 < function TIBDatabase.GetDataset(Index : longint) : TDataset;
1331 > function TIBDataBase.GetDataset(Index: longint): TDataset;
1332   begin
1333    if (Index >= 0) and (Index < FDataSets.Count) then
1334      Result := TDataSet(FDataSets[Index])
# Line 1179 | Line 1336 | begin
1336      raise Exception.Create('Invalid Index to DataSets');
1337   end;
1338  
1339 < function TIBDatabase.GetDataSetCount : Longint;
1339 > function TIBDataBase.GetDataSetCount: Longint;
1340   begin
1341    Result := FDataSets.Count;
1342   end;
1343  
1344 < procedure TIBDatabase.GetFieldNames(const TableName: string; List: TStrings);
1344 > procedure TIBDataBase.ReadState(Reader: TReader);
1345 > begin
1346 >  FDBParams.Clear;
1347 >  inherited ReadState(Reader);
1348 > end;
1349 >
1350 > procedure TIBDataBase.SetConnected(Value: boolean);
1351 > begin
1352 >  if StreamedConnected and not AllowStreamedConnected then
1353 >  begin
1354 >    StreamedConnected := false;
1355 >    Value := false
1356 >  end;
1357 >  inherited SetConnected(Value);
1358 > end;
1359 >
1360 > procedure TIBDataBase.GetFieldNames( const TableName: string; List: TStrings);
1361   var
1362    Query: TIBSQL;
1363   begin
# Line 1225 | Line 1398 | begin
1398    end;
1399   end;
1400  
1401 < procedure TIBDatabase.GetTableNames(List: TStrings; SystemTables: Boolean);
1401 > procedure TIBDataBase.GetTableNames(List: TStrings; SystemTables: Boolean);
1402   var
1403    Query : TIBSQL;
1404   begin
# Line 1284 | Line 1457 | begin
1457    FTRParamsChanged := True;
1458    TStringList(FTRParams).OnChange := TRParamsChange;
1459    TStringList(FTRParams).OnChanging := TRParamsChanging;
1460 <  FTimer := TTimer.Create(Self);
1460 >  FTimer := TFPTimer.Create(Self);
1461    FTimer.Enabled := False;
1462    FTimer.Interval := 0;
1463    FTimer.OnTimer := TimeoutTransaction;
# Line 1340 | Line 1513 | begin
1513      IBError(ibxeNotInTransaction, [nil]);
1514   end;
1515  
1516 + procedure TIBTransaction.DoBeforeTransactionEnd;
1517 + begin
1518 +  if Assigned(FBeforeTransactionEnd) then
1519 +    FBeforeTransactionEnd(self);
1520 + end;
1521 +
1522 + procedure TIBTransaction.DoAfterTransactionEnd;
1523 + begin
1524 +  if Assigned(FAfterTransactionEnd) then
1525 +    FAfterTransactionEnd(self);
1526 + end;
1527 +
1528 + procedure TIBTransaction.DoOnStartTransaction;
1529 + begin
1530 +  if assigned(FOnStartTransaction) then
1531 +    OnStartTransaction(self);
1532 + end;
1533 +
1534 + procedure TIBTransaction.DoAfterExecQuery(Sender: TObject);
1535 + begin
1536 +  if assigned(FAfterExecQuery) then
1537 +    AfterExecQuery(Sender);
1538 + end;
1539 +
1540 + procedure TIBTransaction.DoAfterEdit(Sender: TObject);
1541 + begin
1542 +  if assigned(FAfterEdit) then
1543 +    AfterEdit(Sender);
1544 + end;
1545 +
1546 + procedure TIBTransaction.DoAfterDelete(Sender: TObject);
1547 + begin
1548 +  if assigned(FAfterDelete) then
1549 +    AfterDelete(Sender);
1550 + end;
1551 +
1552 + procedure TIBTransaction.DoAfterInsert(Sender: TObject);
1553 + begin
1554 +  if assigned(FAfterInsert) then
1555 +    AfterInsert(Sender);
1556 + end;
1557 +
1558 + procedure TIBTransaction.DoAfterPost(Sender: TObject);
1559 + begin
1560 +  if assigned(FAfterPost) then
1561 +    AfterPost(Sender);
1562 + end;
1563 +
1564   procedure TIBTransaction.EnsureNotInTransaction;
1565   begin
1566    if csDesigning in ComponentState then
# Line 1414 | Line 1635 | var
1635    i: Integer;
1636   begin
1637    CheckInTransaction;
1638 +  if FInEndTransaction then Exit;
1639 +  FInEndTransaction := true;
1640 +  FEndAction := Action;
1641 +  try
1642    case Action of
1643      TARollback, TACommit:
1644      begin
# Line 1421 | Line 1646 | begin
1646           (Action <> FDefaultAction) and
1647           (not Force) then
1648          IBError(ibxeCantEndSharedTransaction, [nil]);
1649 +      DoBeforeTransactionEnd;
1650        for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1651 <        SQLObjects[i].DoBeforeTransactionEnd;
1651 >        SQLObjects[i].DoBeforeTransactionEnd(Action);
1652        if InTransaction then
1653        begin
1654          if HandleIsShared then
# Line 1445 | Line 1671 | begin
1671              IBDataBaseError;
1672          for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1673            SQLObjects[i].DoAfterTransactionEnd;
1674 +        DoAfterTransactionEnd;
1675        end;
1676      end;
1677      TACommitRetaining:
# Line 1452 | Line 1679 | begin
1679      TARollbackRetaining:
1680        Call(isc_rollback_retaining(StatusVector, @FHandle), True);
1681    end;
1455  {$IFDEF HAS_SQLMONITOR}
1682    if not (csDesigning in ComponentState) then
1683    begin
1684      case Action of
# Line 1466 | Line 1692 | begin
1692          MonitorHook.TRRollbackRetaining(Self);
1693      end;
1694    end;
1695 <  {$ENDIF}
1695 >  finally
1696 >    FInEndTransaction := false
1697 >  end;
1698   end;
1699  
1700   function TIBTransaction.GetDatabase(Index: Integer): TIBDatabase;
# Line 1534 | Line 1762 | begin
1762    end;
1763   end;
1764  
1765 + function TIBTransaction.GetEndAction: TTransactionAction;
1766 + begin
1767 +  if FInEndTransaction then
1768 +     Result := FEndAction
1769 +  else
1770 +     IBError(ibxeIB60feature, [nil])
1771 + end;
1772 +
1773  
1774   function TIBTransaction.GetIdleTimer: Integer;
1775   begin
# Line 1639 | Line 1875 | begin
1875      for i := 0 to FSQLObjects.Count - 1 do
1876        if (FSQLObjects[i] <> nil) and
1877           (TIBBase(FSQLObjects[i]).Database = nil) then
1878 <        SetOrdProp(TIBBase(FSQLObjects[i]).Owner, 'Database', Integer(Value));
1878 >         SetObjectProp(TIBBase(FSQLObjects[i]).Owner, 'Database', Value);
1879    end;
1880    FDefaultDatabase := Value;
1881   end;
# Line 1740 | Line 1976 | begin
1976        FHandle := nil;
1977        IBDataBaseError;
1978      end;
1743  {$IFDEF HAS_SQLMONITOR}
1979      if not (csDesigning in ComponentState) then
1980        MonitorHook.TRStart(Self);
1746  {$ENDIF}
1981    finally
1982      FreeMem(pteb);
1983    end;
1984 +  DoOnStartTransaction;
1985   end;
1986  
1987   procedure TIBTransaction.TimeoutTransaction(Sender: TObject);
# Line 1788 | Line 2023 | begin
2023    inherited Destroy;
2024   end;
2025  
2026 + function TIBBase.GetCharSetSize(CharSetID: integer): integer;
2027 + begin
2028 +  if (CharSetID >= 0) and (CharSetID < Length(Database.FCharSetSizes)) then
2029 +    Result := Database.FCharSetSizes[CharSetID]
2030 +  else
2031 +    Result := 1; {Unknown character set}
2032 + end;
2033 +
2034 + function TIBBase.GetDefaultCharSetSize: integer;
2035 + var DefaultCharSetName: string;
2036 +    i: integer;
2037 + begin
2038 +  DefaultCharSetName := GetDefaultCharSetName;
2039 +  Result := 4; {worse case}
2040 +  for i := 0 to Length(Database.FCharSetSizes) - 1 do
2041 +    if Database.FCharSetNames[i] = DefaultCharSetName then
2042 +    begin
2043 +      Result := Database.FCharSetSizes[i];
2044 +      break;
2045 +    end;
2046 + end;
2047 +
2048 + function TIBBase.GetCharSetName(CharSetID: integer): string;
2049 + begin
2050 +  if (CharSetID >= 0) and (CharSetID < Length(Database.FCharSetNames)) then
2051 +    Result := Database.FCharSetNames[CharSetID]
2052 +  else
2053 +    Result := ''; {Unknown character set}
2054 + end;
2055 +
2056 + function TIBBase.GetDefaultCharSetName: string;
2057 + begin
2058 +  Result := AnsiUpperCase(Database.Params.Values['lc_ctype']);
2059 + end;
2060 +
2061 + procedure TIBBase.HandleException(Sender: TObject);
2062 + begin
2063 +  if assigned(Database) then
2064 +     Database.HandleException(Sender)
2065 +  else
2066 +     SysUtils.ShowException(ExceptObject,ExceptAddr);
2067 + end;
2068 +
2069 + procedure TIBBase.SetCursor;
2070 + begin
2071 +  if Assigned(Database) and not Database.SQLHourGlass then
2072 +     Exit;
2073 +  if assigned(IBGUIInterface) then
2074 +     IBGUIInterface.SetCursor;
2075 + end;
2076 +
2077 + procedure TIBBase.RestoreCursor;
2078 + begin
2079 +  if Assigned(Database) and not Database.SQLHourGlass then
2080 +     Exit;
2081 +  if assigned(IBGUIInterface) then
2082 +     IBGUIInterface.RestoreCursor;
2083 + end;
2084 +
2085   procedure TIBBase.CheckDatabase;
2086   begin
2087    if (FDatabase = nil) then
# Line 1814 | Line 2108 | begin
2108    result := @FTransaction.Handle;
2109   end;
2110  
2111 + procedure TIBBase.DoBeforeDatabaseConnect(DBParams: TStrings; var DBName: string
2112 +  );
2113 + begin
2114 +  if assigned(FBeforeDatabaseConnect) then
2115 +    BeforeDatabaseConnect(self,DBParams,DBName);
2116 + end;
2117 +
2118 + procedure TIBBase.DoAfterDatabaseConnect;
2119 + begin
2120 +  if assigned(FAfterDatabaseConnect) then
2121 +    AfterDatabaseConnect(self);
2122 + end;
2123 +
2124   procedure TIBBase.DoBeforeDatabaseDisconnect;
2125   begin
2126    if Assigned(BeforeDatabaseDisconnect) then
# Line 1834 | Line 2141 | begin
2141    SetTransaction(nil);
2142   end;
2143  
2144 < procedure TIBBase.DoBeforeTransactionEnd;
2144 > procedure TIBBase.DoBeforeTransactionEnd(Action: TTransactionAction);
2145   begin
2146    if Assigned(BeforeTransactionEnd) then
2147 <    BeforeTransactionEnd(Self);
2147 >    BeforeTransactionEnd(Self,Action);
2148   end;
2149  
2150   procedure TIBBase.DoAfterTransactionEnd;
# Line 1853 | Line 2160 | begin
2160    FTransaction := nil;
2161   end;
2162  
2163 + procedure TIBBase.DoAfterExecQuery(Sender: TObject);
2164 + begin
2165 +  if FTransaction <> nil then
2166 +    FTransaction.DoAfterExecQuery(Sender);
2167 + end;
2168 +
2169 + procedure TIBBase.DoAfterEdit(Sender: TObject);
2170 + begin
2171 +  if FTransaction <> nil then
2172 +    FTransaction.DoAfterEdit(Sender);
2173 + end;
2174 +
2175 + procedure TIBBase.DoAfterDelete(Sender: TObject);
2176 + begin
2177 +  if FTransaction <> nil then
2178 +    FTransaction.DoAfterDelete(Sender);
2179 + end;
2180 +
2181 + procedure TIBBase.DoAfterInsert(Sender: TObject);
2182 + begin
2183 +  if FTransaction <> nil then
2184 +    FTransaction.DoAfterInsert(Sender);
2185 + end;
2186 +
2187 + procedure TIBBase.DoAfterPost(Sender: TObject);
2188 + begin
2189 +  if FTransaction <> nil then
2190 +    FTransaction.DoAfterPost(Sender);
2191 + end;
2192 +
2193   procedure TIBBase.SetDatabase(Value: TIBDatabase);
2194   begin
2195    if (FDatabase <> nil) then

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines