Provider.pas
上传用户:etonglee
上传日期:2014-03-01
资源大小:698k
文件大小:136k
源码类别:

Internet/IE编程

开发平台:

Delphi

  1. { ********************************************************************** }
  2. {                                                                        }
  3. { Kylix and Delphi Cross-Platform Visual Component Library               }
  4. {                                                                        }
  5. { Copyright (C) 1997, 2001 Borland Software Corporation                  }
  6. {                                                                        }
  7. { ********************************************************************** }
  8. unit Provider;
  9. {$T-,H+,X+}
  10. interface
  11. {$IFDEF MSWINDOWS}
  12. uses Windows, SysUtils, VarUtils, Variants, Classes, DBClient, DB, DSIntf, ActiveX, Midas, SqlTimSt;
  13. {$ENDIF}
  14. {$IFDEF LINUX}
  15. uses Libc, SysUtils, VarUtils, Variants, Classes, DBClient, DB, DSIntf, Midas, SqlTimSt;
  16. {$ENDIF}
  17. var
  18.   InformixLob: Boolean;
  19. type
  20. { EDSWriter }
  21.   EDSWriter = class(Exception)
  22.   private
  23.     FErrorCode: Integer;
  24.   public
  25.     constructor Create(ErrMsg: string; Status: Integer);
  26.     property ErrorCode: Integer read FErrorCode;
  27.   end;
  28. {$EXTERNALSYM EDSWriter}
  29. (*$HPPEMIT 'namespace Provider' *)
  30. (*$HPPEMIT '{' *)
  31. (*$HPPEMIT 'class DELPHICLASS EDSWriter;' *)
  32. (*$HPPEMIT '#pragma pack(push, 4)' *)
  33. (*$HPPEMIT 'class PASCALIMPLEMENTATION EDSWriter : public Sysutils::Exception' *)
  34. (*$HPPEMIT '{' *)
  35. (*$HPPEMIT '  typedef Sysutils::Exception inherited;' *)
  36. (*$HPPEMIT '' *)
  37. (*$HPPEMIT 'private:' *)
  38. (*$HPPEMIT '  int FErrorCode;' *)
  39. (*$HPPEMIT '' *)
  40. (*$HPPEMIT 'public:' *)
  41. (*$HPPEMIT '  __fastcall EDSWriter(AnsiString ErrMsg, long Status);' *)
  42. (*$HPPEMIT '  __property int ErrorCode = {read=FErrorCode, nodefault};' *)
  43. (*$HPPEMIT 'public:' *)
  44. (*$HPPEMIT '  /* Exception.CreateFmt */ inline __fastcall EDSWriter(const AnsiString Msg, const System::TVarRec * Args, const int Args_Size) : Sysutils::Exception(Msg, Args, Args_Size) { }' *)
  45. (*$HPPEMIT '  /* Exception.CreateRes */ inline __fastcall EDSWriter(int Ident, Extended Dummy) : Sysutils::Exception(Ident, Dummy) { }' *)
  46. (*$HPPEMIT '  /* Exception.CreateResFmt */ inline __fastcall EDSWriter(int Ident, const System::TVarRec * Args, const int Args_Size) : Sysutils::Exception(Ident, Args, Args_Size) { }' *)
  47. (*$HPPEMIT '  /* Exception.CreateHelp */ inline __fastcall EDSWriter(const AnsiString Msg, int AHelpContext) : Sysutils::Exception(Msg, AHelpContext) { }' *)
  48. (*$HPPEMIT '  /* Exception.CreateFmtHelp */ inline __fastcall EDSWriter(const AnsiString Msg, const System::TVarRec * Args, const int Args_Size, int AHelpContext) : Sysutils::Exception(Msg, Args, Args_Size, AHelpContext) { }' *)
  49. (*$HPPEMIT '  /* Exception.CreateResHelp */ inline __fastcall EDSWriter(int Ident, int AHelpContext) : Sysutils::Exception(Ident, AHelpContext) { }' *)
  50. (*$HPPEMIT '  /* Exception.CreateResFmtHelp */ inline __fastcall EDSWriter(int Ident, const System::TVarRec * Args, const int Args_Size, int AHelpContext) : Sysutils::Exception(Ident, Args, Args_Size, AHelpContext) { }' *)
  51. (*$HPPEMIT '' *)
  52. (*$HPPEMIT 'public:' *)
  53. (*$HPPEMIT '  /* TObject.Destroy */ inline __fastcall virtual ~EDSWriter(void) { }' *)
  54. (*$HPPEMIT '' *)
  55. (*$HPPEMIT '};' *)
  56. (*$HPPEMIT '' *)
  57. (*$HPPEMIT '#pragma pack(pop)' *)
  58. (*$HPPEMIT '}' *)
  59. { TCustomPacketWriter }
  60.   TCustomPacketWriter = class(TObject)
  61.   private
  62.     FIDSWriter: IDSWriter;
  63.     FBuffer: array of Byte;
  64.   protected
  65.     procedure AddAttribute(Area: TPcktAttrArea; const ParamName: string;
  66.       const Value: OleVariant; IncludeInDelta: Boolean);
  67.     procedure Check(Status: Integer);
  68.     property DSWriter: IDSWriter read FIDSWriter;
  69.   public
  70.     constructor Create; virtual;
  71.     destructor Destroy; override;
  72.   end;
  73. { TDataPacketWriter }
  74. type
  75. { Forward declarations }
  76.   TGetRecordOption = (grMetaData, grReset, grXML, grXMLUTF8);
  77.   TGetRecordOptions = set of TGetRecordOption;
  78.   TDataRequestEvent = function(Sender: TObject; Input: OleVariant): OleVariant of object;
  79.   TProviderOption = (poFetchBlobsOnDemand, poFetchDetailsOnDemand,
  80.     poIncFieldProps, poCascadeDeletes, poCascadeUpdates, poReadOnly,
  81.     poAllowMultiRecordUpdates, poDisableInserts, poDisableEdits,
  82.     poDisableDeletes, poNoReset, poAutoRefresh, poPropogateChanges,
  83.     poAllowCommandText, poRetainServerOrder );
  84.   TProviderOptions = set of TProviderOption;
  85.   PPutFieldInfo = ^TPutFieldInfo;
  86.   TPutFieldProc = procedure(Info: PPutFieldInfo) of object;
  87.   TPutFieldInfo = record
  88.     FieldNo: Integer;
  89.     Field: TField;
  90.     DataSet: TDataSet;
  91.     Size: Integer;
  92.     IsDetail: Boolean;
  93.     Opened: Boolean;
  94.     PutProc: TPutFieldProc;
  95.     LocalFieldIndex: Integer;
  96.     FieldInfos: Pointer;
  97.   end;
  98.   TInfoArray = array of TPutFieldInfo;
  99.   TGetParamsEvent = procedure(DataSet: TDataSet; Params: TList) of object;
  100.   TDataPacketWriter = class(TCustomPacketWriter)
  101.   private
  102.     FConstraints: Boolean;
  103.     FPutFieldInfo: TInfoArray;
  104.     FOptions: TProviderOptions;
  105.     FPacketOptions: TGetRecordOptions;
  106.     FOnGetParams: TGetParamsEvent;
  107.     procedure FreeInfoRecords(var Info: TInfoArray);
  108.     function GetFieldIdx(const FieldName: string; const Info: TInfoArray): Integer;
  109.     procedure AddExtraFieldProps(Field: TField);
  110.     function InitPutProcs(ADataSet: TDataSet; var GlobalIdx: Integer): TInfoArray;
  111.     procedure RefreshPutProcs(ADataSet: TDataSet; var Info: TInfoArray);
  112.   protected
  113.     procedure AddColumn(const Info: TPutFieldInfo);
  114.     procedure AddConstraints(DataSet: TDataSet);
  115.     procedure AddDataSetAttributes(DataSet: TDataSet);
  116.     procedure AddFieldLinks(const Info: TInfoArray);
  117.     procedure AddIndexDefs(DataSet: TDataSet; const Info: TInfoArray);
  118.     procedure PutADTField(Info: PPutFieldInfo);
  119.     procedure PutArrayField(Info: PPutFieldInfo);
  120.     procedure PutBlobField(Info: PPutFieldInfo);
  121.     procedure PutCalcField(Info: PPutFieldInfo);
  122.     procedure PutDataSetField(Info: PPutFieldInfo);
  123.     procedure PutField(Info: PPutFieldInfo);
  124.     procedure PutStringField(Info: PPutFieldInfo);
  125.     procedure PutWideStringField(Info: PPutFieldInfo);
  126.     procedure PutVarBytesField(Info: PPutFieldInfo);
  127.     procedure Reset;
  128.     procedure WriteMetaData(DataSet: TDataSet; const Info: TInfoArray;
  129.       IsReference: Boolean = False);
  130.     function WriteDataSet(DataSet: TDataSet; var Info: TInfoArray;
  131.       RecsOut: Integer): Integer;
  132.     property OnGetParams: TGetParamsEvent read FOnGetParams write FOnGetParams;
  133.   public
  134.     destructor Destroy; override;
  135.     procedure GetDataPacket(DataSet: TDataSet; var RecsOut: Integer;
  136.       out Data: OleVariant);
  137.     property Constraints: Boolean read FConstraints write FConstraints;
  138.     property PacketOptions: TGetRecordOptions read FPacketOptions write FPacketOptions;
  139.     property Options: TProviderOptions read FOptions write FOptions;
  140.   end;
  141. { TPacketDataSet }
  142.   TPacketDataSet = class(TCustomClientDataSet)
  143.   private
  144.     FOldRecBuf: PChar;
  145.     FCurRecBuf: PChar;
  146.     FCurValues: PChar;
  147.     FUseCurValues: Boolean;
  148.     FWritingCurValues: Boolean;
  149.     FNewValuesModified: Boolean;
  150.     function GetStreamMetaData: Boolean;
  151.     procedure SetStreamMetaData(Value: Boolean);
  152.     procedure SetWritingCurValues(const Value: Boolean);
  153.   protected
  154.     procedure DataEvent(Event: TDataEvent; Info: Longint); override;
  155.     function GetStateFieldValue(State: TDataSetState; Field: TField): Variant; override;
  156.     procedure InternalClose; override;
  157.     procedure InternalOpen; override;
  158.     procedure InternalInitRecord(Buffer: PChar); override;
  159.     procedure SetFieldData(Field: TField; Buffer: Pointer); override;
  160.     property WritingCurValues: Boolean read FWritingCurValues write SetWritingCurValues;
  161.   public
  162.     constructor Create(AOwner: TComponent); override;
  163.     procedure AssignCurValues(Source: TDataSet); overload;
  164.     procedure AssignCurValues(const CurValues: Variant); overload;
  165.     procedure CreateFromDelta(Source: TPacketDataSet);
  166.     function HasCurValues: Boolean;
  167.     function HasMergeConflicts: Boolean;
  168.     procedure InitAltRecBuffers(CheckModified: Boolean = True);
  169.     function UpdateKind: TUpdateKind;
  170.     property NewValuesModified: Boolean read FNewValuesModified;
  171.     property StreamMetaData: Boolean read GetStreamMetaData write SetStreamMetaData;
  172.     property UseCurValues: Boolean read FUseCurValues write FUseCurValues;
  173.   end;
  174. { TCustomProvider }
  175.   TCustomProvider = class(TComponent)
  176.   private
  177.     FExported: Boolean;
  178.     FOnDataRequest: TDataRequestEvent;
  179.     FBeforeApplyUpdates: TRemoteEvent;
  180.     FAfterApplyUpdates: TRemoteEvent;
  181.     FBeforeGetRecords: TRemoteEvent;
  182.     FAfterGetRecords: TRemoteEvent;
  183.     FBeforeRowRequest: TRemoteEvent;
  184.     FAfterRowRequest: TRemoteEvent;
  185.     FBeforeExecute: TRemoteEvent;
  186.     FAfterExecute: TRemoteEvent;
  187.     FBeforeGetParams: TRemoteEvent;
  188.     FAfterGetParams: TRemoteEvent;
  189.     function GetData: OleVariant;
  190.   protected
  191.     function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  192.       out ErrorCount: Integer): OleVariant; virtual; abstract;
  193.     function InternalGetRecords(Count: Integer; out RecsOut: Integer;
  194.       Options: TGetRecordOptions; const CommandText: WideString;
  195.       var Params: OleVariant): OleVariant; virtual;
  196.     function InternalRowRequest(const Row: OleVariant; RequestType: TFetchOptions): OleVariant; virtual;
  197.     procedure InternalExecute(const CommandText: WideString; var Params: OleVariant); virtual;
  198.     function InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant; virtual;
  199.   { Event overrides }
  200.     procedure DoAfterApplyUpdates(var OwnerData: OleVariant); virtual;
  201.     procedure DoBeforeApplyUpdates(var OwnerData: OleVariant); virtual;
  202.     procedure DoAfterExecute(var OwnerData: OleVariant); virtual;
  203.     procedure DoBeforeExecute(const CommandText: WideString; var Params,
  204.       OwnerData: OleVariant); virtual;
  205.     procedure DoAfterGetParams(var OwnerData: OleVariant); virtual;
  206.     procedure DoBeforeGetParams(var OwnerData: OleVariant); virtual;
  207.     procedure DoAfterGetRecords(var OwnerData: OleVariant); virtual;
  208.     procedure DoBeforeGetRecords(Count: Integer; Options: Integer;
  209.       const CommandText: WideString; var Params, OwnerData: OleVariant); virtual;
  210.     procedure DoAfterRowRequest(var OwnerData: OleVariant); virtual;
  211.     procedure DoBeforeRowRequest(var OwnerData: OleVariant); virtual;
  212.   { Events }
  213.     property OnDataRequest: TDataRequestEvent read FOnDataRequest write FOnDataRequest;
  214.     property BeforeApplyUpdates: TRemoteEvent read FBeforeApplyUpdates write FBeforeApplyUpdates;
  215.     property AfterApplyUpdates: TRemoteEvent read FAfterApplyUpdates write FAfterApplyUpdates;
  216.     property BeforeGetRecords: TRemoteEvent read FBeforeGetRecords write FBeforeGetRecords;
  217.     property AfterGetRecords: TRemoteEvent read FAfterGetRecords write FAfterGetRecords;
  218.     property BeforeRowRequest: TRemoteEvent read FBeforeRowRequest write FBeforeRowRequest;
  219.     property AfterRowRequest: TRemoteEvent read FAfterRowRequest write FAfterRowRequest;
  220.     property BeforeExecute: TRemoteEvent read FBeforeExecute write FBeforeExecute;
  221.     property AfterExecute: TRemoteEvent read FAfterExecute write FAfterExecute;
  222.     property BeforeGetParams: TRemoteEvent read FBeforeGetParams write FBeforeGetParams;
  223.     property AfterGetParams: TRemoteEvent read FAfterGetParams write FAfterGetParams;
  224.   public
  225.     constructor Create(AOwner: TComponent); override;
  226.     destructor Destroy; override;
  227.     function ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  228.       out ErrorCount: Integer): OleVariant; overload;
  229.     function ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  230.       out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant; overload;
  231.     function GetRecords(Count: Integer; out RecsOut: Integer;
  232.       Options: Integer): OleVariant; overload;
  233.     function GetRecords(Count: Integer; out RecsOut: Integer; Options: Integer;
  234.       const CommandText: WideString; var Params,
  235.       OwnerData: OleVariant): OleVariant; overload;
  236.     function RowRequest(const Row: OleVariant; RequestType: Integer;
  237.       var OwnerData: OleVariant): OleVariant;
  238.     procedure Execute(const CommandText: WideString; var Params,
  239.       OwnerData: OleVariant);
  240.     function GetParams(var OwnerData: OleVariant): OleVariant;
  241.     function DataRequest(Input: OleVariant): OleVariant; virtual;
  242.     property Data: OleVariant read GetData;
  243.     property Exported: Boolean read FExported write FExported default True;
  244.   end;
  245. const
  246.   ResetOption: Integer = 1 shl ord(grReset);
  247.   MetaDataOption: Integer = 1 shl ord(grMetaData);
  248.   XMLOption: Integer = 1 shl ord(grXML);
  249.   XMLUTF8Option: Integer = 1 shl ord(grXMLUTF8);
  250. { TBaseProvider }
  251. type
  252.   TUpdateTree = class;
  253.   TCustomResolver = class;
  254.   TResolverResponse = (rrSkip, rrAbort, rrMerge, rrApply, rrIgnore);
  255.   TProviderDataEvent = procedure(Sender: TObject; DataSet: TCustomClientDataSet) of object;
  256.   TBeforeUpdateRecordEvent = procedure(Sender: TObject; SourceDS: TDataSet;
  257.     DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean) of object;
  258.   TAfterUpdateRecordEvent = procedure(Sender: TObject; SourceDS: TDataSet;
  259.     DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind) of object;
  260.   TResolverErrorEvent = procedure(Sender: TObject; DataSet: TCustomClientDataSet;
  261.     E: EUpdateError; UpdateKind: TUpdateKind; var Response: TResolverResponse) of object;
  262.   TBaseProvider = class(TCustomProvider)
  263.   private
  264.     FDataDS: TPacketDataSet;
  265.     FUpdateMode: TUpdateMode;
  266.     FResolver: TCustomResolver;
  267.     FOnGetData: TProviderDataEvent;
  268.     FOnUpdateData: TProviderDataEvent;
  269.     FOnUpdateError: TResolverErrorEvent;
  270.     FBeforeUpdateRecord: TBeforeUpdateRecordEvent;
  271.     FAfterUpdateRecord: TAfterUpdateRecordEvent;
  272.     FProviderOptions: TProviderOptions;
  273.   protected
  274.     procedure CheckResolver;
  275.     function CreateResolver: TCustomResolver; virtual;
  276.     procedure FreeResolver;
  277.     procedure CreateDataPacket(PacketOpts: TGetRecordOptions;
  278.       ProvOpts: TProviderOptions; var RecsOut: Integer; var Data: OleVariant); virtual;
  279.     procedure DoOnGetData(var Data: OleVariant);
  280.     procedure DoOnUpdateData(Delta: TPacketDataSet);
  281.     procedure LocateRecord(Source, Delta: TDataSet); virtual;
  282.     procedure UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean); virtual;
  283.     procedure FetchDetails(Source, Delta: TDataSet); virtual;
  284.     function InternalRowRequest(const Row: OleVariant;
  285.       RequestType: TFetchOptions): OleVariant; override;
  286.     function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  287.       out ErrorCount: Integer): OleVariant; override;
  288.     function InternalGetRecords(Count: Integer; out RecsOut: Integer;
  289.       Options: TGetRecordOptions; const CommandText: WideString;
  290.       var Params: OleVariant): OleVariant; override;
  291.   public
  292.     constructor Create(AOwner: TComponent); override;
  293.     destructor Destroy; override;
  294.     property Resolver: TCustomResolver read FResolver;
  295.     property Options: TProviderOptions read FProviderOptions
  296.       write FProviderOptions default [];
  297.     property UpdateMode: TUpdateMode read FUpdateMode write FUpdateMode default upWhereAll;
  298.     property OnDataRequest;
  299.     property OnGetData: TProviderDataEvent read FOnGetData write FOnGetData;
  300.     property OnUpdateData: TProviderDataEvent read FOnUpdateData write FOnUpdateData;
  301.     property OnUpdateError: TResolverErrorEvent read FOnUpdateError write FOnUpdateError;
  302.     property BeforeUpdateRecord: TBeforeUpdateRecordEvent read FBeforeUpdateRecord
  303.       write FBeforeUpdateRecord;
  304.     property AfterUpdateRecord: TAfterUpdateRecordEvent read FAfterUpdateRecord
  305.       write FAfterUpdateRecord;
  306.   end;
  307. { TDataSetProvider }
  308.   TGetTableNameEvent = procedure(Sender: TObject; DataSet: TDataSet; var TableName: string) of object;
  309.   TGetDSProps = procedure(Sender: TObject; DataSet: TDataSet;
  310.     out Properties: OleVariant) of object;
  311.   TDataSetProvider = class(TBaseProvider)
  312.   private
  313.     FDataSet: TDataSet;
  314.     FDataSetOpened: Boolean;
  315.     FDSWriter: TDataPacketWriter;
  316.     FGetDSProps: TGetDSProps;
  317.     FParams: TParams;
  318.     FResolveToDataSet: Boolean;
  319.     FRecordsSent: Integer;
  320.     FConstraints: Boolean;
  321.     FTransactionStarted: Boolean;
  322.     FGetTableName: TGetTableNameEvent;
  323.     function FindRecord(Source, Delta: TDataSet; UpdateMode: TUpdateMode): Boolean;
  324.     procedure Reset;
  325.     procedure SetCommandText(const CommandText: string);
  326.     procedure SetDataSet(ADataSet: TDataSet);
  327.     procedure SetResolveToDataSet(Value: Boolean);
  328.   protected
  329.     { SQL Resolver support methods }
  330.     procedure DoGetTableName(DataSet: TDataSet; var TableName: string); virtual;
  331.   protected
  332.     { Event overrides }
  333.     procedure DoBeforeGetRecords(Count: Integer; Options: Integer;
  334.       const CommandText: WideString; var Params, OwnerData: OleVariant); override;
  335.     procedure DoBeforeExecute(const CommandText: WideString; var Params,
  336.       OwnerData: OleVariant); override;
  337.   protected
  338.     procedure CheckDataSet;
  339.     procedure SetParams(Values: OleVariant);
  340.     procedure DoGetProviderAttributes(DataSet: TDataSet; List: TList); virtual;
  341.     function CreateResolver: TCustomResolver; override;
  342.     procedure CreateDataPacket(PacketOpts: TGetRecordOptions;
  343.       ProvOpts: TProviderOptions; var RecsOut: Integer; var Data: OleVariant); override;
  344.     function GetDataSetFromDelta(ATree: TUpdateTree; Source, Delta: TDataSet; Mode: TUpdateMode): TDataSet;
  345.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  346.     procedure LocateRecord(Source, Delta: TDataSet); override;
  347.     procedure UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean); override;
  348.     procedure FetchDetails(Source, Delta: TDataSet); override;
  349.     function InternalRowRequest(const Row: OleVariant; Options: TFetchOptions): OleVariant; override;
  350.     function InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant; override;
  351.     procedure InternalExecute(const CommandText: WideString; var Params: OleVariant); override;
  352.     function InternalGetRecords(Count: Integer; out RecsOut: Integer;
  353.       Options: TGetRecordOptions; const CommandText: WideString;
  354.       var Params: OleVariant): OleVariant; override;
  355.     function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  356.       out ErrorCount: Integer): OleVariant; override;
  357.     property Params: TParams read FParams;
  358.   public
  359.     constructor Create(AOwner: TComponent); override;
  360.     destructor Destroy; override;
  361.   published
  362.     property DataSet: TDataSet read FDataSet write SetDataSet;
  363.     property Constraints: Boolean read FConstraints write FConstraints default True;
  364.     property ResolveToDataSet: Boolean read FResolveToDataSet write SetResolveToDataSet default False;
  365.     property Exported;
  366.     property Options;
  367.     property UpdateMode;
  368.     property OnDataRequest;
  369.     property OnGetData;
  370.     property OnUpdateData;
  371.     property OnUpdateError;
  372.     property AfterUpdateRecord;
  373.     property BeforeUpdateRecord;
  374.     property BeforeApplyUpdates;
  375.     property AfterApplyUpdates;
  376.     property BeforeGetRecords;
  377.     property AfterGetRecords;
  378.     property BeforeRowRequest;
  379.     property AfterRowRequest;
  380.     property BeforeExecute;
  381.     property AfterExecute;
  382.     property BeforeGetParams;
  383.     property AfterGetParams;
  384.     property OnGetTableName: TGetTableNameEvent read FGetTableName write FGetTableName;
  385.     property OnGetDataSetProperties: TGetDSProps read FGetDSProps write FGetDSProps;
  386.   end;
  387. { TProvider - deprecated }
  388.   TProvider = class(TDataSetProvider)
  389.   end;
  390. { TUpdateTree }
  391.   TUpdateTree = class(TObject)
  392.   private
  393.     FDeltaDS: TPacketDataSet;
  394.     FErrorDS: TPacketDataSet;
  395.     FOpened: Boolean;
  396.     FSourceDS: TDataSet;
  397.     FParent: TUpdateTree;
  398.     FDetails: TList;
  399.     FData: Pointer;
  400.     FResolver: TCustomResolver;
  401.     FName: string;
  402.     function GetDetailCount: Integer;
  403.     function GetDetail(Index: Integer): TUpdateTree;
  404.     function GetErrorDS: TPacketDataSet;
  405.     function GetHasErrors: Boolean;
  406.     function GetIsNested: Boolean;
  407.     function GetTree(const AName: string): TUpdateTree;
  408.   protected
  409.     procedure Clear;
  410.     function DoUpdates: Boolean;
  411.     procedure RefreshData(Options: TFetchOptions);
  412.     procedure InitErrorPacket(E: EUpdateError; Response: TResolverResponse);
  413.     procedure InitData(ASource: TDataSet);
  414.     procedure InitDelta(const ADelta: OleVariant); overload;
  415.     procedure InitDelta(ADelta: TPacketDataSet); overload;
  416.     property Data: Pointer read FData write FData;
  417.     property Delta: TPacketDataSet read FDeltaDS;
  418.     property DetailCount: Integer read GetDetailCount;
  419.     property Details[Index: Integer]: TUpdateTree read GetDetail;
  420.     property ErrorDS: TPacketDataSet read GetErrorDS;
  421.     property HasErrors: Boolean read GetHasErrors;
  422.     property Name: string read FName write FName;
  423.     property Parent: TUpdateTree read FParent;
  424.     property Source: TDataSet read FSourceDS;
  425.     property IsNested: Boolean read GetIsNested;
  426.   public
  427.     constructor Create(AParent: TUpdateTree; AResolver: TCustomResolver);
  428.     destructor Destroy; override;
  429.   end;
  430. { TCustomResolver }
  431.   TCustomResolver = class(TComponent)
  432.   private
  433.     FProvider: TBaseProvider;
  434.     FPrevResponse: TResolverResponse;
  435.     FErrorCount: Integer;
  436.     FMaxErrors: Integer;
  437.     FUpdateTree: TUpdateTree;
  438.   protected
  439.     property Provider: TBaseProvider read FProvider;
  440.     function HandleUpdateError(Tree: TUpdateTree; E: EUpdateError;
  441.       var MaxErrors, ErrorCount: Integer): Boolean;
  442.     procedure LogUpdateRecord(Tree: TUpdateTree);
  443.     procedure LogUpdateError(Tree: TUpdateTree; E: EUpdateError;
  444.       Response: TResolverResponse);
  445.     procedure InitKeyFields(Tree: TUpdateTree; ADelta: TPacketDataSet);
  446.     procedure InternalBeforeResolve(Tree: TUpdateTree); virtual;
  447.     function InternalUpdateRecord(Tree: TUpdateTree): Boolean;
  448.     procedure BeginUpdate; virtual;
  449.     procedure EndUpdate; virtual;
  450.     procedure InitTreeData(Tree: TUpdateTree); virtual;
  451.     procedure FreeTreeData(Tree: TUpdateTree); virtual;
  452.     procedure InitializeConflictBuffer(Tree: TUpdateTree); virtual; abstract;
  453.     procedure DoUpdate(Tree: TUpdateTree); virtual; abstract;
  454.     procedure DoDelete(Tree: TUpdateTree); virtual; abstract;
  455.     procedure DoInsert(Tree: TUpdateTree); virtual; abstract;
  456.     function RowRequest(Row: OleVariant; Options: TFetchOptions): OleVariant; virtual;
  457.     function ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  458.       out ErrorCount: Integer): OleVariant; virtual;
  459.   public
  460.     constructor Create(AProvider: TBaseProvider); reintroduce;
  461.     destructor Destroy; override;
  462.   end;
  463. { TDataSetResolver }
  464.   TDataSetResolver = class(TCustomResolver)
  465.   private
  466.     FBookmark: TBookmarkStr;
  467.     FOpened: Boolean;
  468.     function GetProvider: TDataSetProvider;
  469.     procedure PutRecord(Tree: TUpdateTree);
  470.   protected
  471.     property Provider: TDataSetProvider read GetProvider;
  472.     procedure BeginUpdate; override;
  473.     procedure DoUpdate(Tree: TUpdateTree); override;
  474.     procedure DoDelete(Tree: TUpdateTree); override;
  475.     procedure DoInsert(Tree: TUpdateTree); override;
  476.     procedure EndUpdate; override;
  477.     procedure InternalBeforeResolve(Tree: TUpdateTree); override;
  478.     procedure InitializeConflictBuffer(Tree: TUpdateTree); override;
  479.   public
  480.     constructor Create(AProvider: TDataSetProvider); reintroduce;
  481.   end;
  482. { TSQLResolver }
  483.   TSQLResolver = class(TCustomResolver)
  484.   private
  485.     FSQL: TStringList;
  486.     FParams: TParams;
  487.     function GetProvider: TDataSetProvider;
  488.     procedure GenWhereSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
  489.       GenUpdateMode: TUpdateMode; Alias: string);
  490.     procedure GenInsertSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams);
  491.     procedure GenDeleteSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
  492.       Alias: string);
  493.     procedure GenUpdateSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
  494.       Alias: string);
  495.     procedure GenSelectSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
  496.       Alias: string; Mode: TUpdateMode = upWhereKeyOnly);
  497.     function UseFieldInUpdate(Field: TField): Boolean;
  498.     function UseFieldInWhere(Field: TField; Mode: TUpdateMode): Boolean;
  499.     procedure InternalDoUpdate(Tree: TUpdateTree; UpdateKind: TUpdateKind);
  500.   protected
  501.     property Provider: TDataSetProvider read GetProvider;
  502.     procedure InitializeConflictBuffer(Tree: TUpdateTree); override;
  503.     procedure DoExecSQL(SQL: TStringList; Params: TParams); virtual;
  504.     procedure DoGetValues(SQL: TStringList; Params: TParams;
  505.       DataSet: TDataSet); virtual;
  506.     procedure InitTreeData(Tree: TUpdateTree); override;
  507.     procedure FreeTreeData(Tree: TUpdateTree); override;
  508.     procedure DoUpdate(Tree: TUpdateTree); override;
  509.     procedure DoDelete(Tree: TUpdateTree); override;
  510.     procedure DoInsert(Tree: TUpdateTree); override;
  511.   public
  512.     constructor Create(AProvider: TDataSetProvider); reintroduce;
  513.     destructor Destroy; override;
  514.   end;
  515. { TLocalAppServer }
  516.   TLocalAppServer = class(TInterfacedObject, IAppServer{$IFDEF MSWINDOWS}, ISupportErrorInfo{$ENDIF})
  517.   private
  518.     FProvider: TCustomProvider;
  519.     FProviderCreated: Boolean;
  520.   protected
  521.     { IDispatch }
  522.     function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  523.     function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  524.     function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  525.       NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  526.     function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  527.       Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  528.     { IAppServer }
  529.     function AS_ApplyUpdates(const ProviderName: WideString; Delta: OleVariant; MaxErrors: Integer;
  530.                              out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant; safecall;
  531.     function AS_GetRecords(const ProviderName: WideString; Count: Integer; out RecsOut: Integer;
  532.                            Options: Integer; const CommandText: WideString;
  533.                            var Params: OleVariant; var OwnerData: OleVariant): OleVariant; safecall;
  534.     function AS_DataRequest(const ProviderName: WideString; Data: OleVariant): OleVariant; safecall;
  535.     function AS_GetProviderNames: OleVariant; safecall;
  536.     function AS_GetParams(const ProviderName: WideString; var OwnerData: OleVariant): OleVariant; safecall;
  537.     function AS_RowRequest(const ProviderName: WideString; Row: OleVariant; RequestType: Integer;
  538.                            var OwnerData: OleVariant): OleVariant; safecall;
  539.     procedure AS_Execute(const ProviderName: WideString;  const CommandText: WideString;
  540.                          var Params, OwnerData: OleVariant); safecall;
  541.     { ISupportErrorInfo }
  542.     function InterfaceSupportsErrorInfo(const iid: TGUID): HResult; stdcall;
  543.   public
  544.     constructor Create(AProvider: TCustomProvider); overload;
  545.     constructor Create(ADataset: TDataset); overload;
  546.     destructor Destroy; override;
  547.     function SafeCallException(ExceptObject: TObject;
  548.       ExceptAddr: Pointer): HResult; override;
  549.   end;
  550.   IProviderContainer = interface
  551.   ['{EEE9FFD4-752F-11D4-80DD-00C04F6BB88C}']
  552.     procedure RegisterProvider(Prov: TCustomProvider);
  553.     procedure UnRegisterProvider(Prov: TCustomProvider);
  554.   end;
  555. { Utility functions }
  556. function GetObjectProperty(Instance: TPersistent; const PropName: string): TObject;
  557. function GetStringProperty(Instance: TPersistent; const PropName: string): string;
  558. function VarArrayFromStrings(Strings: TStrings): Variant;
  559. implementation
  560. {$IFDEF MSWINDOWS}
  561. uses MidConst, DBConsts, DBCommon, TypInfo, DataBkr, ComObj, FMTBcd,mtx,StrUtils;
  562. {$ENDIF}
  563. {$IFDEF LINUX}
  564. uses MidConst, DBConsts, DBCommon, TypInfo, FMTBcd, Types;
  565. {$ENDIF}
  566. const
  567.   DEFBUFSIZE = 8192;  { Default size for field data buffer }
  568.   DefAlias   = 'A';
  569.   NestAlias  = 'B';
  570.   tagSERVERCALC = 1;
  571.   ADOID_MSSQLSERVER ='SQLOLEDB.1';                 //ADO MS SQLSERVER 标志
  572.   ADOID_MSACCESSS   ='Microsoft.Jet.OLEDB.4.0';    //ADO MS ACCESS    标志
  573.   ADOID_ORACLE      ='MSDAORA.1';                  //ADO ORCALE       标志
  574.   PacketTypeMap: array [TFieldType] of Integer =
  575.     (dsfldUNKNOWN, dsfldZSTRING, dsfldINT, dsfldINT, dsfldINT, dsfldBOOL,
  576.      dsfldFLOATIEEE, dsfldFLOATIEEE, dsfldBCD, dsfldDATE, dsfldTIME,
  577.      dsfldTIMESTAMP, dsfldBYTES, dsfldBYTES, dsfldINT, dsfldBYTES, dsfldBYTES,
  578.      dsfldBYTES, dsfldBYTES, dsfldBYTES, dsfldBYTES, dsfldBYTES, dsfldUNKNOWN,
  579.      dsfldZSTRING, dsfldUNICODE, dsfldINT, dsfldADT, dsfldARRAY, dsfldEMBEDDEDTBL,
  580.      dsfldEMBEDDEDTBL, dsfldBYTES, dsfldBYTES, dsfldUNKNOWN, dsfldUNKNOWN,
  581.      dsfldUNKNOWN, dsfldZSTRING, dsfldDATETIME, dsFLDFMTBCD);
  582.   ExtraFieldProps: array [0..10] of string = ('Alignment', 'DisplayLabel',
  583.     'DisplayWidth', 'Visible', 'EditMask', 'DisplayFormat', 'EditFormat',
  584.     'MinValue', 'MaxValue', 'currency', 'DisplayValues');
  585. { Utility functions }
  586. function GetObjectProperty(Instance: TPersistent; const PropName: string): TObject;
  587. var
  588.   PropInfo: PPropInfo;
  589. begin
  590.   Result := nil;
  591.   PropInfo := TypInfo.GetPropInfo(Instance.ClassInfo, PropName);
  592.   if (PropInfo <> nil) and (PropInfo^.PropType^.Kind = tkClass) then
  593.     Result := TObject(GetOrdProp(Instance, PropInfo));
  594. end;
  595. function GetStringProperty(Instance: TPersistent; const PropName: string): string;
  596. var
  597.   PropInfo: PPropInfo;
  598. begin
  599.   Result := '';
  600.   PropInfo := TypInfo.GetPropInfo(Instance.ClassInfo, PropName);
  601.   if (PropInfo <> nil) and (PropInfo^.PropType^.Kind in [tkString, tkLString, tkWString]) then
  602.     Result := GetStrProp(Instance, PropInfo);
  603. end;
  604. function VarArrayFromStrings(Strings: TStrings): Variant;
  605. var
  606.   I: Integer;
  607. begin
  608.   Result := Null;
  609.   if Strings.Count > 0 then
  610.   begin
  611.     Result := VarArrayCreate([0, Strings.Count - 1], varOleStr);
  612.     for I := 0 to Strings.Count - 1 do Result[I] := WideString(Strings[I]);
  613.   end;
  614. end;
  615. { EDSWriter }
  616. constructor EDSWriter.Create(ErrMsg: string; Status: Integer);
  617. begin
  618.   FErrorCode := Status;
  619.   inherited Create(ErrMsg);
  620. end;
  621. { TCustomPacketWriter }
  622. constructor TCustomPacketWriter.Create;
  623. begin
  624.   SetLength(FBuffer, DEFBUFSIZE);
  625. end;
  626. destructor TCustomPacketWriter.Destroy;
  627. begin
  628.   FIDSWriter := nil;
  629.   FBuffer := nil;
  630.   inherited Destroy;
  631. end;
  632. procedure TCustomPacketWriter.Check(Status: Integer);
  633. var
  634.   ErrMsg: array[0..2048] of Char;
  635. begin
  636.   if Status <> 0 then
  637.   begin
  638.     FIDSWriter.GetErrorString(Status, ErrMsg);
  639.     raise EDSWriter.Create(ErrMsg, Status);
  640.   end;
  641. end;
  642. procedure TCustomPacketWriter.AddAttribute(Area: TPcktAttrArea; const ParamName: string;
  643.   const Value: OleVariant; IncludeInDelta: Boolean);
  644. const
  645.   ParamTypeMap: array[varSmallInt..varByte] of Integer =
  646.     ( dsfldINT, dsfldINT, dsfldFLOATIEEE, dsfldFLOATIEEE, dsfldBCD,
  647.       dsfldFLOATIEEE, dsfldZSTRING, 0, 0, dsfldBOOL, 0, 0, 0, 0, 0, dsfldINT);
  648.   ParamTypeSize: array[varSmallInt..varByte] of Integer =
  649.     ( SizeOf(SmallInt), SizeOf(Integer), SizeOf(Single), SizeOf(Double),
  650.       SizeOf(Currency), SizeOf(TDateTime), 0, 0, 0, SizeOf(WordBool), 0, 0, 0,
  651.       0, 0, SizeOf(Byte));
  652. var
  653.   ParamType, ParamLen, ElemSize, ElemCount: DWord;
  654.   P: Pointer;
  655.   DateRec: TDateTimeRec;
  656.   TimeStamp: TTimeStamp;
  657. begin
  658.   if ((VarType(Value) and varTypeMask) in [varSmallInt, varInteger, varSingle,
  659.       varDouble, varCurrency, varDate, varOleStr, varBoolean, varByte, varNull]) then
  660.   begin
  661.     ParamType := ParamTypeMap[VarType(Value) and varTypeMask];
  662.     ParamLen := ParamTypeSize[VarType(Value) and varTypeMask];
  663.     if ParamType = dsfldZSTRING then
  664.     begin
  665.       ParamType := (dsfldZSTRING shl dsSizeBitsLen) or dsVaryingFldType or SizeOf(Word);
  666.       ParamLen := Length(Value) + 1;
  667.       PWord(FBuffer)^ := ParamLen;
  668.       Inc(ParamLen, SizeOf(Word));
  669.       StrPLCopy(@FBuffer[SizeOf(Word)], Value, Length(FBuffer) - SizeOf(Word) - 1);
  670.     end else
  671.     if ParamType = dsfldTIMESTAMP then
  672.     begin
  673.       TimeStamp := DateTimeToTimeStamp(Value);
  674.       DateRec.DateTime := TimeStampToMSecs(TimeStamp);
  675.       Move(DateRec, PChar(FBuffer)^, ParamLen);
  676.       ParamType := ParamType shl dsSizeBitsLen or SizeOf(TDateTimeRec);
  677.     end else
  678.     if ParamType = dsfldDATETIME then
  679.     begin
  680.       P := @TVarData(Value).VPointer;
  681.       Move(P^, PByte(FBuffer)^, ParamLen);
  682.       ParamType := (ParamType shl dsSizeBitsLen) or SizeOf(TSQLTimeStamp);
  683.     end else
  684.     if VarIsArray(Value) then
  685.     begin
  686.       if ParamLen = 0 then
  687.         raise EDSWriter.Create(SInvalidOptParamType, 0);
  688.       ElemCount := VarArrayHighBound(Value, 1) + 1;
  689.       ElemSize := ParamLen;
  690.       if ParamType in [dsfldINT, dsfldUINT] then
  691.         ParamType := (dsfldUINT shl dsSizeBitsLen) or dsArrayFldType or ElemSize
  692.       else
  693.         ParamType := (dsfldBYTES shl dsSizeBitsLen) or dsArrayFldType or ElemSize;
  694.       PInteger(FBuffer)^ := ElemCount;
  695.       ParamLen := ElemCount * ElemSize;
  696.       P := VarArrayLock(Value);
  697.       try
  698.         Move(P^, FBuffer[SizeOf(Integer)], ParamLen);
  699.         Inc(ParamLen, SizeOf(Integer));
  700.       finally
  701.         VarArrayUnlock(Value);
  702.       end;
  703.     end else
  704.     begin
  705.       if (VarType(Value) and varByRef) = varByRef then
  706.         P := TVarData(Value).VPointer else
  707.         P := @TVarData(Value).VPointer;
  708.       Move(P^, PByte(FBuffer)^, ParamLen);
  709.       ParamType := ParamType shl dsSizeBitsLen or ParamLen;
  710.     end;
  711.     if IncludeInDelta then
  712.       ParamType := ParamType or dsIncInDelta;
  713.     Check(FIDSWriter.AddAttribute(Area, PChar(ParamName), ParamType, ParamLen, PByte(FBuffer)));
  714.   end else
  715.     raise EDSWriter.Create(SInvalidOptParamType, 0);
  716. end;
  717. { TDataPacketWriter }
  718. destructor TDataPacketWriter.Destroy;
  719. begin
  720.   FreeInfoRecords(FPutFieldInfo);
  721.   FPutFieldInfo := nil;
  722.   inherited Destroy;
  723. end;
  724. procedure TDataPacketWriter.FreeInfoRecords(var Info: TInfoArray);
  725. var
  726.   i: Integer;
  727. begin
  728.   for i := 0 to High(Info) do
  729.     if Info[i].FieldInfos <> nil then
  730.     begin
  731.       FreeInfoRecords(TInfoArray(Info[i].FieldInfos));
  732.       TInfoArray(Info[i].FieldInfos) := nil;
  733.     end;
  734. end;
  735. { Writing data }
  736. procedure TDataPacketWriter.PutBlobField(Info: PPutFieldInfo);
  737. begin
  738.   if not (poFetchBlobsOnDemand in Options) then
  739.   begin
  740.     Info.Size := Info.DataSet.GetBlobFieldData(Info.FieldNo, TBlobByteData(FBuffer));
  741.     if Info.Size <> 0 then
  742.     begin
  743.       if Length(FBuffer) <= Info.Size then
  744.         SetLength(FBuffer, Info.Size + 1);
  745.       FBuffer[Info.Size] := 0;
  746.       if TBlobField(Info.Field).Transliterate then
  747.         Info.Size := Info.DataSet.Translate(PChar(FBuffer), PChar(FBuffer), False);
  748.       FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer))
  749.     end else
  750.       FIDSWriter.PutField(fldIsNull, 0, nil);
  751.   end else
  752.     FIDSWriter.PutField(fldIsChanged, dsDELAYEDBIT or 1, @Info.Size);
  753. end;
  754. procedure TDataPacketWriter.PutCalcField(Info: PPutFieldInfo);
  755. begin
  756.   if Info.DataSet.GetFieldData(Info.Field, FBuffer) then
  757.   begin
  758.     if (Info.Field is TStringField) then
  759.       if TStringField(Info.Field).Transliterate then
  760.         Info.Size := Info.DataSet.Translate(PChar(FBuffer), PChar(FBuffer), False) else
  761.         Info.Size := StrLen(PChar(FBuffer));
  762.     FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer));
  763.   end else
  764.     FIDSWriter.PutField(fldIsNull, 0, nil);
  765. end;
  766. procedure TDataPacketWriter.PutField(Info: PPutFieldInfo);
  767. begin
  768.   if Info.DataSet.GetFieldData(Info.FieldNo, FBuffer) then
  769.     FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer)) else
  770.     FIDSWriter.PutField(fldIsNull, 0, nil);
  771. end;
  772. procedure TDataPacketWriter.PutStringField(Info: PPutFieldInfo);
  773. begin
  774.   if Length(FBuffer) <= Info.Size then
  775.     SetLength(FBuffer, Info.Size + 1);
  776.   if Info.DataSet.GetFieldData(Info.FieldNo, FBuffer) then
  777.   begin
  778.     if TStringField(Info.Field).Transliterate then
  779.       Info.Size := Info.DataSet.Translate(PChar(FBuffer), PChar(FBuffer), False) else
  780.       Info.Size := StrLen(PChar(FBuffer));
  781.     FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer));
  782.   end else
  783.     FIDSWriter.PutField(fldIsNull, 0, nil);
  784. end;
  785. procedure TDataPacketWriter.PutWideStringField(Info: PPutFieldInfo);
  786. var
  787.   W: WideString;
  788. begin
  789.   if Info.DataSet.GetFieldData(Info.field, @W, False) then
  790.   begin
  791.     Info.Size := Length(W);
  792.     FIDSWriter.PutField(fldIsChanged, Info.Size * 2, PByte(W));
  793.   end else
  794.     FIDSWriter.PutField(fldIsNull, 0, nil);
  795. end;
  796. procedure TDataPacketWriter.PutVarBytesField(Info: PPutFieldInfo);
  797. begin
  798.   if Info.DataSet.GetFieldData(Info.FieldNo, FBuffer) then
  799.     FIDSWriter.PutField(fldIsChanged, PWord(FBuffer)^, @FBuffer[SizeOf(Word)]) else
  800.     FIDSWriter.PutField(fldIsNull, 0, nil);
  801. end;
  802. procedure TDataPacketWriter.PutADTField(Info: PPutFieldInfo);
  803. var
  804.   i: Integer;
  805. begin
  806.   if Info.Field.IsNull then
  807.     FIDSWriter.PutField(fldIsNull, 0, nil) else
  808.     FIDSWriter.PutField(fldIsChanged, 0, nil);
  809.   for i := 0 to High(TInfoArray(Info.FieldInfos)) do
  810.     with TInfoArray(Info^.FieldInfos)[i] do
  811.       PutProc(@TInfoArray(Info.FieldInfos)[i]);
  812. end;
  813. procedure TDataPacketWriter.PutArrayField(Info: PPutFieldInfo);
  814.   procedure RefreshInfos(Src: TField; Dest: PPutFieldInfo);
  815.   var
  816.     i: Integer;
  817.   begin
  818.     with Dest^ do
  819.     begin
  820.       Field := Src;
  821.       FieldNo := Src.FieldNo;
  822.       if (FieldInfos <> nil) then { Must be an ADT }
  823.       begin
  824.         if not (Src is TADTField) then
  825.           raise EDSWriter.CreateFmt(SArrayElementError,[Src.ClassName]);
  826.         with (Src as TADTField) do
  827.           for i := 0 to FieldCount - 1 do
  828.             RefreshInfos(Fields[i], @TInfoArray(FieldInfos)[i]);
  829.       end;
  830.     end;
  831.   end;
  832. var
  833.   i: Integer;
  834. begin
  835.   if Info.Field.IsNull then
  836.     FIDSWriter.PutField(fldIsNull, 0, nil) else
  837.     FIDSWriter.PutField(fldIsChanged, 0, nil);
  838.   for i := 0 to TArrayField(Info.Field).FieldCount - 1 do
  839.     with TInfoArray(Info^.FieldInfos)[0] do
  840.     begin
  841.       RefreshInfos(TArrayField(Info.Field).Fields[i], @TInfoArray(Info.FieldInfos)[0]);
  842.       PutProc(@TInfoArray(Info.FieldInfos)[0]);
  843.     end;
  844. end;
  845. procedure TDataPacketWriter.PutDataSetField(Info: PPutFieldInfo);
  846. var
  847.   Count: DWord;
  848.   DataSet: TDataSet;
  849. begin
  850.   if Info.Field <> nil then
  851.   begin
  852.     if Info.Field.IsNull then
  853.     begin
  854.       FIDSWriter.PutField(fldIsNull, 0, nil);
  855.       Exit;
  856.     end;
  857.     DataSet := TDataSetField(Info.Field).NestedDataSet;
  858.   end else
  859.     DataSet := Info.DataSet;
  860.   if (poFetchDetailsOnDemand in Options) then
  861.     Count := dsDELAYEDBIT else
  862.     Count := DWord(-1);
  863.   FIDSWriter.PutField(fldIsChanged, SizeOf(Count), @Count);
  864.   if (not (poFetchDetailsOnDemand in Options)) and (Count = DWord(-1)) then
  865.   begin
  866.     DataSet.UpdateCursorPos;
  867.     DataSet.First;
  868.     DataSet.BlockReadSize := MaxInt;
  869.     try
  870.       WriteDataSet(DataSet, TInfoArray(Info.FieldInfos), -1);
  871.       FIDSWriter.EndOfNestedRows;
  872.     finally
  873.       DataSet.BlockReadSize := 0;
  874.     end;
  875.   end;
  876. end;
  877. function TDataPacketWriter.WriteDataSet(DataSet: TDataSet; var Info: TInfoArray;
  878.   RecsOut: Integer): Integer;
  879. const
  880.   B: Byte = 0;
  881. var
  882.   i: Integer;
  883.   ChildOpened: Boolean;
  884.   function OpenCloseDetails(Info: TInfoArray; ActiveState: Boolean): Boolean;
  885.   var
  886.     I: Integer;
  887.   begin
  888.     Result := False;
  889.     for I := 0 to High(Info) do
  890.     begin
  891.       if Info[I].IsDetail and (Info[I].DataSet.Active <> ActiveState) then
  892.       begin
  893.         Info[I].DataSet.Active := ActiveState;
  894.         Info[I].Opened := ActiveState;
  895.         Result := True;
  896.       end;
  897.     end;
  898.   end;
  899. begin
  900.   Result := 0;
  901.   if RecsOut = AllRecords then
  902.     RecsOut := High(Integer);
  903.   if DataSet.DefaultFields then
  904.     RefreshPutProcs(DataSet, Info);
  905.   ChildOpened := OpenCloseDetails(Info, True);
  906.   while (not DataSet.EOF) and (Result < RecsOut) do
  907.   begin
  908.     FIDSWriter.PutField(fldIsChanged, 1, @B);
  909.     for i := 0 to High(Info) do
  910.       Info[i].PutProc(@Info[i]);
  911.     Inc(Result);
  912.     if Result < RecsOut then
  913.       DataSet.Next;
  914.   end;
  915.   if ChildOpened then
  916.     OpenCloseDetails(Info, False);
  917. end;
  918. { Writing meta data }
  919. procedure TDataPacketWriter.AddDataSetAttributes(DataSet: TDataSet);
  920. var
  921.   i: Integer;
  922.   List: TList;
  923. begin
  924.   if Assigned(FOnGetParams) then
  925.   begin
  926.     List := TList.Create;
  927.     try
  928.       FOnGetParams(DataSet, List);
  929.       for i := 0 to List.Count - 1 do
  930.         with PPacketAttribute(List[i])^ do
  931.         begin
  932.           AddAttribute(pcktAttrArea, Name, Value, IncludeInDelta);
  933.           Dispose(PPacketAttribute(List[i]));
  934.         end;
  935.     finally
  936.       List.Free;
  937.     end;
  938.   end;
  939. end;
  940. function TDataPacketWriter.GetFieldIdx(const FieldName: string; const Info: TInfoArray): Integer;
  941. var
  942.   i: Integer;
  943. begin
  944.   Result := -1;
  945.   for i := 0 to High(Info) do
  946.     if (Info[i].Field <> nil) and (Info[i].Field.FieldName = FieldName) then
  947.     begin
  948.       Result := Info[i].LocalFieldIndex;
  949.       break;
  950.     end;
  951. end;
  952. type
  953.   TPropWriter = class(TWriter);
  954. procedure TDataPacketWriter.AddExtraFieldProps(Field: TField);
  955.   procedure WriteProp(Instance: TPersistent; const PropName: string;
  956.     Writer: TPropWriter);
  957.   var
  958.     PropInfo: PPropInfo;
  959.   begin
  960.     PropInfo := TypInfo.GetPropInfo(Instance.ClassInfo, PropName);
  961.     if (PropInfo <> nil) and IsStoredProp(Instance, PropInfo) then
  962.       Writer.WriteProperty(Instance, PropInfo);
  963.   end;
  964. var
  965.   Writer: TPropWriter;
  966.   Stream: TMemoryStream;
  967.   i: Integer;
  968.   Attr: Cardinal;
  969. begin
  970.   Stream := TMemoryStream.Create;
  971.   try
  972.     Writer := TPropWriter.Create(Stream, 1024);
  973.     try
  974.       Writer.WriteListBegin;
  975.       for i := 0 to High(ExtraFieldProps) do
  976.         WriteProp(Field, ExtraFieldProps[i], Writer);
  977.       Writer.WriteListEnd;
  978.       Writer.FlushBuffer;
  979.       if Stream.Size > 2 then
  980.       begin
  981.         Attr := (dsfldBYTES shl dsSizeBitsLen) or dsArrayFldType or SizeOf(Byte) or dsIncInDelta;
  982.         PInteger(FBuffer)^ := Stream.Size;
  983.         Move(Stream.Memory^, FBuffer[SizeOf(Integer)], Stream.Size);
  984.         Check(FIDSWriter.AddAttribute(fldAttrArea, szFIELDPROPS, Attr,
  985.           Stream.Size + SizeOf(Integer), FBuffer));
  986.       end;
  987.     finally
  988.       Writer.Free;
  989.     end;
  990.   finally
  991.     Stream.Free;
  992.   end;
  993. end;
  994. procedure TDataPacketWriter.AddColumn(const Info: TPutFieldInfo);
  995.   procedure AddFieldDesc(const FldName: string; FldType, Attributes: Integer);
  996.   var
  997.     FldDesc: TDSDataPacketFldDesc;
  998.   begin
  999.     if Length(FldName) >= SizeOf(FldDesc.szFieldName) then
  1000.       raise EDSWriter.CreateFmt(SFieldNameTooLong,[SizeOf(FldDesc.szFieldName) - 1]);
  1001.     FillChar(FldDesc, SizeOf(FldDesc), 0);
  1002.     StrLCopy(FldDesc.szFieldName, PChar(FldName), SizeOf(FldDesc.szFieldName) - 1);
  1003.     FldDesc.iFieldType := FldType;
  1004.     FldDesc.iAttributes := Attributes;
  1005.     Check(FIDSWriter.AddColumnDesc(FldDesc));
  1006.   end;
  1007.   function ComputeInfoCount(Info: TInfoArray): Integer;
  1008.   var
  1009.     i: Integer;
  1010.   begin
  1011.     Result := Length(Info);
  1012.     for i := 0 to High(Info) do
  1013.       if Info[i].FieldInfos <> nil then
  1014.         Inc(Result, ComputeInfoCount(Info[i].FieldInfos));
  1015.   end;
  1016.   procedure AddMinMax(AField: TField);
  1017.   begin
  1018.     case AField.DataType of
  1019.       ftInteger, ftSmallInt:    
  1020.         if (TIntegerField(AField).MinValue <> 0) or 
  1021.            (TIntegerField(AField).MaxValue <> 0)  then
  1022.            begin
  1023.              AddAttribute(fldAttrArea, szMINVALUE, 
  1024.                            TIntegerField(AField).MinValue, False);
  1025.              AddAttribute(fldAttrArea, szMAXVALUE, 
  1026.                           TIntegerField(AField).MaxValue, False);
  1027.            end;
  1028.       ftCurrency, ftFloat:
  1029.         if (TFloatField(AField).MinValue <> 0 ) or 
  1030.            (TFloatField(AField).MaxValue <> 0 ) then
  1031.            begin
  1032.              AddAttribute(fldAttrArea, szMINVALUE, 
  1033.                            TFloatField(AField).MinValue, False);
  1034.              AddAttribute(fldAttrArea, szMAXVALUE, 
  1035.                           TFloatField(AField).MaxValue, False);
  1036.            end;
  1037.       ftBCD:
  1038.         if (TBCDField(AField).MinValue <> 0 ) or 
  1039.            (TIntegerField(AField).MaxValue <> 0 ) then
  1040.            begin
  1041.              AddAttribute(fldAttrArea, szMINVALUE, 
  1042.                            TBCDField(AField).MinValue, False);
  1043.              AddAttribute(fldAttrArea, szMAXVALUE, 
  1044.                           TBCDField(AField).MaxValue, False);
  1045.            end;
  1046.       ftFMTBcd:
  1047.         if (TFMTBcdField(AField).MaxValue <> '') or
  1048.            (TFMTBcdField(AField).MinValue <> '') then
  1049.            begin
  1050.              AddAttribute(fldAttrArea, szMINVALUE, 
  1051.                     VarFMTBcdCreate(TFMTBCDField(AField).MinValue, TFMTBCDField(AField).Precision, TFMTBCDField(AField).Size), False);
  1052.              AddAttribute(fldAttrArea, szMAXVALUE, 
  1053.                     VarFMTBcdCreate(TFMTBCDField(AField).MaxValue, TFMTBCDField(AField).Precision, TFMTBCDField(AField).Size), False);
  1054.            end;
  1055.     end;
  1056.   end;
  1057. var
  1058.   FldType, Prec, Attr, i, Width: Integer;
  1059.   TempStr: string;
  1060. begin
  1061.   if Info.IsDetail and (Info.Field = nil) then
  1062.   begin
  1063.     FldType := (dsfldEMBEDDEDTBL shl dsSizeBitsLen) or
  1064.       ComputeInfoCount(Info.FieldInfos) or dsPseudoFldType;
  1065.     AddFieldDesc(Info.DataSet.Name, FldType, 0);
  1066.     WriteMetaData(Info.DataSet, TInfoArray(Info.FieldInfos));
  1067.   end else
  1068.   begin
  1069.     Width := 0;
  1070.     Attr := 0;
  1071.     if Info.Field.ReadOnly or (Info.Field.FieldKind <> fkData) then Attr := Attr or fldAttrREADONLY;
  1072.     if Info.Field.Required and (Info.Field.DataType <> ftAutoInc) then Attr := Attr or fldAttrREQUIRED;
  1073.     if (pfHidden in Info.Field.ProviderFlags) then Attr := Attr or fldAttrHIDDEN or fldAttrREADONLY;
  1074.     FldType := PacketTypeMap[Info.Field.DataType];
  1075.     case Info.Field.DataType of
  1076.       ftTimeStamp:
  1077.         FldType := (FldType shl dsSizeBitsLen) or sizeof(TSQLTimeStamp);
  1078.       ftString, ftFixedChar, ftVarBytes, ftGUID, ftWideString:
  1079.       begin
  1080.         FldType := FldType shl dsSizeBitsLen or dsVaryingFldType;
  1081.         if Info.Size < 255 then
  1082.           FldType := FldType or SizeOf(Byte) else
  1083.           FldType := FldType or SizeOf(Word);
  1084.         Width := Info.Size;
  1085.       end;
  1086.       ftBCD:
  1087.       begin
  1088.         if TBCDField(Info.Field).Precision = 0 then
  1089.           Width := 32 else
  1090.           Width := TBCDField(Info.Field).Precision;
  1091.         Prec := Width shr 1;
  1092.         Inc(Prec, Prec and 1);  { Make an even number }
  1093.         FldType := (FldType shl dsSizeBitsLen) or (Prec + 2);
  1094.       end;
  1095.       ftFMTBcd:
  1096.       begin
  1097.         if TFMTBCDField(Info.Field).Precision = 0 then
  1098.           Width := 32 else
  1099.           Width := TFMTBCDField(Info.Field).Precision;
  1100.         Prec := Width shr 1;
  1101.         Inc(Prec, Prec and 1);  { Make an even number }
  1102.         FldType := (FldType shl dsSizeBitsLen) or (Prec + 2);
  1103.       end;
  1104.       ftArray:
  1105.         FldType := (FldType shl dsSizeBitsLen) or dsPseudoFldType or
  1106.           dsCompArrayFldType or TObjectField(Info.Field).Size;
  1107.       ftADT:
  1108.         FldType := (FldType shl dsSizeBitsLen) or dsPseudoFldType or
  1109.           TObjectField(Info.Field).FieldCount;
  1110.       ftDataSet, ftReference:
  1111.         FldType := (FldType shl dsSizeBitsLen) or dsPseudoFldType or
  1112.           dsEmbeddedFldType or ComputeInfoCount(TInfoArray(Info.FieldInfos));
  1113.     else
  1114.       if Info.Field.IsBlob then
  1115.       begin
  1116.         FldType := (FldType shl dsSizeBitsLen) or dsVaryingFldType or SizeOf(Integer);
  1117.         Width := Info.Field.Size;
  1118.       end else
  1119.         FldType := (FldType shl dsSizeBitsLen) or Info.Size;
  1120.     end;
  1121.     AddFieldDesc(Info.Field.FieldName, FldType, Attr);
  1122.     if (Info.Field.FieldKind <> fkData) then
  1123.       AddAttribute(fldAttrArea, szSERVERCALC, True, True);
  1124.     if Info.Field.ProviderFlags <> [pfInWhere, pfInUpdate] then
  1125.       AddAttribute(fldAttrArea, szPROVFLAGS, Byte(Info.Field.ProviderFlags), True);
  1126.     if Info.Field.Origin <> '' then
  1127.       AddAttribute(fldAttrArea, szORIGIN, Info.Field.Origin, True);
  1128.     if Width > 0 then
  1129.       AddAttribute(fldAttrArea, szWIDTH, Width, False);
  1130.     if Info.Field is TBCDField then 
  1131.     begin
  1132.       if TBCDField(Info.Field).Size <> 0 then
  1133.         AddAttribute(fldAttrArea, szDECIMALS, TBCDField(Info.Field).Size, False);
  1134.     end
  1135.     else if Info.Field is TFMTBCDField then 
  1136.     begin
  1137.       if TFMTBCDField(Info.Field).Size <> 0 then
  1138.         AddAttribute(fldAttrArea, szDECIMALS, TFMTBCDField(Info.Field).Size, False);
  1139.     end;
  1140.     AddMinMax(Info.Field);
  1141.     case Info.Field.DataType of
  1142.       ftCurrency: TempStr := szstMONEY;
  1143.       ftAutoInc: TempStr := szstAUTOINC;
  1144.       ftVarBytes, ftBlob: TempStr := szstBINARY;
  1145.       ftMemo: TempStr := szstMEMO;
  1146.       ftFmtMemo: TempStr := szstFMTMEMO;
  1147.       ftParadoxOle: TempStr := szstOLEOBJ;
  1148.       ftGraphic: TempStr := szstGRAPHIC;
  1149.       ftDBaseOle: TempStr := szstDBSOLEOBJ;
  1150.       ftTypedBinary: TempStr := szstTYPEDBINARY;
  1151.       ftADT:
  1152.         if (Info.Field.ParentField <> nil) and
  1153.            (Info.Field.ParentField.DataType in [ftDataSet, ftReference]) then
  1154.           TempStr := szstADTNESTEDTABLE;
  1155.       ftReference: TempStr := szstREFNESTEDTABLE;
  1156.       ftString:
  1157.         if TStringField(Info.Field).FixedChar then
  1158.           TempStr := szstFIXEDCHAR else
  1159.           TempStr := '';
  1160.       ftGUID: TempStr := szstGUID;
  1161.       ftOraClob: TempStr := szstHMEMO;
  1162.       ftOraBlob: TempStr := szstHBINARY;
  1163.     else
  1164.         TempStr := '';
  1165.     end;
  1166.     if TempStr <> '' then
  1167.       AddAttribute(fldAttrArea, szSUBTYPE, TempStr, False);
  1168.     if Info.Field is TObjectField then
  1169.       AddAttribute(fldAttrArea, szTYPENAME, TObjectField(Info.Field).ObjectType, False);
  1170.     if poIncFieldProps in Options then
  1171.       AddExtraFieldProps(Info.Field);
  1172.     case Info.Field.DataType of
  1173.       ftADT, ftArray: { Array will only have 1 child field }
  1174.         for i := 0 to High(TInfoArray(Info.FieldInfos)) do
  1175.           AddColumn(TInfoArray(Info.FieldInfos)[i]);
  1176.       ftDataSet, ftReference:
  1177.         with TDataSetField(Info.Field) do
  1178.           WriteMetaData(NestedDataSet, TInfoArray(Info.FieldInfos),
  1179.             Info.Field.DataType = ftReference);
  1180.     end;
  1181.   end;
  1182. end;
  1183. procedure TDataPacketWriter.AddConstraints(DataSet: TDataSet);
  1184. type
  1185.   TConstraintType = (ctField, ctRecord, ctDefault);
  1186.   procedure AddSQLExprAttr(ExprParser: TExprParser; const ExprText, ExprErrMsg,
  1187.     FieldName: string; FieldIndex: Integer; ConstraintType: TConstraintType;
  1188.     Required: Boolean);
  1189.   type
  1190.     PSQLExprInfo = ^TSQLExprInfo;
  1191.     TSQLExprInfo = packed record
  1192.       iErrStrLen: Integer;
  1193.       iFldNum: Integer;
  1194.       bReqExpr: BYTE;
  1195.     end;
  1196.   const
  1197.     TypeStr: array[TConstraintType] of PChar = (szBDEDOMX, szBDERECX, szBDEDEFX);
  1198.     Attr: Integer = dsVaryingFldType or SizeOf(Integer) or (dsfldBYTES shl dsSizeBitsLen);
  1199.   var
  1200.     ErrorStr: string;
  1201.     AttrType: PChar;
  1202.     Len, AttrSize: Integer;
  1203.     SQLExprInfo: PSQLExprInfo;
  1204.     Options: TParserOptions;
  1205.   begin
  1206.     if ExprText = '' then Exit;
  1207.     if (ConstraintType <> ctDefault) and (ExprErrMsg = '') then
  1208.     begin
  1209.       if (ConstraintType = ctField) and (FieldName <> '') then
  1210.         ErrorStr := Format('%s %s: %s %s',[SConstraintFailed, SField, FieldName, ExprText]) else
  1211.         ErrorStr := Format('%s %s',[SConstraintFailed, ExprText]);
  1212.     end else
  1213.       ErrorStr := ExprErrMsg;
  1214.     Len := Length(ErrorStr);
  1215.     if (Len > 0) then Inc(Len);
  1216.     SQLExprInfo := @FBuffer[SizeOf(Integer)];
  1217.     SQLExprInfo.iErrStrLen := Len;
  1218.     SQLExprInfo.iFldNum := FieldIndex;
  1219.     SQLExprInfo.bReqExpr := Ord(Required);
  1220.     Options := [poExtSyntax];
  1221.     if ConstraintType = ctDefault then Include(Options, poDefaultExpr);
  1222.     if ConstraintType = ctRecord then Include(Options, poUseOrigNames);
  1223.     if FieldName <> '' then Include(Options, poFieldNameGiven);
  1224.     with ExprParser do
  1225.     begin
  1226.       SetExprParams(ExprText, [], Options, FieldName);
  1227.       Move(FilterData[0], FBuffer[SizeOf(TSQLExprInfo) + Len + SizeOf(Integer)], DataSize);
  1228.       AttrSize := DataSize + SizeOf(TSQLExprInfo) + Len;
  1229.     end;
  1230.     PInteger(FBuffer)^ := AttrSize;
  1231.     if Len > 0 then
  1232.       StrLCopy(@FBuffer[SizeOf(TSQLExprInfo) + SizeOf(Integer)], PChar(ErrorStr), Length(FBuffer) - SizeOf(TSQLExprInfo) - SizeOf(Integer) - 1);
  1233.     AttrType := TypeStr[ConstraintType];
  1234.     Check(FIDSWriter.AddAttribute(pcktAttrArea, AttrType, Attr, AttrSize + SizeOf(Integer), PByte(FBuffer)));
  1235.   end;
  1236. var
  1237.   i: Integer;
  1238.   ExprParser: TExprParser;
  1239.   Constraints: TCheckConstraints;
  1240.   Obj: TObject;
  1241.   ErrMsg: string;
  1242. begin
  1243.   ExprParser := TExprParser.Create(DataSet, '', [], [], '', nil, FieldTypeMap);
  1244.   try
  1245.     Obj := GetObjectProperty(DataSet, 'Constraints'); { Do not localize }
  1246.     if (Obj <> nil) and (Obj is TCheckConstraints) then
  1247.     begin
  1248.       Constraints := Obj as TCheckConstraints;
  1249.       try
  1250.         for i := 0 to Constraints.Count - 1 do
  1251.           with Constraints[i] do
  1252.           begin
  1253.             AddSQLExprAttr(ExprParser, ImportedConstraint, ErrorMessage, '', 0,
  1254.               ctRecord, False);
  1255.             AddSQLExprAttr(ExprParser, CustomConstraint, ErrorMessage, '', 0,
  1256.               ctRecord, False);
  1257.           end;
  1258.       except
  1259.         if DataSet.Name <> '' then
  1260.           ErrMsg := Format('%s: %s',[DataSet.Name, SRecConstFail]) 
  1261.         else
  1262.           ErrMsg := SRecConstFail;
  1263.         if ExceptObject is Exception then
  1264.           raise EDSWriter.CreateFmt(ErrMsg, [Exception(ExceptObject).Message])
  1265.         else
  1266.           raise EDSWriter.CreateFmt(ErrMsg, ['']);
  1267.       end;
  1268.     end;
  1269.     for i := 0 to DataSet.FieldList.Count - 1 do
  1270.       with DataSet.FieldList[i] do
  1271.       begin
  1272.         try
  1273.           AddSQLExprAttr(ExprParser, DefaultExpression, '', FullName, i + 1,
  1274.             ctDefault, False);
  1275.         except
  1276.           if Name <> '' then
  1277.             ErrMsg := Format('%s: %s',[Name, SDefExprFail]) else
  1278.           if DataSet.Name <> '' then
  1279.             ErrMsg := Format('%s.%s: %s',[DataSet.Name, FullName, SDefExprFail]) else
  1280.             ErrMsg := Format('%s: %s', [FullName, SDefExprFail]);
  1281.           if ExceptObject is Exception then
  1282.             raise EDSWriter.CreateFmt(ErrMsg, [Exception(ExceptObject).Message])
  1283.           else
  1284.             raise EDSWriter.CreateFmt(ErrMsg, ['']);
  1285.         end;
  1286.         try
  1287.           AddSQLExprAttr(ExprParser, ImportedConstraint, ConstraintErrorMessage,
  1288.             FullName, i + 1, ctField, False);
  1289.           AddSQLExprAttr(ExprParser, CustomConstraint, ConstraintErrorMessage,
  1290.             FullName, i + 1, ctField, False);
  1291.         except
  1292.           if Name <> '' then
  1293.             ErrMsg := Format('%s: %s',[Name, SFieldConstFail]) else
  1294.           if DataSet.Name <> '' then
  1295.             ErrMsg := Format('%s.%s: %s',[DataSet.Name, FullName, SFieldConstFail]) else
  1296.             ErrMsg := Format('%s: %s', [FullName, SFieldConstFail]);
  1297.           if ExceptObject is Exception then
  1298.             raise EDSWriter.CreateFmt(ErrMsg, [Exception(ExceptObject).Message])
  1299.           else
  1300.             raise EDSWriter.CreateFmt(ErrMsg, ['']);
  1301.         end;
  1302.       end;
  1303.   finally
  1304.     ExprParser.Free;
  1305.   end;
  1306. end;
  1307. procedure TDataPacketWriter.AddIndexDefs(DataSet: TDataSet; const Info: TInfoArray);
  1308. var
  1309.   FieldList, CaseList, DescList: TList;
  1310.   function GetKeyData(Index: TIndexDef): OleVariant;
  1311.   var
  1312.     i: Integer;
  1313.     x: Integer;
  1314.   begin
  1315.     with Index do
  1316.     begin
  1317.       FieldList.Clear;
  1318.       CaseList.Clear;
  1319.       DescList.Clear;
  1320.       DataSet.GetFieldList(FieldList, Fields);
  1321.       DataSet.GetFieldList(CaseList, CaseInsFields);
  1322.       DataSet.GetFieldList(DescList, DescFields);
  1323.       Result := VarArrayCreate([0, FieldList.Count - 1], varInteger);
  1324.       for i := 0 to FieldList.Count - 1 do
  1325.       begin
  1326.         x := GetFieldIdx(TField(FieldList[i]).FieldName, Info);
  1327.         if (CaseList.IndexOf(FieldList[i]) <> -1) or
  1328.            ((i = 0) and (FieldList.Count = 1) and (ixCaseInSensitive in Options)) then
  1329.           x := x or dskeyCASEINSENSITIVE;
  1330.         if (DescList.IndexOf(FieldList[i]) <> -1) or
  1331.            ((i = 0) and (FieldList.Count = 1) and (ixDescending in Options)) then
  1332.           x := x or dskeyDESCENDING;
  1333.         Result[i] := x;
  1334.       end;
  1335.     end;
  1336.   end;
  1337. var
  1338.   i: Integer;
  1339.   DefIdx, KeyIndex: TIndexDef;
  1340.   IndexDefs: TIndexDefs;
  1341.   KeyList: OleVariant;
  1342.   KeyFields: string;
  1343. begin
  1344.   FieldList := TList.Create;
  1345.   try
  1346.     CaseList := TList.Create;
  1347.     try
  1348.       DescList := TList.Create;
  1349.       try
  1350.         { Get the DEFAULT_ORDER }
  1351.         if not (poRetainServerOrder in Options) then
  1352.           DefIdx := IProviderSupport(DataSet).PSGetDefaultOrder
  1353.         else
  1354.           DefIdx := nil;
  1355.         if Assigned(DefIdx) then
  1356.         try
  1357.           KeyList := GetKeyData(DefIdx);
  1358.           AddAttribute(pcktAttrArea, szDEFAULT_ORDER, KeyList, False);
  1359.         finally
  1360.           DefIdx.Free;
  1361.         end;
  1362.         KeyFields := IProviderSupport(DataSet).PSGetKeyFields;
  1363.         IndexDefs := IProviderSupport(DataSet).PSGetIndexDefs([ixUnique]);
  1364.         try
  1365.           if KeyFields <> '' then
  1366.           begin
  1367.             { PRIMARY_KEY is used to define the keyfields }
  1368.             KeyList := NULL;
  1369.             if Assigned(IndexDefs) then
  1370.             begin
  1371.               KeyIndex := IndexDefs.GetIndexForFields(KeyFields, False);
  1372.               if Assigned(KeyIndex) then
  1373.               begin
  1374.                 KeyList := GetKeyData(KeyIndex);
  1375.                 KeyIndex.Free;{ KeyIndex is already used, remove it from the list }
  1376.               end;
  1377.             end;
  1378.             if VarIsNull(KeyList) then
  1379.             begin
  1380.               DataSet.GetFieldList(FieldList, KeyFields);
  1381.               KeyList := VarArrayCreate([0, FieldList.Count - 1], varSmallInt);
  1382.               for i := 0 to FieldList.Count - 1 do
  1383.                 KeyList[i] := GetFieldIdx(TField(FieldList[i]).FieldName, Info);
  1384.             end;
  1385.             if not VarIsNull(KeyList) then
  1386.               AddAttribute(pcktAttrArea, szPRIMARY_KEY, KeyList, False);
  1387.           end;
  1388.           if Assigned(IndexDefs) then
  1389.             for i := 0 to IndexDefs.Count - 1 do
  1390.               with IndexDefs[i] do
  1391.               begin
  1392.                 KeyList := GetKeyData(IndexDefs[i]);
  1393.                 AddAttribute(pcktAttrArea, szUNIQUE_KEY, KeyList, False);
  1394.               end;
  1395.         finally
  1396.           IndexDefs.Free;
  1397.         end;
  1398.       finally
  1399.         DescList.Free;
  1400.       end;
  1401.     finally
  1402.       CaseList.Free;
  1403.     end;
  1404.   finally
  1405.     FieldList.Free;
  1406.   end;
  1407. end;
  1408. procedure TDataPacketWriter.AddFieldLinks(const Info: TInfoArray);
  1409. var
  1410.   MasterFields, DetailFields: TList;
  1411.   i, j: Integer;
  1412.   LinkFields: Variant;
  1413. begin
  1414.   MasterFields := TList.Create;
  1415.   try
  1416.     DetailFields := TList.Create;
  1417.     try
  1418.       for i := 0 to High(Info) do
  1419.         if Info[i].IsDetail and (Info[i].Field = nil) then
  1420.         begin
  1421.           Info[i].DataSet.GetDetailLinkFields(MasterFields, DetailFields);
  1422.           if (MasterFields.Count > 0) and (MasterFields.Count <= DetailFields.Count) then
  1423.           begin
  1424.             LinkFields := VarArrayCreate([0, MasterFields.Count * 2], varSmallInt);
  1425.             LinkFields[0] := Info[i].LocalFieldIndex;
  1426.             for j := 0 to MasterFields.Count - 1 do
  1427.               LinkFields[j + 1] := GetFieldIdx(TField(MasterFields[j]).FieldName,
  1428.                 Info);
  1429.             for j := 0 to MasterFields.Count - 1 do
  1430.               LinkFields[j + MasterFields.Count + 1] :=
  1431.                 GetFieldIdx(TField(DetailFields[j]).FieldName, TInfoArray(Info[i].FieldInfos));
  1432.             AddAttribute(pcktAttrArea, szMD_FIELDLINKS, LinkFields, False);
  1433.           end;
  1434.         end;
  1435.     finally
  1436.       DetailFields.Free;
  1437.     end;
  1438.   finally
  1439.     MasterFields.Free;
  1440.   end;
  1441. end;
  1442. procedure TDataPacketWriter.WriteMetaData(DataSet: TDataSet; const Info: TInfoArray;
  1443.   IsReference: Boolean);
  1444. var
  1445.   i, MDOptions: Integer;
  1446. begin
  1447.   for i := 0 to High(Info) do
  1448.     AddColumn(Info[i]);
  1449.   if (poReadOnly in Options) or IsReference then
  1450.     AddAttribute(pcktAttrArea, szREADONLY, True, False);
  1451.   if (poDisableEdits in Options) then
  1452.     AddAttribute(pcktAttrArea, szDISABLE_EDITS, True, False);
  1453.   if (poDisableInserts in Options) then
  1454.     AddAttribute(pcktAttrArea, szDISABLE_INSERTS, True, False);
  1455.   if (poDisableDeletes in Options) then
  1456.     AddAttribute(pcktAttrArea, szDISABLE_DELETES, True, False);
  1457.   if (poNoReset in Options) then
  1458.     AddAttribute(pcktAttrArea, szNO_RESET_CALL, True, False);
  1459.   if Constraints then
  1460.     AddConstraints(DataSet);
  1461.   AddIndexDefs(DataSet, Info);
  1462.   AddFieldLinks(Info);
  1463.   MDOptions := 0;
  1464.   if poCascadeDeletes in Options then MDOptions := dsCASCADEDELETES;
  1465.   if poCascadeUpdates in Options then MDOptions := MDOptions or dsCASCADEUPDATES;
  1466.   if MDOptions <> 0 then
  1467.     AddAttribute(pcktAttrArea, szMD_SEMANTICS, MDOptions, True);
  1468.   AddDataSetAttributes(DataSet);
  1469.   if Info <> FPutFieldInfo then
  1470.     Check(FIDSWriter.AddAttribute(pcktAttrArea, nil, 0, 0, nil));
  1471. end;
  1472. procedure TDataPacketWriter.RefreshPutProcs(ADataSet: TDataSet; var Info: TInfoArray);
  1473.   procedure RefreshInfo(ADataSet: TDataSet; AField: TField; var Info: TPutFieldInfo);
  1474.   var
  1475.     j: Integer;
  1476.   begin
  1477.     Info.Field := AField;
  1478.     if AField = nil then
  1479.       Info.DataSet := ADataSet
  1480.     else
  1481.     begin
  1482.       Info.DataSet := AField.DataSet;
  1483.       if AField.DataType = ftADT then
  1484.       begin
  1485.         with TADTField(AField) do
  1486.         for j := 0 to FieldCount - 1 do
  1487.           RefreshInfo(ADataSet, Fields[j], TInfoArray(Info.FieldInfos)[j]);
  1488.       end;
  1489.     end;
  1490.   end;
  1491. var
  1492.   i: Integer;
  1493.   List: TList;
  1494. begin
  1495.   List := TList.Create;
  1496.   try
  1497.     ADataSet.GetDetailDataSets(List);
  1498.     for i := 0 to ADataSet.FieldCount - 1 do
  1499.       RefreshInfo(ADataSet, ADataSet.Fields[i], Info[i]);
  1500.     for i := 0 to List.Count - 1 do
  1501.       RefreshInfo(TDataSet(List[i]), nil, Info[ADataSet.FieldCount + i]);
  1502.   finally
  1503.     List.Free;
  1504.   end;
  1505. end;
  1506. function TDataPacketWriter.InitPutProcs(ADataSet: TDataSet;
  1507.   var GlobalIdx: Integer): TInfoArray;
  1508.   procedure InitInfoStruct(var Info: TPutFieldInfo; AField: TField;
  1509.     var GlobalIdx, LocalIdx: Integer);
  1510.   begin
  1511.     FillChar(Info, SizeOf(Info), 0);
  1512.     with Info do
  1513.     begin
  1514.       IsDetail := AField = nil;
  1515.       Field := AField;
  1516.       Inc(GlobalIdx);
  1517.       LocalFieldIndex := LocalIdx;
  1518.       Inc(LocalIdx);
  1519.       if Field <> nil then
  1520.       begin
  1521.         FieldNo := Field.FieldNo;
  1522.         Size := Field.DataSize;
  1523.         DataSet := Field.DataSet;
  1524.       end;
  1525.     end;
  1526.   end;
  1527.   procedure InitFieldProc(ADataSet: TDataSet; AField: TField;
  1528.     var Info: TPutFieldInfo; var GlobalIdx, LocalIdx: Integer);
  1529.   var
  1530.     i: Integer;
  1531.     NestedIdx: Integer;
  1532.   begin
  1533.     with Info do
  1534.     begin
  1535.       InitInfoStruct(Info, AField, GlobalIdx, LocalIdx);
  1536.       if AField = nil then { Linked dataset }
  1537.       begin
  1538.         Opened := not ADataSet.Active;
  1539.         if Opened then ADataSet.Open;
  1540.         DataSet := ADataSet;
  1541.         PutProc := PutDataSetField;
  1542.         TInfoArray(FieldInfos) := InitPutProcs(DataSet, GlobalIdx);
  1543.       end else
  1544.       begin
  1545.         case Field.DataType of
  1546.           ftString, ftFixedChar, ftGUID:
  1547.           begin
  1548.             PutProc := PutStringField;
  1549.             Dec(Size);  { Don't count the null terminator }
  1550.           end;
  1551.           ftWideString:
  1552.           begin
  1553.             PutProc := PutWideStringField;
  1554.             Size := AField.Size * 2;
  1555.           end;
  1556.           ftVarBytes:
  1557.           begin
  1558.             PutProc := PutVarBytesField;
  1559.             Dec(Size, 2); { Don't write size bytes }
  1560.           end;
  1561.           ftADT:
  1562.           with TADTField(Field) do
  1563.           begin
  1564.             PutProc := PutADTField;
  1565.             SetLength(TInfoArray(FieldInfos), FieldCount);
  1566.             for i := 0 to FieldCount - 1 do
  1567.               InitFieldProc(ADataSet, Fields[i], TInfoArray(FieldInfos)[i],
  1568.                 GlobalIdx, LocalIdx);
  1569.           end;
  1570.           ftArray:
  1571.           with TArrayField(Field) do
  1572.           begin
  1573.             PutProc := PutArrayField;
  1574.             SetLength(TInfoArray(FieldInfos), 1);
  1575.             NestedIdx := LocalIdx;
  1576.             InitFieldProc(ADataSet, Fields[0], TInfoArray(FieldInfos)[0],
  1577.                 GlobalIdx, LocalIdx);
  1578.             LocalIdx := (LocalIdx - NestedIdx) * (FieldCount - 1) + LocalIdx;
  1579.           end;
  1580.           ftDataSet, ftReference:
  1581.           with TDataSetField(Field).NestedDataSet do
  1582.           begin
  1583.             PutProc := PutDataSetField;
  1584.             NestedIdx := 1;
  1585.             SetLength(TInfoArray(FieldInfos), FieldCount);
  1586.             for i := 0 to FieldCount - 1 do
  1587.               InitFieldProc(TDataSetField(Field).NestedDataSet, Fields[i],
  1588.                 TInfoArray(FieldInfos)[i], GlobalIdx, NestedIdx);
  1589.           end;
  1590.           ftSmallint, ftInteger, ftWord, ftBoolean, ftFloat, ftCurrency, ftBCD,
  1591.           ftDate, ftTime, ftDateTime, ftAutoInc, ftLargeint, ftBytes, ftTimeStamp, ftFMTBcd:
  1592.             PutProc := PutField;
  1593.           ftBlob, ftMemo, ftGraphic, ftFmtMemo, ftParadoxOle, ftDBaseOle, ftTypedBinary, ftOraBlob, ftOraClob:
  1594.             PutProc := PutBlobField;
  1595.         else
  1596.           DatabaseErrorFmt(SUnknownFieldType, [Field.FieldName]);
  1597.         end;
  1598.         if Field.FieldKind <> fkData then
  1599.           PutProc := PutCalcField;
  1600.       end;
  1601.     end;
  1602.   end;
  1603. var
  1604.   i, LocalIdx: Integer;
  1605.   List: TList;
  1606. begin
  1607.   LocalIdx := 1;
  1608.   List := TList.Create;
  1609.   try
  1610.     ADataSet.GetDetailDataSets(List);
  1611.     SetLength(Result, ADataSet.FieldCount + List.Count);
  1612.     for i := 0 to ADataSet.FieldCount - 1 do
  1613.       InitFieldProc(ADataSet, ADataSet.Fields[i], Result[i], GlobalIdx, LocalIdx);
  1614.     for i := 0 to List.Count - 1 do
  1615.       InitFieldProc(TDataSet(List[i]), nil, Result[ADataSet.FieldCount + i],
  1616.         GlobalIdx, LocalIdx);
  1617.   finally
  1618.     List.Free;
  1619.   end;
  1620. end;
  1621. procedure TDataPacketWriter.GetDataPacket(DataSet: TDataSet;
  1622.   var RecsOut: Integer; out Data: OleVariant);
  1623.   procedure CheckMetaData(DataSet: TDataSet);
  1624.   var
  1625.     Idx: Integer;
  1626.     TempPacket: TDataPacket;
  1627.     Version: Integer;
  1628.   begin
  1629.     Idx := 1;
  1630.     if (FPutFieldInfo = nil) or (grMetaData in PacketOptions) then
  1631.     begin
  1632.       CreateDBClientObject(CLSID_DSWriter, IDSWriter, FIDSWriter);
  1633.       if FPutFieldInfo <> nil then
  1634.       begin
  1635.         FreeInfoRecords(FPutFieldInfo);
  1636.         FPutFieldInfo := nil;
  1637.       end;
  1638.       FPutFieldInfo := InitPutProcs(DataSet, Idx);
  1639.       if poFetchBlobsOnDemand in Options then
  1640.         Version := PACKETVERSION_3 else
  1641.         Version := PACKETVERSION_1;
  1642.       if grXMLUTF8 in PacketOptions then
  1643.         FIDSWriter.SetXMLMode(xmlUTF8)
  1644.       else if grXML in PacketOptions then
  1645.         FIDSWriter.SetXMLMode(xmlON)
  1646.       else
  1647.         FIDSWriter.SetXMLMode(0);
  1648.       Check(FIDSWriter.Init_Sequential(Version, Idx - 1));
  1649.       WriteMetaData(DataSet, FPutFieldInfo);
  1650.       if not (grMetaData in PacketOptions) then
  1651.       begin
  1652.         FIDSWriter.GetDataPacket(TempPacket);
  1653.         SafeArrayCheck(SafeArrayDestroy(TempPacket));
  1654.         TempPacket := nil;
  1655.       end;
  1656.     end;
  1657.     if not (grMetaData in PacketOptions) then
  1658.       Check(FIDSWriter.Reset);
  1659.   end;
  1660. var
  1661.   DataPacket: TDataPacket;
  1662. begin
  1663.     CheckMetaData(DataSet);
  1664.     RecsOut := WriteDataSet(DataSet, FPutFieldInfo, RecsOut);
  1665.     FIDSWriter.GetDataPacket(DataPacket);
  1666.     DataPacketToVariant(DataPacket, Data);
  1667. end;
  1668. procedure TDataPacketWriter.Reset;
  1669.   procedure CloseDetailDatasets(const Info: TInfoArray);
  1670.   var
  1671.     i: integer;
  1672.   begin
  1673.     for i := 0 to High(Info) do
  1674.       if Info[i].IsDetail and (Info[i].Opened or Info[i].Dataset.Active) then
  1675.       begin
  1676.         Info[i].DataSet.Close;
  1677.         Info[i].Opened := False;
  1678.         CloseDetailDatasets(TInfoArray(Info[i].FieldInfos));
  1679.       end;
  1680.   end;
  1681. begin
  1682.   CloseDetailDatasets(FPutFieldInfo);
  1683. end;
  1684. { TPacketDataSet }
  1685. constructor TPacketDataSet.Create(AOwner: TComponent);
  1686. begin
  1687.   inherited;
  1688.   FetchOnDemand := False;
  1689. end;
  1690. procedure TPacketDataSet.CreateFromDelta(Source: TPacketDataSet);
  1691. var
  1692.   TempBase: IDSBase;
  1693. begin
  1694.   Source.Check(Source.DSBase.Clone(2, True, False, TempBase));
  1695.   DSBase := TempBase;
  1696.   Open;
  1697. end;
  1698. procedure TPacketDataSet.InternalInitRecord(Buffer: PChar);
  1699. var
  1700.   I: Integer;
  1701. begin
  1702.   inherited InternalInitRecord(Buffer);
  1703.   { Initialize new records in the error result dataset to unchanged values }
  1704.   for I := 1 to FieldCount do
  1705.     DSBase.PutBlank(PByte(Buffer), 0, I, BLANK_NOTCHANGED);
  1706. end;
  1707. procedure TPacketDataSet.InternalOpen;
  1708. var
  1709.   MDSem: DWord;
  1710. begin
  1711.   inherited InternalOpen;
  1712.   FOldRecBuf := AllocRecordBuffer;
  1713.   FCurRecBuf := AllocRecordBuffer;
  1714.   DSBase.GetProp(dspropMD_SEMANTICS, @MDSem);
  1715.   MDSem := MDSem and mdCASCADEMOD;
  1716.   DSBase.SetProp(dspropMD_SEMANTICS, MDSem);
  1717. end;
  1718. procedure TPacketDataSet.InternalClose;
  1719. begin
  1720.   inherited InternalClose;
  1721.   FreeRecordBuffer(FOldRecBuf);
  1722.   FreeRecordBuffer(FCurRecBuf);
  1723. end;
  1724. function TPacketDataSet.GetStateFieldValue(State: TDataSetState; Field: TField): Variant;
  1725. begin
  1726.   { When reading an OldValue, return the CurValue instead if we have one }
  1727.   if FUseCurValues and (State = dsOldValue) and HasCurValues then
  1728.   begin
  1729.     Result := inherited GetStateFieldValue(dsCurValue, Field);
  1730.     if not VarIsClear(Result) then Exit;
  1731.   end;
  1732.   Result := inherited GetStateFieldValue(State, Field);
  1733. end;
  1734. function TPacketDataSet.GetStreamMetaData: Boolean;
  1735. var
  1736.   Value: Integer;
  1737. begin
  1738.   DSBase.GetProp(DSProp(dspropDONTINCLMETADATA), @Value);
  1739.   Result := Value <> 0;
  1740. end;
  1741. procedure TPacketDataSet.SetStreamMetaData(Value: Boolean);
  1742. begin
  1743.   DSBase.SetProp(DSProp(dspropDONTINCLMETADATA), Integer(not Value));
  1744. end;
  1745. function TPacketDataSet.UpdateKind: TUpdateKind;
  1746. begin
  1747.   case UpdateStatus of
  1748.     usInserted: Result := ukInsert;
  1749.     usDeleted: Result := ukDelete;
  1750.   else
  1751.     Result := ukModify;
  1752.   end;
  1753. end;
  1754. procedure TPacketDataSet.DataEvent(Event: TDataEvent; Info: Integer);
  1755. begin
  1756.   if Event in [deDataSetScroll, deDataSetChange] then
  1757.   begin
  1758.     FNewValuesModified := False;
  1759.     FCurValues := nil;
  1760.   end;
  1761.   inherited DataEvent(Event, Info);
  1762. end;
  1763. function TPacketDataSet.HasCurValues: Boolean;
  1764. begin
  1765.   Result := FCurValues <> nil;
  1766. end;
  1767. procedure TPacketDataSet.InitAltRecBuffers(CheckModified: Boolean);
  1768. var
  1769.   No: Integer;
  1770. begin
  1771.   if UpdateStatus in [usUnmodified, usDeleted] then
  1772.     GetCurrentRecord(FOldRecBuf);
  1773.   if CheckModified and (UpdateStatus = usUnmodified) then
  1774.   begin
  1775.     No := RecNo;
  1776.     Next;
  1777.     if UpdateStatus <> usModified then
  1778.       RecNo := No;
  1779.   end;
  1780.   if UpdateStatus = usInserted then
  1781.     SetAltRecBuffers(ActiveBuffer, ActiveBuffer, FCurRecBuf) else
  1782.     SetAltRecBuffers(FOldRecBuf, ActiveBuffer, FCurRecBuf);
  1783. end;
  1784. procedure TPacketDataSet.SetFieldData(Field: TField; Buffer: Pointer);
  1785. begin
  1786.   { Set a flag when any of the field's NewValue properties are modified }
  1787.   if State = dsNewValue then
  1788.     FNewValuesModified := True;
  1789.   if FWritingCurValues then
  1790.     Check(DSCursor.PutField(FCurRecBuf, Field.FieldNo, Buffer)) else
  1791.     inherited SetFieldData(Field, Buffer);
  1792. end;
  1793. procedure TPacketDataSet.SetWritingCurValues(const Value: Boolean);
  1794. begin
  1795.   if Value then
  1796.   begin
  1797.     FCurValues := FCurRecBuf;
  1798.     InitRecord(FCurValues);
  1799.   end else
  1800.     InitAltRecBuffers;
  1801.   FWritingCurValues := Value;
  1802. end;
  1803. procedure TPacketDataSet.AssignCurValues(Source: TDataSet);
  1804. var
  1805.   I: Integer;
  1806.   NewValue: Variant;
  1807.   Field, SourceField: TField;
  1808. begin
  1809.   WritingCurValues := True;
  1810.   try
  1811.     for i := 0 to FieldCount - 1 do
  1812.     begin
  1813.       Field := Fields[i];
  1814.       SourceField := Source.FindField(Field.FieldName);
  1815.       if (SourceField <> nil) and not Field.IsBlob and
  1816.          not (Field.DataType in [ftBytes, ftVarBytes]) and
  1817.          (Field.OldValue <> SourceField.Value) then
  1818.       begin
  1819.         NewValue := Field.NewValue;
  1820.         if VarIsClear(Field.NewValue) or
  1821.            (NewValue <> SourceField.Value) then
  1822.           Field.Assign(SourceField);
  1823.       end;
  1824.     end;
  1825.   finally
  1826.     WritingCurValues := False;
  1827.   end;
  1828. end;
  1829. procedure TPacketDataSet.AssignCurValues(const CurValues: Variant);
  1830. var
  1831.   I: Integer;
  1832.   Field: TField;
  1833.   CurValue: Variant;
  1834. begin
  1835.   WritingCurValues := True;
  1836.   try
  1837.     if VarIsNull(CurValues) then
  1838.       FCurValues := nil
  1839.     else
  1840.       for I := VarArrayLowBound(CurValues, 1) to VarArrayHighBound(CurValues, 1) do
  1841.       begin
  1842.         if VarIsArray(CurValues[I]) then
  1843.         begin
  1844.           CurValue := CurValues[I][1];
  1845.           Field := FieldByName(CurValues[I][0])
  1846.         end else
  1847.         begin
  1848.           CurValue := CurValues[I];
  1849.           Field := Fields[I];
  1850.         end;
  1851.         if not VarIsClear(CurValue) then
  1852.           if (Field.OldValue <> CurValue) then
  1853.             Fields[I].Value := CurValue;
  1854.       end;
  1855.   finally
  1856.     WritingCurValues := False;
  1857.   end;
  1858. end;
  1859. function TPacketDataSet.HasMergeConflicts: Boolean;
  1860. var
  1861.   I: Integer;
  1862.   CurVal, NewVal: Variant;
  1863. begin
  1864.   Result := False;
  1865.   for I := 0 to FieldCount - 1 do
  1866.     with Fields[I] do
  1867.     begin
  1868.       CurVal := CurValue;
  1869.       if VarIsClear(CurVal) then Continue;
  1870.       NewVal := NewValue;
  1871.       if VarIsClear(NewVal) then Continue;
  1872.       if CurVal = NewVal then Continue;
  1873.       Result := True;
  1874.       Break;
  1875.     end;
  1876. end;
  1877. { TCustomProvider }
  1878. constructor TCustomProvider.Create(AOwner: TComponent);
  1879. var
  1880.   ProvContainer: IProviderContainer;
  1881. begin
  1882.   inherited Create(AOwner);
  1883.   FExported := True;
  1884. {$IFDEF MSWINDOWS}
  1885.   if AOwner is TRemoteDataModule then
  1886.     TRemoteDataModule(AOwner).RegisterProvider(Self)
  1887.   else if AOwner is TCRemoteDataModule then
  1888.     TCRemoteDataModule(AOwner).RegisterProvider(Self)
  1889.   else if Assigned(AOwner) then
  1890.     if AOwner.GetInterface(IProviderContainer, ProvContainer) then
  1891.       ProvContainer.RegisterProvider(Self);
  1892. {$ENDIF}
  1893. {$IFDEF LINUX}
  1894.   if Assigned(AOwner) then
  1895.     if AOwner.GetInterface(IProviderContainer, ProvContainer) then
  1896.       ProvContainer.RegisterProvider(Self);
  1897. {$ENDIF}
  1898. end;
  1899. destructor TCustomProvider.Destroy;
  1900. var
  1901.   ProvContainer: IProviderContainer;
  1902. begin
  1903. {$IFDEF MSWINDOWS}
  1904.   if Owner is TRemoteDataModule then
  1905.     TRemoteDataModule(Owner).UnRegisterProvider(Self)
  1906.   else if Owner is TCRemoteDataModule then
  1907.     TCRemoteDataModule(Owner).UnRegisterProvider(Self)
  1908.   else if Assigned(Owner) then
  1909.     if Owner.GetInterface(IProviderContainer, ProvContainer) then
  1910.       ProvContainer.UnRegisterProvider(Self);
  1911. {$ENDIF}
  1912. {$IFDEF LINUX}
  1913.   if Assigned(Owner) then
  1914.     if Owner.GetInterface(IProviderContainer, ProvContainer) then
  1915.       ProvContainer.UnRegisterProvider(Self);
  1916. {$ENDIF}
  1917.   inherited Destroy;
  1918. end;
  1919. function TCustomProvider.GetData: OleVariant;
  1920. var
  1921.   Recs: Integer;
  1922.   Options: TGetRecordOptions;
  1923. begin
  1924.   Options := [grMetaData];
  1925.   Result := GetRecords(-1, Recs, Byte(Options));
  1926. end;
  1927. procedure TCustomProvider.DoAfterApplyUpdates(var OwnerData: OleVariant);
  1928. begin
  1929.   if Assigned(FAfterApplyUpdates) then FAfterApplyUpdates(Self, OwnerData);
  1930. end;
  1931. procedure TCustomProvider.DoBeforeApplyUpdates(var OwnerData: OleVariant);
  1932. begin
  1933.   if Assigned(FBeforeApplyUpdates) then FBeforeApplyUpdates(Self, OwnerData);
  1934. end;
  1935. function TCustomProvider.ApplyUpdates(Const Delta: OleVariant; MaxErrors: Integer;