unit dm_IBRepl;


(* Help: Library for developers that offers all IB replicator functionality to independent
         developers. Because it's possible implement replicator to own software no
         external IBReplServer >>ibreplserver.htt or ibreplc is necessary. >>ibreplc.htt
         
         ---- Topics
         -  Key Items                       >>#dm_ibrepl__KeyItems
         -  Example                         >>#dm_ibrepl__Example
         -  Implementation History          >>history.htt
         -  Background Information          >>description.htt
         -  License          	             >>license.htt
         
         
         ---- Key Items
         >>Marker dm_ibrepl__KeyItems
         
         -  ^TIBReplDataModule defines generic functions to replication
         -  ^TIBReplDataModule.IBCfgDB defines configuration database >>config.htt
         -  ^TIBReplDataModule.ReplicateOnline replicates database
         -  ^TIBReplDataModule.Synchronize synchronizes databases
         
         ---- Example
         >>Marker dm_ibrepl__Example
         
         Here's some sample code using replicator:
         
         (pascalsource)
         var
           ReplDM: TIBReplDataModule;
         begin
           ReplDM:= TIBReplDataModule.Create(nil);
           try
             with ReplDM do
             begin
               IBCfgDB.DatabaseName:= 'replconfig.gdb'
               IBCfgDB.Params.Values['user_name']:= 'SYSDBA;
               IBCfgDB.Params.Values['password']:= 'masterkey';
               IBCfgDB.Params.Values['lc_ctype']:= 'WIN1250';
               Synchronize(1);
             end;
           finally
             ReplDM.Free;
         end;
         (end pascalsource) *)


{ Listing generated by Opus Documentor 1.2.1.1147 on 19.3.2003 }
{ Parts omitted from listing: private }


{==============================================================================}
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
  IBDatabase, Db, IBSQL, IBCustomDataSet, ExtCtrls, IniFiles, Connect, IB, 
  IBBlob, Transfer, Magic, IBStoredProc;

const 
  saUpd = '01';
  (* Help: update during synchronization enabled *)

  saInsDel = '02';
  (* Help: insert/delete during synchronization enabled *)

  saSrcTgt = '04';
  (* Help: loop target relation *)

  saRO = '08';
  (* Help: don't update target database but create differential log *)

  dbtInterbase = 0;
  (* Help: Replication target is Interbase/Firebird database *)

  dbtLog = 1;
  (* Help: Replication target is replication log *)

  offrtRelationDef = 1;
  (* Help: >^TOffSrcRelDef *)

  offrtReplLog = 2;
  (* Help: >^TOffSrcReplLog *)

  offrtReplAck = 3;
  (* Help: >^TOffTgtReplAck *)

  offrrtReplAckAck = 4;
  (* Help: >^TOffSrcReplAckAck *)

  offrrtReplAckAckAck = 5;
  (* Help: >^TOffSrcReplAckAck *)

type 
  TOffStamp = array[ 1 .. 9 ] of Char;
  (* Help: Platform independent timestamp (no double, float cross platform problem) *)

  TRelName = array[ 1 .. 30 ] of Char;
  (* Help: Name of relation of a Interbase object *)

  TOffHeader = record
  (* Help: Header of offline package *)

    Magic: TOffMagic;
    (* Help: Magic number identifiing offline package *)

    SchemaId: LongInt;
    (* Help: Schema contained in offline package *)

    TransferId: LongInt;
    (* Help: Transfer identifier *)

    Status: Char;
    (* Help: -  $'S'$ .. package created on the source side
             -  $'T'$ .. package created on the target side *)

    SrcDBId: LongInt;
    (* Help: Source database identifier *)

    TgtDBId: LongInt;
    (* Help: Target database identifier *)

    GroupId: LongInt;
    (* Help: Database group identifier *)

    Stamp: TOffStamp;
    (* Help: Timestamp when package was created *)

    Reserved: array[ 0 .. 15 + 11 ] of Byte;
    (* Help: Reserved for future use *)

  end {TOffHeader};

  TOffSrcRelDefField = record
  (* Help: Field definition in the source relation *)

    FieldType: Byte;
    (* Help: Type of field, see FIELDS.FIELDTYPE >>config.htt#fields__fieldtype *)

    Name: TRelName;
    (* Help: Field name *)

  end {TOffSrcRelDefField};

  TOffSrcRelDef = record
  (* Help: Source relation definition
           
           > ^TOffSrcRelDefField *)

    RecType: Byte;
    (* Help: Must be equal to ^offrtRelationDef *)

    RelationId: LongInt;
    (* Help: Relation identifier *)

    Name: TRelName;
    (* Help: Relation name *)

    Count: Word;
    (* Help: Count of fields in relation.
             
             Follows:
             
             (pascal)
             Fields: array[0..Count-1] of TOffSrcRelDefField; *)

  end {TOffSrcRelDef};

  TOffSrcReplLog = record
  (* Help: Replication log record contains one REPL\$LOG record. >>replobj.htt#repllog
           
           First occurrence must be proceeded by relation definition >>#Docu_dm_IBRepl_TOffSrcRelDef
           
           > ^TOffSrcRelRec *)

    RecType: Byte;
    (* Help: Must be equal to ^offrtReplLog *)

    RelationId: LongInt;
    (* Help: Relation identifier *)

    SeqId: LongWord;
    (* Help: Seq. identifier from REPL\$LOG..SEQID >>replobj.htt#repllog *)

    RepType: Char;
    (* Help: Seq. identifier from REPL\$LOG. >>replobj.htt#repllog *)

    Sep: Char;
    (* Help: Used separator from REPL\$LOG.SEPARATOR >>replobj.htt#repllog *)

    Stamp: TOffStamp;
    (* Help: Timestamp from REPL\$LOG >>replobj.htt#repllog *)

    IsRelRecord: Byte;
    (* Help: If equal 0 not record is empty (record in source table was deleted)
             
             Field is followed by three wide ASCIIZ key fields from REPL\$LOG.NEWPKEY,OLDPKEY,NEWFKEY. >>replobj.htt#repllog
             
             If $IsRelRecord <> 0$ then follows:
             
             (pascal)
             RelRecord: TOffSrcRelRec; *)

  end {TOffSrcReplLog};

  TOffSrcRelRec = record
  (* Help: Record contains one source relation record values
           
           > ^TOffReplRecValue *)

    FieldCount: Word;
    (* Help: Count of fields in array that follows:
             
             (pascal)
             Values: array[0..Count-1] of TOffReplRecValue; *)

  end {TOffSrcRelRec};

  TOffReplRecValue = record
  (* Help: Value of a field in source relation *)

    DataType: Char;
    (* Help: Type of value that follows record:
             
             -  $N$ .. null
             -  $C$ .. string(65535), follows $Len: word; widestring$
             -  $O$ .. blob/memo/binary, follows $Len: longword; data$
             -  $D$ .. date, follows $longint$
             -  $T$ .. time, follows $byte$
             -  $S$ .. datetime, follows $yyyymmdd$
             -  $B$ .. boolean, follows $hhnnss$
             -  $I$ .. Integer, follows $yyyymnddhhnnsszzz$
             -  $F$ .. float, follows $extended$
             -  $' '$ .. field not found, follows $Len: longword; widestring$ *)

    FieldType: Byte;
    (* Help: Type of field ^TFieldType *)

  end {TOffReplRecValue};

  TOffTgtReplAckRec = record
  (* Help: Result of record replication *)

    Flag: Byte;
    (* Help: -  $0$ .. delete record from REPL\$LOG
             -  $1$ .. move record to REPL\$MAN *)

    SeqId: LongInt;
    (* Help: Sequential id of corresponding REPL\$LOG.SEQID record >>replobj.htt#repllog *)

  end {TOffTgtReplAckRec};

  TOffTgtReplAck = record
  (* Help: Record contained in acknowledge package (2nd pass)
           
           > ^TOffTgtReplAckRec *)

    RecType: Byte;
    (* Help: Must be equal to ^offrtReplAck *)

    TransferIdAck: LongInt;
    (* Help: Identified of the source transfer id *)

    StampRec: TOffStamp;
    (* Help: Timestamp when source package was received *)

    StampProc: TOffStamp;
    (* Help: Timestamp when source package was processed *)

    ProcCount: LongInt;
    (* Help: Number of processed records
             
             Follows:
             
             (pascal)
             SeqIds: array[0..ProcCount-1] of TOffTgtReplAckRec; *)

  end {TOffTgtReplAck};

  TOffSrcReplAckAck = record
  (* Help: Record contained in acknowledge package (3rd pass) *)

    RecType: Byte;
    (* Help: Must be equal to ^offrrtReplAckAck *)

    TransferId: LongInt;
    (* Help: Identified of 1st pass transfer package *)

    TransferIdAck: LongInt;
    (* Help: Identifier of 2nd pass transfer package *)

    StampSent: TOffStamp;
    (* Help: Timestamp when 1st pass package was sent *)

    StampRec: TOffStamp;
    (* Help: Timestamp when 2nd pass was received *)

    StampProc: TOffStamp;
    (* Help: Timestamp when 2nd pass was processed *)

  end {TOffSrcReplAckAck};

  TOffTgtReplAckAckAck = record
  (* Help: Record contained in acknowledge package (4th pass) *)

    RecType: Byte;
    (* Help: Must be equal to ^offrrtReplAckAckAck *)

    TransferIdAck: LongInt;
    (* Help: Identifier of 2nd pass transfer package *)

    StampSent: TOffStamp;
    (* Help: Timestamp when 2nd pass package was sent *)

  end {TOffTgtReplAckAckAck};

  TUpdateCallbackProc = procedure ( 
      aTicks: Integer; 
      aCnt: Integer ) of object;
  (* Help: Callback function called when replication record
           
           
           ---- Example:
           
           (pascalsource)
           ...
             IBReplDataModule.UpdateCallbackProc:= UpdateStatusLine;
             try
               IBReplDataModule.ReplicateOnline(DB_IB, '', 1, 0);
             finally
               IBReplDataModule.UpdateCallbackProc:= nil;
             end;
           
           // replication performance
            procedure TIBReplicationServerForm.UpdateStatusLine(T, aCnt: Integer);
            begin
              StatusBar.Panels[1].Text:= IntToStr(T div 1000);
              StatusBar.Panels[2].Text:= IntToStr(aCnt);
              if T = 0 then
                StatusBar.Panels[3].Text:= '0'
              else
                StatusBar.Panels[3].Text:= FloatToStrF(aCnt / (T / 1000 / 60), ffGeneral, 2, 0);
            end;
           
           (end pascalsource) *)

  TIBReplDataModule = class( TDataModule )
  (* Help: Implements all replication functionality *)

  published
    IBCfgDB: TIBDatabase;
    (* Help: Configuration database. Set property values before using any method using configuration database
             
             
             ---- Example:
             
             (pascalsource)
             
             procedure TIBReplicationServerForm.FormCreate(Sender: TObject);
             begin
             ...
               IBReplDataModule.IBCfgDB.BeforeConnect:= IBCfgDBBeforeConnect;
             ...
             end;
             
             procedure TIBReplicationServerForm.IBCfgDBBeforeConnect(Sender: TObject);
             var
               DM:
             begin
               with Sender as TIBDatabase, GetReplIni do
               try
                 DatabaseName:= ReadString(DBIniSection, 'DatabaseName', '');
                 Params.Values['user_name']:= ReadString(DBIniSection, 'User', '');
                 Params.Values['password']:= ReadString(DBIniSection, 'Password', '');
                 SQLDialect:= ReadInteger(DBIniSection, 'SQLDialect', 3);
               finally
                 Free;  // TIniFile
               end;
             end;
             (end pascalsource) *)

    IBCfgTransaction: TIBTransaction;
    (* Help: Default transaction of ^IBCfgDB *)

  published
    procedure IBCfgDBAfterConnect( Sender: TObject );
    (* Help: - *)

    procedure IBCfgDBAfterDisconnect( Sender: TObject );
    (* Help: - *)

    procedure DataModuleCreate( Sender: TObject );
    (* Help: - *)

    procedure DataModuleDestroy( Sender: TObject );
    (* Help: - *)

  protected
    property CachedList: TStringList read;
    (* Help: List of cached configuration values.
             
             > ^ClearCachedList ^ReadCachedFields *)

  protected
    function GetTriggerName( 
        aSchemaID: Integer; 
        aGroupId: Integer; 
        aRelationId: Integer; 
        aRelationName: string; 
        aAction: string; 
        aTablePrefix: string ): string; virtual;
    (* Help: Returns name of replication trigger. *)

    function RelationExists( 
        aDB: TIBDatabase; 
        aName: string ): Boolean;
    (* Help: Returns $True$ if relation exists in database
             
             > ^TIBDatabase.SQLDialect *)

    function ProcedureExists( 
        aDB: TIBDatabase; 
        aName: string ): Boolean;
    (* Help: Returns $True$ if stored procedure exists in database
             
             > ^TIBDatabase.SQLDialect *)

    function TriggerExists( 
        aDB: TIBDatabase; 
        aName: string ): Boolean;
    (* Help: Returns $True$ if trigger exists in database
             
             > ^TIBDatabase.SQLDialect *)

    function GeneratorExists( 
        aDB: TIBDatabase; 
        aName: string ): Boolean;
    (* Help: Returns $True$ if generator exists in database
             
             > ^TIBDatabase.SQLDialect *)

    function RoleExists( 
        aDB: TIBDatabase; 
        aName: string ): Boolean;
    (* Help: Returns $True$ if role exists in database
             
             > ^TIBDatabase.SQLDialect *)

    function ReadCachedFields( 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aRelId: Integer; 
        var CN: string ): Boolean;
    (* Help: read configuration parameters to cache *)

    procedure ReplicateOnlineRecord( 
        CN: string; 
        aDB: TIBDatabase; 
        aSeqId: Integer; 
        IUD: Char; 
        const aOldPKey: string; 
        const aNewPKey: string; 
        const aNewFKey: string; 
        aSeparator: Char; 
        Tgt: TObject; 
        NoTgtSelect: Boolean; 
        var aCounter: Integer ); virtual;
    (* Help: Implements online replication code. Override this method to implement own replication features. Values from
             REPL\$LOG are passed as parameters.
             
             > REPL\$LOG *)

    procedure ReplicateOfflineRecord( 
        CN: string; 
        SQRecord: PChar; 
        aSeqId: Integer; 
        IUD: Char; 
        const aOldPKey: string; 
        const aNewPKey: string; 
        const aNewFKey: string; 
        aSeparator: Char; 
        Tgt: TObject; 
        NoTgtSelect: Boolean; 
        var aCounter: Integer ); virtual;
    (* Help: Implements offline replication code. Override this method to implement own replication features. Values from
             offline package are passed as parameters.
             
             > REPL\$LOG *)

    procedure PrepareSourceOfflineRecord( 
        ReplQ: TIBSQL; 
        Tgt: TStream; 
        var aRecCounter: Integer; 
        var aRelCounter: Integer ); virtual;
    (* Help: create offline source record and put it to stream *)

    function PrepareSourceOfflinePackage( 
        aDB: TIBDatabase; 
        const aTablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aSrcDbId: Integer; 
        aTgtDBId: Integer; 
        Tgt: TStream; 
        aIfReplRecord: Boolean ): Integer; virtual;
    (* Help: prepare source database offline package in stream and insert record to REPL\$TRANSFER *)

    function ProcessSourceOfflinePackageAndPrepareTargetOfflinePackage( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aSrcDbId: Integer; 
        aTgtDBId: Integer; 
        Src: TStream; 
        Tgt: TStream; 
        const aOfflineDir: string; 
        aStampRec: TDateTime; 
        var aStamp: TDateTime ): Integer; virtual;
    (* Help: process offline package and prepare acknowledge package (in target database) to stream. Override this method to implement own functionality.
             
             > ProcessSourceOfflinePackageAndPrepareTargetOfflinePackageToFile *)

    procedure ProcessTargetOfflinePackage( 
        aDB: TIBDatabase; 
        const aTablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aSrcDBId: Integer; 
        aTgtDBId: Integer; 
        aTransferId: Integer; 
        Src: TStream; 
        const aOfflineDir: string ); virtual;
    (* Help: Process acknowledge offline package in source database - 2nd and 4th pass *)

    function GetReplTarget( 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aFldName: string; 
        aDBMask: Integer; 
        var aName: string; 
        var aObjPrefix: string ): TObject; virtual;
    (* Help: returns replication target according to configuration settings
             
             > ^GetDatabaseType *)

    function GetOfflinePackageName( 
        aSchemaId: Integer; 
        aStatus: Char; 
        aGroupId: Integer; 
        aSrcDBId: Integer; 
        aTgtDBId: Integer; 
        aTransferId: Integer ): string; virtual;
    (* Help: Returns unique file name for transfer offline package. *)

  public
    DBLog: TLogger;
    (* Help: Log used for logging of replication errors and process messages *)

    ReplLog: TLogger;
    (* Help: Log used for logging of replication statistics *)

    StopFlag: Boolean;
    (* Help: Set true to stop processing. In loops is called ^TApplication.ProcessMessages then
             is possible to use some stop button that assign $StopFlag:= True$, *)

    IBCfgDBTablePrefix: string;
    (* Help: Prefix of objects in configuration database. It's not necessary unless
             you need use the same database for more replicators or share source/target database
             with configuration database. *)

    UpdateCallbackProc: TUpdateCallbackProc;
    (* Help: Callback called from ^ReplicateOnline or ^ProcessSourceOfflinePackageAndPrepareTargetOfflinePackage. *)

    NowAsUTC: Boolean;
    (* Help: If $True$ all timestamps will use UTC. Handy for real time (non unique time due to daylight daving time)
             or distributed applications (time zone problem). One exception is REPL\$LOG.STAMP >>replobj.htt#repllog - its field value is generated
             in trigger and Interbase/Firebird don't know "NOW_UTC". *)

    LogErrSQLCmds: Boolean;
    (* Help: If $True$ to ^DBLog are logged full SQL commands (raising exception). Useful when adding condition replication trigger commands to
             obtain where is error.
             
             > ^DBLog *)

  public
    procedure CreateCfgDatabase( 
        aFileName: string; 
        aTablePrefix: string; 
        aUser: string; 
        aPsw: string; 
        aCodePage: string; 
        aSQLDialect: Integer );
    (* Help: Create new configuration database or if database file already exists insert objects
             
             
             ---- Example:
             
             (pascalsource)
             CreateCfgDatabase('replcfg.gdb', '', 'SYSDBA', 'masterkey', 'WIN1250', 3);
             (end pascalsource) *)

    procedure GenerateFields( 
        aSchemaId: Integer; 
        aTargetGroupId: Integer );
    (* Help: Reads source database and insert relation and fields to the configuration database.
             If source database changes (new object was added) it updates information in configuration database.
             Using is safe - no records will be deleted. *)

    procedure CreateSystemObjects( 
        aSchemaId: Integer; 
        aKeyLength: Integer; 
        aGroupId: Integer; 
        DBId: Integer = 0 );
    (* Help: Creates / updates all system objects in source/target database
             
             
             ---- Example:
             
             (pascalsource)
             CreateSystemObjects(1, 255, 0);  // source database
             (end pascalsource) *)

    procedure DropSystemObjects( 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        DBId: Integer = 0; 
        aOnlyTriggers: Boolean = False );
    (* Help: Remove system objects from source/target database *)

    function GetSourceDBId( aSchemaId: Integer ): Integer;
    (* Help: Get database id of the source database *)

    procedure SetDBParams( 
        aDB: TIBDatabase; 
        aId: Integer; 
        var aTablePrefix: string );
    (* Help: Assign database parameters according to values stored in configuration database *)

    procedure SetDBParams_Repl( 
        aDB: TIBDatabase; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aDBId: Integer; 
        aAlternateTgt: Boolean; 
        var aTablePrefix: string );
    (* Help: Assign database parameters according to values stored in configuration database *)

    function DBSQLExec( 
        aDB: TIBDatabase; 
        aSQL: string; 
        aTrans: TIBTransaction = nil ): Integer;
    (* Help: Safe SQL execution.
             
             > ^LogErrSQLCmds ^DBLog ^DBSQLRecord ^SafeExecQuery ^SafeExecProc *)

    function DBSQLRecord( 
        aDB: TIBDatabase; 
        aSQL: string; 
        aTrans: TIBTransaction = nil ): Variant;
    (* Help: Safe SQL execution.
             
             > ^LogErrSQLCmds ^DBLog ^DBSQLRecord ^SafeExecQuery ^SafeExecProc *)

    procedure SafeExecQuery( Q: TIBSQL );
    (* Help: Safe query execution.
             
             > ^LogErrSQLCmds ^DBLog ^DBSQLExec ^DBSQLRecord ^SafeExecProc *)

    procedure SafeExecProc( Q: TIBStoredProc );
    (* Help: Safe stored procedure execution.
             
             > ^LogErrSQLCmds ^DBLog ^DBSQLExec ^DBSQLRecord ^SafeExecQuery *)

    function Now2{}: TDateTime;
    (* Help: Returns timestamp according to ^NowAsUTC *)

    procedure ClearCachedList;
    (* Help: Clear all cached values read from configuration database. Values are kept in memory to improve replication performance.
             
             > ^ReadCachedFields ^CachedList *)

    procedure SynchronizeTable( 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aSrcDB: TIBDatabase; 
        aTgt: TObject; 
        aRelId: Integer; 
        Act: Byte; 
        var Cnt: Integer; 
        var CntI: Integer; 
        var CntU: Integer; 
        var CntD: Integer; 
        var CntErr: Integer; 
        var CntConf: Integer ); virtual;
    (* Help: process synchronization of relation - compress source and target tables. Override to implement own synchronization features. *)

    procedure Synchronize( aSchemaId: Integer );
    (* Help: Executes source and target database synchronization *)

    procedure ReplicateOnline( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSchemaId: Integer; 
        aMaxReplCount: Integer );
    (* Help: Executes online replication from whole schema *)

    procedure SourceOfflineBatch( 
        aDB: TIBDatabase; 
        const aTablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string; 
        aReceiveData: Boolean; 
        aProcessReceived: Boolean; 
        aProcess: Boolean; 
        aSendData: Boolean );
    (* Help: Executes actions for offline replication on source database *)

    function PrepareSourceOfflinePackageToFile( 
        aDB: TIBDatabase; 
        const aTablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aSrcDbId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string; 
        aIfReplRecord: Boolean ): Integer;
    (* Help: process records in REPL\$LOG and creates offline package *)

    procedure TargetOfflineBatch( 
        aDB: TIBDatabase; 
        const aTablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string; 
        aReceiveData: Boolean; 
        aProcess: Boolean; 
        aSendData: Boolean );
    (* Help: Executes actions for offline replication on target database *)

    function ProcessSourceOfflinePackageAndPrepareTargetOfflinePackageToFile( 
        aDB: TIBDatabase; 
        const aTablePrefix: string; 
        aSchemaId: Integer; 
        aGroupId: Integer; 
        aSrcDBId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string; 
        Src: TStream; 
        aStampRec: TDateTime; 
        var aStamp: TDateTime ): Integer;
    (* Help: process offline package and prepare acknowledge package (in target database) *)

    procedure ReceivePackages( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSchemaId: Integer; 
        aStatus: Char; 
        aGroupId: Integer; 
        aSrcDbId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string );
    (* Help: receive offline packages and store them in offline dir. Receiving is done using encoder and transfer libraries. *)

    procedure SendPendingPackages( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSchemaId: Integer; 
        aStatus: Char; 
        aGroupId: Integer; 
        aSrcDbId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string );
    (* Help: receive pending (unsent) offline packages stored in offline dir. Sending is done using encoder and transfer libraries. *)

    procedure ProcessReceivedPackages( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSchemaId: Integer; 
        aStatus: Char; 
        aGroupId: Integer; 
        aSrcDbId: Integer; 
        aTgtDBId: Integer; 
        const aOfflineDir: string );
    (* Help: Process received (unprocessed) packages. *)

    function DeleteFromRepl( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSeqId: Integer; 
        DBMask: Integer; 
        aPending: Boolean ): Byte;
    (* Help: delete record from REPL\$LOG *)

    function WriteToManRepl( 
        aDB: TIBDatabase; 
        const TablePrefix: string; 
        aSeqId: Integer; 
        DBMask: Integer ): Byte;
    (* Help: write REPL\$LOG record to REP\$MAN *)

  end {TIBReplDataModule};

  TFileLogger2 = class( TFileLogger )
  (* Help: Internal class for logging *)

  protected
    SQLDialect: Integer;
    (* Help: Dialect usd for proper logging *)

  end {TFileLogger2};

  EIBReplError = class( Exception )
  (* Help: Replicator exception class
           
           > ^IBReplError *)

  published
    Kind: Byte;
    (* Help: -  1 .. replication conflict
             -  2 .. replication error
             -  0 .. other *)

  end {EIBReplError};

function IBDT2DT( S: string ): TDateTime;
(* Help: Converts from Interbase datetime to TDateTime *)

function DT2IBDT( DT: TDateTime ): string;
(* Help: Converts from TDateTime to Interbase datetime *)

function DT2OffStamp( DT: TDateTime ): TOffStamp;
(* Help: Converts from TDateTime to TOffStamp *)

function OffStamp2DT( S: TOffStamp ): TDateTime;
(* Help: Converts from TOffStamp to TDateTime *)

function NowUTC{}: TDateTime;
(* Help: Returns datetime in UTC (universal time coordinate) (=GMT .. Greenwich mean time) *)

function Blob2SafeSQL( S: string ): string;
(* Help: Strip dangerous chars from blob (used for logging to SQL text) *)

function GetDatabaseType( S: string ): Integer;
(* Help: Returns type of database according its extension
         
         > ^dbtLog ^dbtInterbase *)

procedure IBReplError( 
    const Msg: string; 
    aKind: Byte );
(* Help: Raise ^EIBReplError *)

const 
  tranRO = 'read'#13#10'read_committed';
  (* Help: read only transaction parameters *)

  tranRW = 'write'#13#10'read_committed'#13#10'rec_version'#13#10'wait';
  (* Help: read/write transaction parameters *)

var 
  IBReplDataModule: TIBReplDataModule;
  (* Help: Instance of replication class.
           
           
           ---- Example
           
           (pascalsource)
           program IBReplServer;
           ....
           begin
           ...
             Application.CreateForm(TIBReplDataModule, IBReplDataModule);
             Application.Run;
           end.
           (end pascalsource) *)

resourcestring 
  sError = 'Error';
  (* Help: - *)


{==============================================================================}
implementation
