Provider.pas
资源名称:__DCOM.rar [点击查看]
上传用户:etonglee
上传日期:2014-03-01
资源大小:698k
文件大小:136k
源码类别:
Internet/IE编程
开发平台:
Delphi
- { ********************************************************************** }
- { }
- { Kylix and Delphi Cross-Platform Visual Component Library }
- { }
- { Copyright (C) 1997, 2001 Borland Software Corporation }
- { }
- { ********************************************************************** }
- unit Provider;
- {$T-,H+,X+}
- interface
- {$IFDEF MSWINDOWS}
- uses Windows, SysUtils, VarUtils, Variants, Classes, DBClient, DB, DSIntf, ActiveX, Midas, SqlTimSt;
- {$ENDIF}
- {$IFDEF LINUX}
- uses Libc, SysUtils, VarUtils, Variants, Classes, DBClient, DB, DSIntf, Midas, SqlTimSt;
- {$ENDIF}
- var
- InformixLob: Boolean;
- type
- { EDSWriter }
- EDSWriter = class(Exception)
- private
- FErrorCode: Integer;
- public
- constructor Create(ErrMsg: string; Status: Integer);
- property ErrorCode: Integer read FErrorCode;
- end;
- {$EXTERNALSYM EDSWriter}
- (*$HPPEMIT 'namespace Provider' *)
- (*$HPPEMIT '{' *)
- (*$HPPEMIT 'class DELPHICLASS EDSWriter;' *)
- (*$HPPEMIT '#pragma pack(push, 4)' *)
- (*$HPPEMIT 'class PASCALIMPLEMENTATION EDSWriter : public Sysutils::Exception' *)
- (*$HPPEMIT '{' *)
- (*$HPPEMIT ' typedef Sysutils::Exception inherited;' *)
- (*$HPPEMIT '' *)
- (*$HPPEMIT 'private:' *)
- (*$HPPEMIT ' int FErrorCode;' *)
- (*$HPPEMIT '' *)
- (*$HPPEMIT 'public:' *)
- (*$HPPEMIT ' __fastcall EDSWriter(AnsiString ErrMsg, long Status);' *)
- (*$HPPEMIT ' __property int ErrorCode = {read=FErrorCode, nodefault};' *)
- (*$HPPEMIT 'public:' *)
- (*$HPPEMIT ' /* Exception.CreateFmt */ inline __fastcall EDSWriter(const AnsiString Msg, const System::TVarRec * Args, const int Args_Size) : Sysutils::Exception(Msg, Args, Args_Size) { }' *)
- (*$HPPEMIT ' /* Exception.CreateRes */ inline __fastcall EDSWriter(int Ident, Extended Dummy) : Sysutils::Exception(Ident, Dummy) { }' *)
- (*$HPPEMIT ' /* Exception.CreateResFmt */ inline __fastcall EDSWriter(int Ident, const System::TVarRec * Args, const int Args_Size) : Sysutils::Exception(Ident, Args, Args_Size) { }' *)
- (*$HPPEMIT ' /* Exception.CreateHelp */ inline __fastcall EDSWriter(const AnsiString Msg, int AHelpContext) : Sysutils::Exception(Msg, AHelpContext) { }' *)
- (*$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) { }' *)
- (*$HPPEMIT ' /* Exception.CreateResHelp */ inline __fastcall EDSWriter(int Ident, int AHelpContext) : Sysutils::Exception(Ident, AHelpContext) { }' *)
- (*$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) { }' *)
- (*$HPPEMIT '' *)
- (*$HPPEMIT 'public:' *)
- (*$HPPEMIT ' /* TObject.Destroy */ inline __fastcall virtual ~EDSWriter(void) { }' *)
- (*$HPPEMIT '' *)
- (*$HPPEMIT '};' *)
- (*$HPPEMIT '' *)
- (*$HPPEMIT '#pragma pack(pop)' *)
- (*$HPPEMIT '}' *)
- { TCustomPacketWriter }
- TCustomPacketWriter = class(TObject)
- private
- FIDSWriter: IDSWriter;
- FBuffer: array of Byte;
- protected
- procedure AddAttribute(Area: TPcktAttrArea; const ParamName: string;
- const Value: OleVariant; IncludeInDelta: Boolean);
- procedure Check(Status: Integer);
- property DSWriter: IDSWriter read FIDSWriter;
- public
- constructor Create; virtual;
- destructor Destroy; override;
- end;
- { TDataPacketWriter }
- type
- { Forward declarations }
- TGetRecordOption = (grMetaData, grReset, grXML, grXMLUTF8);
- TGetRecordOptions = set of TGetRecordOption;
- TDataRequestEvent = function(Sender: TObject; Input: OleVariant): OleVariant of object;
- TProviderOption = (poFetchBlobsOnDemand, poFetchDetailsOnDemand,
- poIncFieldProps, poCascadeDeletes, poCascadeUpdates, poReadOnly,
- poAllowMultiRecordUpdates, poDisableInserts, poDisableEdits,
- poDisableDeletes, poNoReset, poAutoRefresh, poPropogateChanges,
- poAllowCommandText, poRetainServerOrder );
- TProviderOptions = set of TProviderOption;
- PPutFieldInfo = ^TPutFieldInfo;
- TPutFieldProc = procedure(Info: PPutFieldInfo) of object;
- TPutFieldInfo = record
- FieldNo: Integer;
- Field: TField;
- DataSet: TDataSet;
- Size: Integer;
- IsDetail: Boolean;
- Opened: Boolean;
- PutProc: TPutFieldProc;
- LocalFieldIndex: Integer;
- FieldInfos: Pointer;
- end;
- TInfoArray = array of TPutFieldInfo;
- TGetParamsEvent = procedure(DataSet: TDataSet; Params: TList) of object;
- TDataPacketWriter = class(TCustomPacketWriter)
- private
- FConstraints: Boolean;
- FPutFieldInfo: TInfoArray;
- FOptions: TProviderOptions;
- FPacketOptions: TGetRecordOptions;
- FOnGetParams: TGetParamsEvent;
- procedure FreeInfoRecords(var Info: TInfoArray);
- function GetFieldIdx(const FieldName: string; const Info: TInfoArray): Integer;
- procedure AddExtraFieldProps(Field: TField);
- function InitPutProcs(ADataSet: TDataSet; var GlobalIdx: Integer): TInfoArray;
- procedure RefreshPutProcs(ADataSet: TDataSet; var Info: TInfoArray);
- protected
- procedure AddColumn(const Info: TPutFieldInfo);
- procedure AddConstraints(DataSet: TDataSet);
- procedure AddDataSetAttributes(DataSet: TDataSet);
- procedure AddFieldLinks(const Info: TInfoArray);
- procedure AddIndexDefs(DataSet: TDataSet; const Info: TInfoArray);
- procedure PutADTField(Info: PPutFieldInfo);
- procedure PutArrayField(Info: PPutFieldInfo);
- procedure PutBlobField(Info: PPutFieldInfo);
- procedure PutCalcField(Info: PPutFieldInfo);
- procedure PutDataSetField(Info: PPutFieldInfo);
- procedure PutField(Info: PPutFieldInfo);
- procedure PutStringField(Info: PPutFieldInfo);
- procedure PutWideStringField(Info: PPutFieldInfo);
- procedure PutVarBytesField(Info: PPutFieldInfo);
- procedure Reset;
- procedure WriteMetaData(DataSet: TDataSet; const Info: TInfoArray;
- IsReference: Boolean = False);
- function WriteDataSet(DataSet: TDataSet; var Info: TInfoArray;
- RecsOut: Integer): Integer;
- property OnGetParams: TGetParamsEvent read FOnGetParams write FOnGetParams;
- public
- destructor Destroy; override;
- procedure GetDataPacket(DataSet: TDataSet; var RecsOut: Integer;
- out Data: OleVariant);
- property Constraints: Boolean read FConstraints write FConstraints;
- property PacketOptions: TGetRecordOptions read FPacketOptions write FPacketOptions;
- property Options: TProviderOptions read FOptions write FOptions;
- end;
- { TPacketDataSet }
- TPacketDataSet = class(TCustomClientDataSet)
- private
- FOldRecBuf: PChar;
- FCurRecBuf: PChar;
- FCurValues: PChar;
- FUseCurValues: Boolean;
- FWritingCurValues: Boolean;
- FNewValuesModified: Boolean;
- function GetStreamMetaData: Boolean;
- procedure SetStreamMetaData(Value: Boolean);
- procedure SetWritingCurValues(const Value: Boolean);
- protected
- procedure DataEvent(Event: TDataEvent; Info: Longint); override;
- function GetStateFieldValue(State: TDataSetState; Field: TField): Variant; override;
- procedure InternalClose; override;
- procedure InternalOpen; override;
- procedure InternalInitRecord(Buffer: PChar); override;
- procedure SetFieldData(Field: TField; Buffer: Pointer); override;
- property WritingCurValues: Boolean read FWritingCurValues write SetWritingCurValues;
- public
- constructor Create(AOwner: TComponent); override;
- procedure AssignCurValues(Source: TDataSet); overload;
- procedure AssignCurValues(const CurValues: Variant); overload;
- procedure CreateFromDelta(Source: TPacketDataSet);
- function HasCurValues: Boolean;
- function HasMergeConflicts: Boolean;
- procedure InitAltRecBuffers(CheckModified: Boolean = True);
- function UpdateKind: TUpdateKind;
- property NewValuesModified: Boolean read FNewValuesModified;
- property StreamMetaData: Boolean read GetStreamMetaData write SetStreamMetaData;
- property UseCurValues: Boolean read FUseCurValues write FUseCurValues;
- end;
- { TCustomProvider }
- TCustomProvider = class(TComponent)
- private
- FExported: Boolean;
- FOnDataRequest: TDataRequestEvent;
- FBeforeApplyUpdates: TRemoteEvent;
- FAfterApplyUpdates: TRemoteEvent;
- FBeforeGetRecords: TRemoteEvent;
- FAfterGetRecords: TRemoteEvent;
- FBeforeRowRequest: TRemoteEvent;
- FAfterRowRequest: TRemoteEvent;
- FBeforeExecute: TRemoteEvent;
- FAfterExecute: TRemoteEvent;
- FBeforeGetParams: TRemoteEvent;
- FAfterGetParams: TRemoteEvent;
- function GetData: OleVariant;
- protected
- function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer): OleVariant; virtual; abstract;
- function InternalGetRecords(Count: Integer; out RecsOut: Integer;
- Options: TGetRecordOptions; const CommandText: WideString;
- var Params: OleVariant): OleVariant; virtual;
- function InternalRowRequest(const Row: OleVariant; RequestType: TFetchOptions): OleVariant; virtual;
- procedure InternalExecute(const CommandText: WideString; var Params: OleVariant); virtual;
- function InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant; virtual;
- { Event overrides }
- procedure DoAfterApplyUpdates(var OwnerData: OleVariant); virtual;
- procedure DoBeforeApplyUpdates(var OwnerData: OleVariant); virtual;
- procedure DoAfterExecute(var OwnerData: OleVariant); virtual;
- procedure DoBeforeExecute(const CommandText: WideString; var Params,
- OwnerData: OleVariant); virtual;
- procedure DoAfterGetParams(var OwnerData: OleVariant); virtual;
- procedure DoBeforeGetParams(var OwnerData: OleVariant); virtual;
- procedure DoAfterGetRecords(var OwnerData: OleVariant); virtual;
- procedure DoBeforeGetRecords(Count: Integer; Options: Integer;
- const CommandText: WideString; var Params, OwnerData: OleVariant); virtual;
- procedure DoAfterRowRequest(var OwnerData: OleVariant); virtual;
- procedure DoBeforeRowRequest(var OwnerData: OleVariant); virtual;
- { Events }
- property OnDataRequest: TDataRequestEvent read FOnDataRequest write FOnDataRequest;
- property BeforeApplyUpdates: TRemoteEvent read FBeforeApplyUpdates write FBeforeApplyUpdates;
- property AfterApplyUpdates: TRemoteEvent read FAfterApplyUpdates write FAfterApplyUpdates;
- property BeforeGetRecords: TRemoteEvent read FBeforeGetRecords write FBeforeGetRecords;
- property AfterGetRecords: TRemoteEvent read FAfterGetRecords write FAfterGetRecords;
- property BeforeRowRequest: TRemoteEvent read FBeforeRowRequest write FBeforeRowRequest;
- property AfterRowRequest: TRemoteEvent read FAfterRowRequest write FAfterRowRequest;
- property BeforeExecute: TRemoteEvent read FBeforeExecute write FBeforeExecute;
- property AfterExecute: TRemoteEvent read FAfterExecute write FAfterExecute;
- property BeforeGetParams: TRemoteEvent read FBeforeGetParams write FBeforeGetParams;
- property AfterGetParams: TRemoteEvent read FAfterGetParams write FAfterGetParams;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer): OleVariant; overload;
- function ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant; overload;
- function GetRecords(Count: Integer; out RecsOut: Integer;
- Options: Integer): OleVariant; overload;
- function GetRecords(Count: Integer; out RecsOut: Integer; Options: Integer;
- const CommandText: WideString; var Params,
- OwnerData: OleVariant): OleVariant; overload;
- function RowRequest(const Row: OleVariant; RequestType: Integer;
- var OwnerData: OleVariant): OleVariant;
- procedure Execute(const CommandText: WideString; var Params,
- OwnerData: OleVariant);
- function GetParams(var OwnerData: OleVariant): OleVariant;
- function DataRequest(Input: OleVariant): OleVariant; virtual;
- property Data: OleVariant read GetData;
- property Exported: Boolean read FExported write FExported default True;
- end;
- const
- ResetOption: Integer = 1 shl ord(grReset);
- MetaDataOption: Integer = 1 shl ord(grMetaData);
- XMLOption: Integer = 1 shl ord(grXML);
- XMLUTF8Option: Integer = 1 shl ord(grXMLUTF8);
- { TBaseProvider }
- type
- TUpdateTree = class;
- TCustomResolver = class;
- TResolverResponse = (rrSkip, rrAbort, rrMerge, rrApply, rrIgnore);
- TProviderDataEvent = procedure(Sender: TObject; DataSet: TCustomClientDataSet) of object;
- TBeforeUpdateRecordEvent = procedure(Sender: TObject; SourceDS: TDataSet;
- DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean) of object;
- TAfterUpdateRecordEvent = procedure(Sender: TObject; SourceDS: TDataSet;
- DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind) of object;
- TResolverErrorEvent = procedure(Sender: TObject; DataSet: TCustomClientDataSet;
- E: EUpdateError; UpdateKind: TUpdateKind; var Response: TResolverResponse) of object;
- TBaseProvider = class(TCustomProvider)
- private
- FDataDS: TPacketDataSet;
- FUpdateMode: TUpdateMode;
- FResolver: TCustomResolver;
- FOnGetData: TProviderDataEvent;
- FOnUpdateData: TProviderDataEvent;
- FOnUpdateError: TResolverErrorEvent;
- FBeforeUpdateRecord: TBeforeUpdateRecordEvent;
- FAfterUpdateRecord: TAfterUpdateRecordEvent;
- FProviderOptions: TProviderOptions;
- protected
- procedure CheckResolver;
- function CreateResolver: TCustomResolver; virtual;
- procedure FreeResolver;
- procedure CreateDataPacket(PacketOpts: TGetRecordOptions;
- ProvOpts: TProviderOptions; var RecsOut: Integer; var Data: OleVariant); virtual;
- procedure DoOnGetData(var Data: OleVariant);
- procedure DoOnUpdateData(Delta: TPacketDataSet);
- procedure LocateRecord(Source, Delta: TDataSet); virtual;
- procedure UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean); virtual;
- procedure FetchDetails(Source, Delta: TDataSet); virtual;
- function InternalRowRequest(const Row: OleVariant;
- RequestType: TFetchOptions): OleVariant; override;
- function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer): OleVariant; override;
- function InternalGetRecords(Count: Integer; out RecsOut: Integer;
- Options: TGetRecordOptions; const CommandText: WideString;
- var Params: OleVariant): OleVariant; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- property Resolver: TCustomResolver read FResolver;
- property Options: TProviderOptions read FProviderOptions
- write FProviderOptions default [];
- property UpdateMode: TUpdateMode read FUpdateMode write FUpdateMode default upWhereAll;
- property OnDataRequest;
- property OnGetData: TProviderDataEvent read FOnGetData write FOnGetData;
- property OnUpdateData: TProviderDataEvent read FOnUpdateData write FOnUpdateData;
- property OnUpdateError: TResolverErrorEvent read FOnUpdateError write FOnUpdateError;
- property BeforeUpdateRecord: TBeforeUpdateRecordEvent read FBeforeUpdateRecord
- write FBeforeUpdateRecord;
- property AfterUpdateRecord: TAfterUpdateRecordEvent read FAfterUpdateRecord
- write FAfterUpdateRecord;
- end;
- { TDataSetProvider }
- TGetTableNameEvent = procedure(Sender: TObject; DataSet: TDataSet; var TableName: string) of object;
- TGetDSProps = procedure(Sender: TObject; DataSet: TDataSet;
- out Properties: OleVariant) of object;
- TDataSetProvider = class(TBaseProvider)
- private
- FDataSet: TDataSet;
- FDataSetOpened: Boolean;
- FDSWriter: TDataPacketWriter;
- FGetDSProps: TGetDSProps;
- FParams: TParams;
- FResolveToDataSet: Boolean;
- FRecordsSent: Integer;
- FConstraints: Boolean;
- FTransactionStarted: Boolean;
- FGetTableName: TGetTableNameEvent;
- function FindRecord(Source, Delta: TDataSet; UpdateMode: TUpdateMode): Boolean;
- procedure Reset;
- procedure SetCommandText(const CommandText: string);
- procedure SetDataSet(ADataSet: TDataSet);
- procedure SetResolveToDataSet(Value: Boolean);
- protected
- { SQL Resolver support methods }
- procedure DoGetTableName(DataSet: TDataSet; var TableName: string); virtual;
- protected
- { Event overrides }
- procedure DoBeforeGetRecords(Count: Integer; Options: Integer;
- const CommandText: WideString; var Params, OwnerData: OleVariant); override;
- procedure DoBeforeExecute(const CommandText: WideString; var Params,
- OwnerData: OleVariant); override;
- protected
- procedure CheckDataSet;
- procedure SetParams(Values: OleVariant);
- procedure DoGetProviderAttributes(DataSet: TDataSet; List: TList); virtual;
- function CreateResolver: TCustomResolver; override;
- procedure CreateDataPacket(PacketOpts: TGetRecordOptions;
- ProvOpts: TProviderOptions; var RecsOut: Integer; var Data: OleVariant); override;
- function GetDataSetFromDelta(ATree: TUpdateTree; Source, Delta: TDataSet; Mode: TUpdateMode): TDataSet;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure LocateRecord(Source, Delta: TDataSet); override;
- procedure UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean); override;
- procedure FetchDetails(Source, Delta: TDataSet); override;
- function InternalRowRequest(const Row: OleVariant; Options: TFetchOptions): OleVariant; override;
- function InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant; override;
- procedure InternalExecute(const CommandText: WideString; var Params: OleVariant); override;
- function InternalGetRecords(Count: Integer; out RecsOut: Integer;
- Options: TGetRecordOptions; const CommandText: WideString;
- var Params: OleVariant): OleVariant; override;
- function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer): OleVariant; override;
- property Params: TParams read FParams;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- published
- property DataSet: TDataSet read FDataSet write SetDataSet;
- property Constraints: Boolean read FConstraints write FConstraints default True;
- property ResolveToDataSet: Boolean read FResolveToDataSet write SetResolveToDataSet default False;
- property Exported;
- property Options;
- property UpdateMode;
- property OnDataRequest;
- property OnGetData;
- property OnUpdateData;
- property OnUpdateError;
- property AfterUpdateRecord;
- property BeforeUpdateRecord;
- property BeforeApplyUpdates;
- property AfterApplyUpdates;
- property BeforeGetRecords;
- property AfterGetRecords;
- property BeforeRowRequest;
- property AfterRowRequest;
- property BeforeExecute;
- property AfterExecute;
- property BeforeGetParams;
- property AfterGetParams;
- property OnGetTableName: TGetTableNameEvent read FGetTableName write FGetTableName;
- property OnGetDataSetProperties: TGetDSProps read FGetDSProps write FGetDSProps;
- end;
- { TProvider - deprecated }
- TProvider = class(TDataSetProvider)
- end;
- { TUpdateTree }
- TUpdateTree = class(TObject)
- private
- FDeltaDS: TPacketDataSet;
- FErrorDS: TPacketDataSet;
- FOpened: Boolean;
- FSourceDS: TDataSet;
- FParent: TUpdateTree;
- FDetails: TList;
- FData: Pointer;
- FResolver: TCustomResolver;
- FName: string;
- function GetDetailCount: Integer;
- function GetDetail(Index: Integer): TUpdateTree;
- function GetErrorDS: TPacketDataSet;
- function GetHasErrors: Boolean;
- function GetIsNested: Boolean;
- function GetTree(const AName: string): TUpdateTree;
- protected
- procedure Clear;
- function DoUpdates: Boolean;
- procedure RefreshData(Options: TFetchOptions);
- procedure InitErrorPacket(E: EUpdateError; Response: TResolverResponse);
- procedure InitData(ASource: TDataSet);
- procedure InitDelta(const ADelta: OleVariant); overload;
- procedure InitDelta(ADelta: TPacketDataSet); overload;
- property Data: Pointer read FData write FData;
- property Delta: TPacketDataSet read FDeltaDS;
- property DetailCount: Integer read GetDetailCount;
- property Details[Index: Integer]: TUpdateTree read GetDetail;
- property ErrorDS: TPacketDataSet read GetErrorDS;
- property HasErrors: Boolean read GetHasErrors;
- property Name: string read FName write FName;
- property Parent: TUpdateTree read FParent;
- property Source: TDataSet read FSourceDS;
- property IsNested: Boolean read GetIsNested;
- public
- constructor Create(AParent: TUpdateTree; AResolver: TCustomResolver);
- destructor Destroy; override;
- end;
- { TCustomResolver }
- TCustomResolver = class(TComponent)
- private
- FProvider: TBaseProvider;
- FPrevResponse: TResolverResponse;
- FErrorCount: Integer;
- FMaxErrors: Integer;
- FUpdateTree: TUpdateTree;
- protected
- property Provider: TBaseProvider read FProvider;
- function HandleUpdateError(Tree: TUpdateTree; E: EUpdateError;
- var MaxErrors, ErrorCount: Integer): Boolean;
- procedure LogUpdateRecord(Tree: TUpdateTree);
- procedure LogUpdateError(Tree: TUpdateTree; E: EUpdateError;
- Response: TResolverResponse);
- procedure InitKeyFields(Tree: TUpdateTree; ADelta: TPacketDataSet);
- procedure InternalBeforeResolve(Tree: TUpdateTree); virtual;
- function InternalUpdateRecord(Tree: TUpdateTree): Boolean;
- procedure BeginUpdate; virtual;
- procedure EndUpdate; virtual;
- procedure InitTreeData(Tree: TUpdateTree); virtual;
- procedure FreeTreeData(Tree: TUpdateTree); virtual;
- procedure InitializeConflictBuffer(Tree: TUpdateTree); virtual; abstract;
- procedure DoUpdate(Tree: TUpdateTree); virtual; abstract;
- procedure DoDelete(Tree: TUpdateTree); virtual; abstract;
- procedure DoInsert(Tree: TUpdateTree); virtual; abstract;
- function RowRequest(Row: OleVariant; Options: TFetchOptions): OleVariant; virtual;
- function ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer): OleVariant; virtual;
- public
- constructor Create(AProvider: TBaseProvider); reintroduce;
- destructor Destroy; override;
- end;
- { TDataSetResolver }
- TDataSetResolver = class(TCustomResolver)
- private
- FBookmark: TBookmarkStr;
- FOpened: Boolean;
- function GetProvider: TDataSetProvider;
- procedure PutRecord(Tree: TUpdateTree);
- protected
- property Provider: TDataSetProvider read GetProvider;
- procedure BeginUpdate; override;
- procedure DoUpdate(Tree: TUpdateTree); override;
- procedure DoDelete(Tree: TUpdateTree); override;
- procedure DoInsert(Tree: TUpdateTree); override;
- procedure EndUpdate; override;
- procedure InternalBeforeResolve(Tree: TUpdateTree); override;
- procedure InitializeConflictBuffer(Tree: TUpdateTree); override;
- public
- constructor Create(AProvider: TDataSetProvider); reintroduce;
- end;
- { TSQLResolver }
- TSQLResolver = class(TCustomResolver)
- private
- FSQL: TStringList;
- FParams: TParams;
- function GetProvider: TDataSetProvider;
- procedure GenWhereSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
- GenUpdateMode: TUpdateMode; Alias: string);
- procedure GenInsertSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams);
- procedure GenDeleteSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
- Alias: string);
- procedure GenUpdateSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
- Alias: string);
- procedure GenSelectSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
- Alias: string; Mode: TUpdateMode = upWhereKeyOnly);
- function UseFieldInUpdate(Field: TField): Boolean;
- function UseFieldInWhere(Field: TField; Mode: TUpdateMode): Boolean;
- procedure InternalDoUpdate(Tree: TUpdateTree; UpdateKind: TUpdateKind);
- protected
- property Provider: TDataSetProvider read GetProvider;
- procedure InitializeConflictBuffer(Tree: TUpdateTree); override;
- procedure DoExecSQL(SQL: TStringList; Params: TParams); virtual;
- procedure DoGetValues(SQL: TStringList; Params: TParams;
- DataSet: TDataSet); virtual;
- procedure InitTreeData(Tree: TUpdateTree); override;
- procedure FreeTreeData(Tree: TUpdateTree); override;
- procedure DoUpdate(Tree: TUpdateTree); override;
- procedure DoDelete(Tree: TUpdateTree); override;
- procedure DoInsert(Tree: TUpdateTree); override;
- public
- constructor Create(AProvider: TDataSetProvider); reintroduce;
- destructor Destroy; override;
- end;
- { TLocalAppServer }
- TLocalAppServer = class(TInterfacedObject, IAppServer{$IFDEF MSWINDOWS}, ISupportErrorInfo{$ENDIF})
- private
- FProvider: TCustomProvider;
- FProviderCreated: Boolean;
- protected
- { IDispatch }
- function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
- function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
- function GetIDsOfNames(const IID: TGUID; Names: Pointer;
- NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
- function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
- Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
- { IAppServer }
- function AS_ApplyUpdates(const ProviderName: WideString; Delta: OleVariant; MaxErrors: Integer;
- out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant; safecall;
- function AS_GetRecords(const ProviderName: WideString; Count: Integer; out RecsOut: Integer;
- Options: Integer; const CommandText: WideString;
- var Params: OleVariant; var OwnerData: OleVariant): OleVariant; safecall;
- function AS_DataRequest(const ProviderName: WideString; Data: OleVariant): OleVariant; safecall;
- function AS_GetProviderNames: OleVariant; safecall;
- function AS_GetParams(const ProviderName: WideString; var OwnerData: OleVariant): OleVariant; safecall;
- function AS_RowRequest(const ProviderName: WideString; Row: OleVariant; RequestType: Integer;
- var OwnerData: OleVariant): OleVariant; safecall;
- procedure AS_Execute(const ProviderName: WideString; const CommandText: WideString;
- var Params, OwnerData: OleVariant); safecall;
- { ISupportErrorInfo }
- function InterfaceSupportsErrorInfo(const iid: TGUID): HResult; stdcall;
- public
- constructor Create(AProvider: TCustomProvider); overload;
- constructor Create(ADataset: TDataset); overload;
- destructor Destroy; override;
- function SafeCallException(ExceptObject: TObject;
- ExceptAddr: Pointer): HResult; override;
- end;
- IProviderContainer = interface
- ['{EEE9FFD4-752F-11D4-80DD-00C04F6BB88C}']
- procedure RegisterProvider(Prov: TCustomProvider);
- procedure UnRegisterProvider(Prov: TCustomProvider);
- end;
- { Utility functions }
- function GetObjectProperty(Instance: TPersistent; const PropName: string): TObject;
- function GetStringProperty(Instance: TPersistent; const PropName: string): string;
- function VarArrayFromStrings(Strings: TStrings): Variant;
- implementation
- {$IFDEF MSWINDOWS}
- uses MidConst, DBConsts, DBCommon, TypInfo, DataBkr, ComObj, FMTBcd,mtx,StrUtils;
- {$ENDIF}
- {$IFDEF LINUX}
- uses MidConst, DBConsts, DBCommon, TypInfo, FMTBcd, Types;
- {$ENDIF}
- const
- DEFBUFSIZE = 8192; { Default size for field data buffer }
- DefAlias = 'A';
- NestAlias = 'B';
- tagSERVERCALC = 1;
- ADOID_MSSQLSERVER ='SQLOLEDB.1'; //ADO MS SQLSERVER 标志
- ADOID_MSACCESSS ='Microsoft.Jet.OLEDB.4.0'; //ADO MS ACCESS 标志
- ADOID_ORACLE ='MSDAORA.1'; //ADO ORCALE 标志
- PacketTypeMap: array [TFieldType] of Integer =
- (dsfldUNKNOWN, dsfldZSTRING, dsfldINT, dsfldINT, dsfldINT, dsfldBOOL,
- dsfldFLOATIEEE, dsfldFLOATIEEE, dsfldBCD, dsfldDATE, dsfldTIME,
- dsfldTIMESTAMP, dsfldBYTES, dsfldBYTES, dsfldINT, dsfldBYTES, dsfldBYTES,
- dsfldBYTES, dsfldBYTES, dsfldBYTES, dsfldBYTES, dsfldBYTES, dsfldUNKNOWN,
- dsfldZSTRING, dsfldUNICODE, dsfldINT, dsfldADT, dsfldARRAY, dsfldEMBEDDEDTBL,
- dsfldEMBEDDEDTBL, dsfldBYTES, dsfldBYTES, dsfldUNKNOWN, dsfldUNKNOWN,
- dsfldUNKNOWN, dsfldZSTRING, dsfldDATETIME, dsFLDFMTBCD);
- ExtraFieldProps: array [0..10] of string = ('Alignment', 'DisplayLabel',
- 'DisplayWidth', 'Visible', 'EditMask', 'DisplayFormat', 'EditFormat',
- 'MinValue', 'MaxValue', 'currency', 'DisplayValues');
- { Utility functions }
- function GetObjectProperty(Instance: TPersistent; const PropName: string): TObject;
- var
- PropInfo: PPropInfo;
- begin
- Result := nil;
- PropInfo := TypInfo.GetPropInfo(Instance.ClassInfo, PropName);
- if (PropInfo <> nil) and (PropInfo^.PropType^.Kind = tkClass) then
- Result := TObject(GetOrdProp(Instance, PropInfo));
- end;
- function GetStringProperty(Instance: TPersistent; const PropName: string): string;
- var
- PropInfo: PPropInfo;
- begin
- Result := '';
- PropInfo := TypInfo.GetPropInfo(Instance.ClassInfo, PropName);
- if (PropInfo <> nil) and (PropInfo^.PropType^.Kind in [tkString, tkLString, tkWString]) then
- Result := GetStrProp(Instance, PropInfo);
- end;
- function VarArrayFromStrings(Strings: TStrings): Variant;
- var
- I: Integer;
- begin
- Result := Null;
- if Strings.Count > 0 then
- begin
- Result := VarArrayCreate([0, Strings.Count - 1], varOleStr);
- for I := 0 to Strings.Count - 1 do Result[I] := WideString(Strings[I]);
- end;
- end;
- { EDSWriter }
- constructor EDSWriter.Create(ErrMsg: string; Status: Integer);
- begin
- FErrorCode := Status;
- inherited Create(ErrMsg);
- end;
- { TCustomPacketWriter }
- constructor TCustomPacketWriter.Create;
- begin
- SetLength(FBuffer, DEFBUFSIZE);
- end;
- destructor TCustomPacketWriter.Destroy;
- begin
- FIDSWriter := nil;
- FBuffer := nil;
- inherited Destroy;
- end;
- procedure TCustomPacketWriter.Check(Status: Integer);
- var
- ErrMsg: array[0..2048] of Char;
- begin
- if Status <> 0 then
- begin
- FIDSWriter.GetErrorString(Status, ErrMsg);
- raise EDSWriter.Create(ErrMsg, Status);
- end;
- end;
- procedure TCustomPacketWriter.AddAttribute(Area: TPcktAttrArea; const ParamName: string;
- const Value: OleVariant; IncludeInDelta: Boolean);
- const
- ParamTypeMap: array[varSmallInt..varByte] of Integer =
- ( dsfldINT, dsfldINT, dsfldFLOATIEEE, dsfldFLOATIEEE, dsfldBCD,
- dsfldFLOATIEEE, dsfldZSTRING, 0, 0, dsfldBOOL, 0, 0, 0, 0, 0, dsfldINT);
- ParamTypeSize: array[varSmallInt..varByte] of Integer =
- ( SizeOf(SmallInt), SizeOf(Integer), SizeOf(Single), SizeOf(Double),
- SizeOf(Currency), SizeOf(TDateTime), 0, 0, 0, SizeOf(WordBool), 0, 0, 0,
- 0, 0, SizeOf(Byte));
- var
- ParamType, ParamLen, ElemSize, ElemCount: DWord;
- P: Pointer;
- DateRec: TDateTimeRec;
- TimeStamp: TTimeStamp;
- begin
- if ((VarType(Value) and varTypeMask) in [varSmallInt, varInteger, varSingle,
- varDouble, varCurrency, varDate, varOleStr, varBoolean, varByte, varNull]) then
- begin
- ParamType := ParamTypeMap[VarType(Value) and varTypeMask];
- ParamLen := ParamTypeSize[VarType(Value) and varTypeMask];
- if ParamType = dsfldZSTRING then
- begin
- ParamType := (dsfldZSTRING shl dsSizeBitsLen) or dsVaryingFldType or SizeOf(Word);
- ParamLen := Length(Value) + 1;
- PWord(FBuffer)^ := ParamLen;
- Inc(ParamLen, SizeOf(Word));
- StrPLCopy(@FBuffer[SizeOf(Word)], Value, Length(FBuffer) - SizeOf(Word) - 1);
- end else
- if ParamType = dsfldTIMESTAMP then
- begin
- TimeStamp := DateTimeToTimeStamp(Value);
- DateRec.DateTime := TimeStampToMSecs(TimeStamp);
- Move(DateRec, PChar(FBuffer)^, ParamLen);
- ParamType := ParamType shl dsSizeBitsLen or SizeOf(TDateTimeRec);
- end else
- if ParamType = dsfldDATETIME then
- begin
- P := @TVarData(Value).VPointer;
- Move(P^, PByte(FBuffer)^, ParamLen);
- ParamType := (ParamType shl dsSizeBitsLen) or SizeOf(TSQLTimeStamp);
- end else
- if VarIsArray(Value) then
- begin
- if ParamLen = 0 then
- raise EDSWriter.Create(SInvalidOptParamType, 0);
- ElemCount := VarArrayHighBound(Value, 1) + 1;
- ElemSize := ParamLen;
- if ParamType in [dsfldINT, dsfldUINT] then
- ParamType := (dsfldUINT shl dsSizeBitsLen) or dsArrayFldType or ElemSize
- else
- ParamType := (dsfldBYTES shl dsSizeBitsLen) or dsArrayFldType or ElemSize;
- PInteger(FBuffer)^ := ElemCount;
- ParamLen := ElemCount * ElemSize;
- P := VarArrayLock(Value);
- try
- Move(P^, FBuffer[SizeOf(Integer)], ParamLen);
- Inc(ParamLen, SizeOf(Integer));
- finally
- VarArrayUnlock(Value);
- end;
- end else
- begin
- if (VarType(Value) and varByRef) = varByRef then
- P := TVarData(Value).VPointer else
- P := @TVarData(Value).VPointer;
- Move(P^, PByte(FBuffer)^, ParamLen);
- ParamType := ParamType shl dsSizeBitsLen or ParamLen;
- end;
- if IncludeInDelta then
- ParamType := ParamType or dsIncInDelta;
- Check(FIDSWriter.AddAttribute(Area, PChar(ParamName), ParamType, ParamLen, PByte(FBuffer)));
- end else
- raise EDSWriter.Create(SInvalidOptParamType, 0);
- end;
- { TDataPacketWriter }
- destructor TDataPacketWriter.Destroy;
- begin
- FreeInfoRecords(FPutFieldInfo);
- FPutFieldInfo := nil;
- inherited Destroy;
- end;
- procedure TDataPacketWriter.FreeInfoRecords(var Info: TInfoArray);
- var
- i: Integer;
- begin
- for i := 0 to High(Info) do
- if Info[i].FieldInfos <> nil then
- begin
- FreeInfoRecords(TInfoArray(Info[i].FieldInfos));
- TInfoArray(Info[i].FieldInfos) := nil;
- end;
- end;
- { Writing data }
- procedure TDataPacketWriter.PutBlobField(Info: PPutFieldInfo);
- begin
- if not (poFetchBlobsOnDemand in Options) then
- begin
- Info.Size := Info.DataSet.GetBlobFieldData(Info.FieldNo, TBlobByteData(FBuffer));
- if Info.Size <> 0 then
- begin
- if Length(FBuffer) <= Info.Size then
- SetLength(FBuffer, Info.Size + 1);
- FBuffer[Info.Size] := 0;
- if TBlobField(Info.Field).Transliterate then
- Info.Size := Info.DataSet.Translate(PChar(FBuffer), PChar(FBuffer), False);
- FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer))
- end else
- FIDSWriter.PutField(fldIsNull, 0, nil);
- end else
- FIDSWriter.PutField(fldIsChanged, dsDELAYEDBIT or 1, @Info.Size);
- end;
- procedure TDataPacketWriter.PutCalcField(Info: PPutFieldInfo);
- begin
- if Info.DataSet.GetFieldData(Info.Field, FBuffer) then
- begin
- if (Info.Field is TStringField) then
- if TStringField(Info.Field).Transliterate then
- Info.Size := Info.DataSet.Translate(PChar(FBuffer), PChar(FBuffer), False) else
- Info.Size := StrLen(PChar(FBuffer));
- FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer));
- end else
- FIDSWriter.PutField(fldIsNull, 0, nil);
- end;
- procedure TDataPacketWriter.PutField(Info: PPutFieldInfo);
- begin
- if Info.DataSet.GetFieldData(Info.FieldNo, FBuffer) then
- FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer)) else
- FIDSWriter.PutField(fldIsNull, 0, nil);
- end;
- procedure TDataPacketWriter.PutStringField(Info: PPutFieldInfo);
- begin
- if Length(FBuffer) <= Info.Size then
- SetLength(FBuffer, Info.Size + 1);
- if Info.DataSet.GetFieldData(Info.FieldNo, FBuffer) then
- begin
- if TStringField(Info.Field).Transliterate then
- Info.Size := Info.DataSet.Translate(PChar(FBuffer), PChar(FBuffer), False) else
- Info.Size := StrLen(PChar(FBuffer));
- FIDSWriter.PutField(fldIsChanged, Info.Size, PByte(FBuffer));
- end else
- FIDSWriter.PutField(fldIsNull, 0, nil);
- end;
- procedure TDataPacketWriter.PutWideStringField(Info: PPutFieldInfo);
- var
- W: WideString;
- begin
- if Info.DataSet.GetFieldData(Info.field, @W, False) then
- begin
- Info.Size := Length(W);
- FIDSWriter.PutField(fldIsChanged, Info.Size * 2, PByte(W));
- end else
- FIDSWriter.PutField(fldIsNull, 0, nil);
- end;
- procedure TDataPacketWriter.PutVarBytesField(Info: PPutFieldInfo);
- begin
- if Info.DataSet.GetFieldData(Info.FieldNo, FBuffer) then
- FIDSWriter.PutField(fldIsChanged, PWord(FBuffer)^, @FBuffer[SizeOf(Word)]) else
- FIDSWriter.PutField(fldIsNull, 0, nil);
- end;
- procedure TDataPacketWriter.PutADTField(Info: PPutFieldInfo);
- var
- i: Integer;
- begin
- if Info.Field.IsNull then
- FIDSWriter.PutField(fldIsNull, 0, nil) else
- FIDSWriter.PutField(fldIsChanged, 0, nil);
- for i := 0 to High(TInfoArray(Info.FieldInfos)) do
- with TInfoArray(Info^.FieldInfos)[i] do
- PutProc(@TInfoArray(Info.FieldInfos)[i]);
- end;
- procedure TDataPacketWriter.PutArrayField(Info: PPutFieldInfo);
- procedure RefreshInfos(Src: TField; Dest: PPutFieldInfo);
- var
- i: Integer;
- begin
- with Dest^ do
- begin
- Field := Src;
- FieldNo := Src.FieldNo;
- if (FieldInfos <> nil) then { Must be an ADT }
- begin
- if not (Src is TADTField) then
- raise EDSWriter.CreateFmt(SArrayElementError,[Src.ClassName]);
- with (Src as TADTField) do
- for i := 0 to FieldCount - 1 do
- RefreshInfos(Fields[i], @TInfoArray(FieldInfos)[i]);
- end;
- end;
- end;
- var
- i: Integer;
- begin
- if Info.Field.IsNull then
- FIDSWriter.PutField(fldIsNull, 0, nil) else
- FIDSWriter.PutField(fldIsChanged, 0, nil);
- for i := 0 to TArrayField(Info.Field).FieldCount - 1 do
- with TInfoArray(Info^.FieldInfos)[0] do
- begin
- RefreshInfos(TArrayField(Info.Field).Fields[i], @TInfoArray(Info.FieldInfos)[0]);
- PutProc(@TInfoArray(Info.FieldInfos)[0]);
- end;
- end;
- procedure TDataPacketWriter.PutDataSetField(Info: PPutFieldInfo);
- var
- Count: DWord;
- DataSet: TDataSet;
- begin
- if Info.Field <> nil then
- begin
- if Info.Field.IsNull then
- begin
- FIDSWriter.PutField(fldIsNull, 0, nil);
- Exit;
- end;
- DataSet := TDataSetField(Info.Field).NestedDataSet;
- end else
- DataSet := Info.DataSet;
- if (poFetchDetailsOnDemand in Options) then
- Count := dsDELAYEDBIT else
- Count := DWord(-1);
- FIDSWriter.PutField(fldIsChanged, SizeOf(Count), @Count);
- if (not (poFetchDetailsOnDemand in Options)) and (Count = DWord(-1)) then
- begin
- DataSet.UpdateCursorPos;
- DataSet.First;
- DataSet.BlockReadSize := MaxInt;
- try
- WriteDataSet(DataSet, TInfoArray(Info.FieldInfos), -1);
- FIDSWriter.EndOfNestedRows;
- finally
- DataSet.BlockReadSize := 0;
- end;
- end;
- end;
- function TDataPacketWriter.WriteDataSet(DataSet: TDataSet; var Info: TInfoArray;
- RecsOut: Integer): Integer;
- const
- B: Byte = 0;
- var
- i: Integer;
- ChildOpened: Boolean;
- function OpenCloseDetails(Info: TInfoArray; ActiveState: Boolean): Boolean;
- var
- I: Integer;
- begin
- Result := False;
- for I := 0 to High(Info) do
- begin
- if Info[I].IsDetail and (Info[I].DataSet.Active <> ActiveState) then
- begin
- Info[I].DataSet.Active := ActiveState;
- Info[I].Opened := ActiveState;
- Result := True;
- end;
- end;
- end;
- begin
- Result := 0;
- if RecsOut = AllRecords then
- RecsOut := High(Integer);
- if DataSet.DefaultFields then
- RefreshPutProcs(DataSet, Info);
- ChildOpened := OpenCloseDetails(Info, True);
- while (not DataSet.EOF) and (Result < RecsOut) do
- begin
- FIDSWriter.PutField(fldIsChanged, 1, @B);
- for i := 0 to High(Info) do
- Info[i].PutProc(@Info[i]);
- Inc(Result);
- if Result < RecsOut then
- DataSet.Next;
- end;
- if ChildOpened then
- OpenCloseDetails(Info, False);
- end;
- { Writing meta data }
- procedure TDataPacketWriter.AddDataSetAttributes(DataSet: TDataSet);
- var
- i: Integer;
- List: TList;
- begin
- if Assigned(FOnGetParams) then
- begin
- List := TList.Create;
- try
- FOnGetParams(DataSet, List);
- for i := 0 to List.Count - 1 do
- with PPacketAttribute(List[i])^ do
- begin
- AddAttribute(pcktAttrArea, Name, Value, IncludeInDelta);
- Dispose(PPacketAttribute(List[i]));
- end;
- finally
- List.Free;
- end;
- end;
- end;
- function TDataPacketWriter.GetFieldIdx(const FieldName: string; const Info: TInfoArray): Integer;
- var
- i: Integer;
- begin
- Result := -1;
- for i := 0 to High(Info) do
- if (Info[i].Field <> nil) and (Info[i].Field.FieldName = FieldName) then
- begin
- Result := Info[i].LocalFieldIndex;
- break;
- end;
- end;
- type
- TPropWriter = class(TWriter);
- procedure TDataPacketWriter.AddExtraFieldProps(Field: TField);
- procedure WriteProp(Instance: TPersistent; const PropName: string;
- Writer: TPropWriter);
- var
- PropInfo: PPropInfo;
- begin
- PropInfo := TypInfo.GetPropInfo(Instance.ClassInfo, PropName);
- if (PropInfo <> nil) and IsStoredProp(Instance, PropInfo) then
- Writer.WriteProperty(Instance, PropInfo);
- end;
- var
- Writer: TPropWriter;
- Stream: TMemoryStream;
- i: Integer;
- Attr: Cardinal;
- begin
- Stream := TMemoryStream.Create;
- try
- Writer := TPropWriter.Create(Stream, 1024);
- try
- Writer.WriteListBegin;
- for i := 0 to High(ExtraFieldProps) do
- WriteProp(Field, ExtraFieldProps[i], Writer);
- Writer.WriteListEnd;
- Writer.FlushBuffer;
- if Stream.Size > 2 then
- begin
- Attr := (dsfldBYTES shl dsSizeBitsLen) or dsArrayFldType or SizeOf(Byte) or dsIncInDelta;
- PInteger(FBuffer)^ := Stream.Size;
- Move(Stream.Memory^, FBuffer[SizeOf(Integer)], Stream.Size);
- Check(FIDSWriter.AddAttribute(fldAttrArea, szFIELDPROPS, Attr,
- Stream.Size + SizeOf(Integer), FBuffer));
- end;
- finally
- Writer.Free;
- end;
- finally
- Stream.Free;
- end;
- end;
- procedure TDataPacketWriter.AddColumn(const Info: TPutFieldInfo);
- procedure AddFieldDesc(const FldName: string; FldType, Attributes: Integer);
- var
- FldDesc: TDSDataPacketFldDesc;
- begin
- if Length(FldName) >= SizeOf(FldDesc.szFieldName) then
- raise EDSWriter.CreateFmt(SFieldNameTooLong,[SizeOf(FldDesc.szFieldName) - 1]);
- FillChar(FldDesc, SizeOf(FldDesc), 0);
- StrLCopy(FldDesc.szFieldName, PChar(FldName), SizeOf(FldDesc.szFieldName) - 1);
- FldDesc.iFieldType := FldType;
- FldDesc.iAttributes := Attributes;
- Check(FIDSWriter.AddColumnDesc(FldDesc));
- end;
- function ComputeInfoCount(Info: TInfoArray): Integer;
- var
- i: Integer;
- begin
- Result := Length(Info);
- for i := 0 to High(Info) do
- if Info[i].FieldInfos <> nil then
- Inc(Result, ComputeInfoCount(Info[i].FieldInfos));
- end;
- procedure AddMinMax(AField: TField);
- begin
- case AField.DataType of
- ftInteger, ftSmallInt:
- if (TIntegerField(AField).MinValue <> 0) or
- (TIntegerField(AField).MaxValue <> 0) then
- begin
- AddAttribute(fldAttrArea, szMINVALUE,
- TIntegerField(AField).MinValue, False);
- AddAttribute(fldAttrArea, szMAXVALUE,
- TIntegerField(AField).MaxValue, False);
- end;
- ftCurrency, ftFloat:
- if (TFloatField(AField).MinValue <> 0 ) or
- (TFloatField(AField).MaxValue <> 0 ) then
- begin
- AddAttribute(fldAttrArea, szMINVALUE,
- TFloatField(AField).MinValue, False);
- AddAttribute(fldAttrArea, szMAXVALUE,
- TFloatField(AField).MaxValue, False);
- end;
- ftBCD:
- if (TBCDField(AField).MinValue <> 0 ) or
- (TIntegerField(AField).MaxValue <> 0 ) then
- begin
- AddAttribute(fldAttrArea, szMINVALUE,
- TBCDField(AField).MinValue, False);
- AddAttribute(fldAttrArea, szMAXVALUE,
- TBCDField(AField).MaxValue, False);
- end;
- ftFMTBcd:
- if (TFMTBcdField(AField).MaxValue <> '') or
- (TFMTBcdField(AField).MinValue <> '') then
- begin
- AddAttribute(fldAttrArea, szMINVALUE,
- VarFMTBcdCreate(TFMTBCDField(AField).MinValue, TFMTBCDField(AField).Precision, TFMTBCDField(AField).Size), False);
- AddAttribute(fldAttrArea, szMAXVALUE,
- VarFMTBcdCreate(TFMTBCDField(AField).MaxValue, TFMTBCDField(AField).Precision, TFMTBCDField(AField).Size), False);
- end;
- end;
- end;
- var
- FldType, Prec, Attr, i, Width: Integer;
- TempStr: string;
- begin
- if Info.IsDetail and (Info.Field = nil) then
- begin
- FldType := (dsfldEMBEDDEDTBL shl dsSizeBitsLen) or
- ComputeInfoCount(Info.FieldInfos) or dsPseudoFldType;
- AddFieldDesc(Info.DataSet.Name, FldType, 0);
- WriteMetaData(Info.DataSet, TInfoArray(Info.FieldInfos));
- end else
- begin
- Width := 0;
- Attr := 0;
- if Info.Field.ReadOnly or (Info.Field.FieldKind <> fkData) then Attr := Attr or fldAttrREADONLY;
- if Info.Field.Required and (Info.Field.DataType <> ftAutoInc) then Attr := Attr or fldAttrREQUIRED;
- if (pfHidden in Info.Field.ProviderFlags) then Attr := Attr or fldAttrHIDDEN or fldAttrREADONLY;
- FldType := PacketTypeMap[Info.Field.DataType];
- case Info.Field.DataType of
- ftTimeStamp:
- FldType := (FldType shl dsSizeBitsLen) or sizeof(TSQLTimeStamp);
- ftString, ftFixedChar, ftVarBytes, ftGUID, ftWideString:
- begin
- FldType := FldType shl dsSizeBitsLen or dsVaryingFldType;
- if Info.Size < 255 then
- FldType := FldType or SizeOf(Byte) else
- FldType := FldType or SizeOf(Word);
- Width := Info.Size;
- end;
- ftBCD:
- begin
- if TBCDField(Info.Field).Precision = 0 then
- Width := 32 else
- Width := TBCDField(Info.Field).Precision;
- Prec := Width shr 1;
- Inc(Prec, Prec and 1); { Make an even number }
- FldType := (FldType shl dsSizeBitsLen) or (Prec + 2);
- end;
- ftFMTBcd:
- begin
- if TFMTBCDField(Info.Field).Precision = 0 then
- Width := 32 else
- Width := TFMTBCDField(Info.Field).Precision;
- Prec := Width shr 1;
- Inc(Prec, Prec and 1); { Make an even number }
- FldType := (FldType shl dsSizeBitsLen) or (Prec + 2);
- end;
- ftArray:
- FldType := (FldType shl dsSizeBitsLen) or dsPseudoFldType or
- dsCompArrayFldType or TObjectField(Info.Field).Size;
- ftADT:
- FldType := (FldType shl dsSizeBitsLen) or dsPseudoFldType or
- TObjectField(Info.Field).FieldCount;
- ftDataSet, ftReference:
- FldType := (FldType shl dsSizeBitsLen) or dsPseudoFldType or
- dsEmbeddedFldType or ComputeInfoCount(TInfoArray(Info.FieldInfos));
- else
- if Info.Field.IsBlob then
- begin
- FldType := (FldType shl dsSizeBitsLen) or dsVaryingFldType or SizeOf(Integer);
- Width := Info.Field.Size;
- end else
- FldType := (FldType shl dsSizeBitsLen) or Info.Size;
- end;
- AddFieldDesc(Info.Field.FieldName, FldType, Attr);
- if (Info.Field.FieldKind <> fkData) then
- AddAttribute(fldAttrArea, szSERVERCALC, True, True);
- if Info.Field.ProviderFlags <> [pfInWhere, pfInUpdate] then
- AddAttribute(fldAttrArea, szPROVFLAGS, Byte(Info.Field.ProviderFlags), True);
- if Info.Field.Origin <> '' then
- AddAttribute(fldAttrArea, szORIGIN, Info.Field.Origin, True);
- if Width > 0 then
- AddAttribute(fldAttrArea, szWIDTH, Width, False);
- if Info.Field is TBCDField then
- begin
- if TBCDField(Info.Field).Size <> 0 then
- AddAttribute(fldAttrArea, szDECIMALS, TBCDField(Info.Field).Size, False);
- end
- else if Info.Field is TFMTBCDField then
- begin
- if TFMTBCDField(Info.Field).Size <> 0 then
- AddAttribute(fldAttrArea, szDECIMALS, TFMTBCDField(Info.Field).Size, False);
- end;
- AddMinMax(Info.Field);
- case Info.Field.DataType of
- ftCurrency: TempStr := szstMONEY;
- ftAutoInc: TempStr := szstAUTOINC;
- ftVarBytes, ftBlob: TempStr := szstBINARY;
- ftMemo: TempStr := szstMEMO;
- ftFmtMemo: TempStr := szstFMTMEMO;
- ftParadoxOle: TempStr := szstOLEOBJ;
- ftGraphic: TempStr := szstGRAPHIC;
- ftDBaseOle: TempStr := szstDBSOLEOBJ;
- ftTypedBinary: TempStr := szstTYPEDBINARY;
- ftADT:
- if (Info.Field.ParentField <> nil) and
- (Info.Field.ParentField.DataType in [ftDataSet, ftReference]) then
- TempStr := szstADTNESTEDTABLE;
- ftReference: TempStr := szstREFNESTEDTABLE;
- ftString:
- if TStringField(Info.Field).FixedChar then
- TempStr := szstFIXEDCHAR else
- TempStr := '';
- ftGUID: TempStr := szstGUID;
- ftOraClob: TempStr := szstHMEMO;
- ftOraBlob: TempStr := szstHBINARY;
- else
- TempStr := '';
- end;
- if TempStr <> '' then
- AddAttribute(fldAttrArea, szSUBTYPE, TempStr, False);
- if Info.Field is TObjectField then
- AddAttribute(fldAttrArea, szTYPENAME, TObjectField(Info.Field).ObjectType, False);
- if poIncFieldProps in Options then
- AddExtraFieldProps(Info.Field);
- case Info.Field.DataType of
- ftADT, ftArray: { Array will only have 1 child field }
- for i := 0 to High(TInfoArray(Info.FieldInfos)) do
- AddColumn(TInfoArray(Info.FieldInfos)[i]);
- ftDataSet, ftReference:
- with TDataSetField(Info.Field) do
- WriteMetaData(NestedDataSet, TInfoArray(Info.FieldInfos),
- Info.Field.DataType = ftReference);
- end;
- end;
- end;
- procedure TDataPacketWriter.AddConstraints(DataSet: TDataSet);
- type
- TConstraintType = (ctField, ctRecord, ctDefault);
- procedure AddSQLExprAttr(ExprParser: TExprParser; const ExprText, ExprErrMsg,
- FieldName: string; FieldIndex: Integer; ConstraintType: TConstraintType;
- Required: Boolean);
- type
- PSQLExprInfo = ^TSQLExprInfo;
- TSQLExprInfo = packed record
- iErrStrLen: Integer;
- iFldNum: Integer;
- bReqExpr: BYTE;
- end;
- const
- TypeStr: array[TConstraintType] of PChar = (szBDEDOMX, szBDERECX, szBDEDEFX);
- Attr: Integer = dsVaryingFldType or SizeOf(Integer) or (dsfldBYTES shl dsSizeBitsLen);
- var
- ErrorStr: string;
- AttrType: PChar;
- Len, AttrSize: Integer;
- SQLExprInfo: PSQLExprInfo;
- Options: TParserOptions;
- begin
- if ExprText = '' then Exit;
- if (ConstraintType <> ctDefault) and (ExprErrMsg = '') then
- begin
- if (ConstraintType = ctField) and (FieldName <> '') then
- ErrorStr := Format('%s %s: %s %s',[SConstraintFailed, SField, FieldName, ExprText]) else
- ErrorStr := Format('%s %s',[SConstraintFailed, ExprText]);
- end else
- ErrorStr := ExprErrMsg;
- Len := Length(ErrorStr);
- if (Len > 0) then Inc(Len);
- SQLExprInfo := @FBuffer[SizeOf(Integer)];
- SQLExprInfo.iErrStrLen := Len;
- SQLExprInfo.iFldNum := FieldIndex;
- SQLExprInfo.bReqExpr := Ord(Required);
- Options := [poExtSyntax];
- if ConstraintType = ctDefault then Include(Options, poDefaultExpr);
- if ConstraintType = ctRecord then Include(Options, poUseOrigNames);
- if FieldName <> '' then Include(Options, poFieldNameGiven);
- with ExprParser do
- begin
- SetExprParams(ExprText, [], Options, FieldName);
- Move(FilterData[0], FBuffer[SizeOf(TSQLExprInfo) + Len + SizeOf(Integer)], DataSize);
- AttrSize := DataSize + SizeOf(TSQLExprInfo) + Len;
- end;
- PInteger(FBuffer)^ := AttrSize;
- if Len > 0 then
- StrLCopy(@FBuffer[SizeOf(TSQLExprInfo) + SizeOf(Integer)], PChar(ErrorStr), Length(FBuffer) - SizeOf(TSQLExprInfo) - SizeOf(Integer) - 1);
- AttrType := TypeStr[ConstraintType];
- Check(FIDSWriter.AddAttribute(pcktAttrArea, AttrType, Attr, AttrSize + SizeOf(Integer), PByte(FBuffer)));
- end;
- var
- i: Integer;
- ExprParser: TExprParser;
- Constraints: TCheckConstraints;
- Obj: TObject;
- ErrMsg: string;
- begin
- ExprParser := TExprParser.Create(DataSet, '', [], [], '', nil, FieldTypeMap);
- try
- Obj := GetObjectProperty(DataSet, 'Constraints'); { Do not localize }
- if (Obj <> nil) and (Obj is TCheckConstraints) then
- begin
- Constraints := Obj as TCheckConstraints;
- try
- for i := 0 to Constraints.Count - 1 do
- with Constraints[i] do
- begin
- AddSQLExprAttr(ExprParser, ImportedConstraint, ErrorMessage, '', 0,
- ctRecord, False);
- AddSQLExprAttr(ExprParser, CustomConstraint, ErrorMessage, '', 0,
- ctRecord, False);
- end;
- except
- if DataSet.Name <> '' then
- ErrMsg := Format('%s: %s',[DataSet.Name, SRecConstFail])
- else
- ErrMsg := SRecConstFail;
- if ExceptObject is Exception then
- raise EDSWriter.CreateFmt(ErrMsg, [Exception(ExceptObject).Message])
- else
- raise EDSWriter.CreateFmt(ErrMsg, ['']);
- end;
- end;
- for i := 0 to DataSet.FieldList.Count - 1 do
- with DataSet.FieldList[i] do
- begin
- try
- AddSQLExprAttr(ExprParser, DefaultExpression, '', FullName, i + 1,
- ctDefault, False);
- except
- if Name <> '' then
- ErrMsg := Format('%s: %s',[Name, SDefExprFail]) else
- if DataSet.Name <> '' then
- ErrMsg := Format('%s.%s: %s',[DataSet.Name, FullName, SDefExprFail]) else
- ErrMsg := Format('%s: %s', [FullName, SDefExprFail]);
- if ExceptObject is Exception then
- raise EDSWriter.CreateFmt(ErrMsg, [Exception(ExceptObject).Message])
- else
- raise EDSWriter.CreateFmt(ErrMsg, ['']);
- end;
- try
- AddSQLExprAttr(ExprParser, ImportedConstraint, ConstraintErrorMessage,
- FullName, i + 1, ctField, False);
- AddSQLExprAttr(ExprParser, CustomConstraint, ConstraintErrorMessage,
- FullName, i + 1, ctField, False);
- except
- if Name <> '' then
- ErrMsg := Format('%s: %s',[Name, SFieldConstFail]) else
- if DataSet.Name <> '' then
- ErrMsg := Format('%s.%s: %s',[DataSet.Name, FullName, SFieldConstFail]) else
- ErrMsg := Format('%s: %s', [FullName, SFieldConstFail]);
- if ExceptObject is Exception then
- raise EDSWriter.CreateFmt(ErrMsg, [Exception(ExceptObject).Message])
- else
- raise EDSWriter.CreateFmt(ErrMsg, ['']);
- end;
- end;
- finally
- ExprParser.Free;
- end;
- end;
- procedure TDataPacketWriter.AddIndexDefs(DataSet: TDataSet; const Info: TInfoArray);
- var
- FieldList, CaseList, DescList: TList;
- function GetKeyData(Index: TIndexDef): OleVariant;
- var
- i: Integer;
- x: Integer;
- begin
- with Index do
- begin
- FieldList.Clear;
- CaseList.Clear;
- DescList.Clear;
- DataSet.GetFieldList(FieldList, Fields);
- DataSet.GetFieldList(CaseList, CaseInsFields);
- DataSet.GetFieldList(DescList, DescFields);
- Result := VarArrayCreate([0, FieldList.Count - 1], varInteger);
- for i := 0 to FieldList.Count - 1 do
- begin
- x := GetFieldIdx(TField(FieldList[i]).FieldName, Info);
- if (CaseList.IndexOf(FieldList[i]) <> -1) or
- ((i = 0) and (FieldList.Count = 1) and (ixCaseInSensitive in Options)) then
- x := x or dskeyCASEINSENSITIVE;
- if (DescList.IndexOf(FieldList[i]) <> -1) or
- ((i = 0) and (FieldList.Count = 1) and (ixDescending in Options)) then
- x := x or dskeyDESCENDING;
- Result[i] := x;
- end;
- end;
- end;
- var
- i: Integer;
- DefIdx, KeyIndex: TIndexDef;
- IndexDefs: TIndexDefs;
- KeyList: OleVariant;
- KeyFields: string;
- begin
- FieldList := TList.Create;
- try
- CaseList := TList.Create;
- try
- DescList := TList.Create;
- try
- { Get the DEFAULT_ORDER }
- if not (poRetainServerOrder in Options) then
- DefIdx := IProviderSupport(DataSet).PSGetDefaultOrder
- else
- DefIdx := nil;
- if Assigned(DefIdx) then
- try
- KeyList := GetKeyData(DefIdx);
- AddAttribute(pcktAttrArea, szDEFAULT_ORDER, KeyList, False);
- finally
- DefIdx.Free;
- end;
- KeyFields := IProviderSupport(DataSet).PSGetKeyFields;
- IndexDefs := IProviderSupport(DataSet).PSGetIndexDefs([ixUnique]);
- try
- if KeyFields <> '' then
- begin
- { PRIMARY_KEY is used to define the keyfields }
- KeyList := NULL;
- if Assigned(IndexDefs) then
- begin
- KeyIndex := IndexDefs.GetIndexForFields(KeyFields, False);
- if Assigned(KeyIndex) then
- begin
- KeyList := GetKeyData(KeyIndex);
- KeyIndex.Free;{ KeyIndex is already used, remove it from the list }
- end;
- end;
- if VarIsNull(KeyList) then
- begin
- DataSet.GetFieldList(FieldList, KeyFields);
- KeyList := VarArrayCreate([0, FieldList.Count - 1], varSmallInt);
- for i := 0 to FieldList.Count - 1 do
- KeyList[i] := GetFieldIdx(TField(FieldList[i]).FieldName, Info);
- end;
- if not VarIsNull(KeyList) then
- AddAttribute(pcktAttrArea, szPRIMARY_KEY, KeyList, False);
- end;
- if Assigned(IndexDefs) then
- for i := 0 to IndexDefs.Count - 1 do
- with IndexDefs[i] do
- begin
- KeyList := GetKeyData(IndexDefs[i]);
- AddAttribute(pcktAttrArea, szUNIQUE_KEY, KeyList, False);
- end;
- finally
- IndexDefs.Free;
- end;
- finally
- DescList.Free;
- end;
- finally
- CaseList.Free;
- end;
- finally
- FieldList.Free;
- end;
- end;
- procedure TDataPacketWriter.AddFieldLinks(const Info: TInfoArray);
- var
- MasterFields, DetailFields: TList;
- i, j: Integer;
- LinkFields: Variant;
- begin
- MasterFields := TList.Create;
- try
- DetailFields := TList.Create;
- try
- for i := 0 to High(Info) do
- if Info[i].IsDetail and (Info[i].Field = nil) then
- begin
- Info[i].DataSet.GetDetailLinkFields(MasterFields, DetailFields);
- if (MasterFields.Count > 0) and (MasterFields.Count <= DetailFields.Count) then
- begin
- LinkFields := VarArrayCreate([0, MasterFields.Count * 2], varSmallInt);
- LinkFields[0] := Info[i].LocalFieldIndex;
- for j := 0 to MasterFields.Count - 1 do
- LinkFields[j + 1] := GetFieldIdx(TField(MasterFields[j]).FieldName,
- Info);
- for j := 0 to MasterFields.Count - 1 do
- LinkFields[j + MasterFields.Count + 1] :=
- GetFieldIdx(TField(DetailFields[j]).FieldName, TInfoArray(Info[i].FieldInfos));
- AddAttribute(pcktAttrArea, szMD_FIELDLINKS, LinkFields, False);
- end;
- end;
- finally
- DetailFields.Free;
- end;
- finally
- MasterFields.Free;
- end;
- end;
- procedure TDataPacketWriter.WriteMetaData(DataSet: TDataSet; const Info: TInfoArray;
- IsReference: Boolean);
- var
- i, MDOptions: Integer;
- begin
- for i := 0 to High(Info) do
- AddColumn(Info[i]);
- if (poReadOnly in Options) or IsReference then
- AddAttribute(pcktAttrArea, szREADONLY, True, False);
- if (poDisableEdits in Options) then
- AddAttribute(pcktAttrArea, szDISABLE_EDITS, True, False);
- if (poDisableInserts in Options) then
- AddAttribute(pcktAttrArea, szDISABLE_INSERTS, True, False);
- if (poDisableDeletes in Options) then
- AddAttribute(pcktAttrArea, szDISABLE_DELETES, True, False);
- if (poNoReset in Options) then
- AddAttribute(pcktAttrArea, szNO_RESET_CALL, True, False);
- if Constraints then
- AddConstraints(DataSet);
- AddIndexDefs(DataSet, Info);
- AddFieldLinks(Info);
- MDOptions := 0;
- if poCascadeDeletes in Options then MDOptions := dsCASCADEDELETES;
- if poCascadeUpdates in Options then MDOptions := MDOptions or dsCASCADEUPDATES;
- if MDOptions <> 0 then
- AddAttribute(pcktAttrArea, szMD_SEMANTICS, MDOptions, True);
- AddDataSetAttributes(DataSet);
- if Info <> FPutFieldInfo then
- Check(FIDSWriter.AddAttribute(pcktAttrArea, nil, 0, 0, nil));
- end;
- procedure TDataPacketWriter.RefreshPutProcs(ADataSet: TDataSet; var Info: TInfoArray);
- procedure RefreshInfo(ADataSet: TDataSet; AField: TField; var Info: TPutFieldInfo);
- var
- j: Integer;
- begin
- Info.Field := AField;
- if AField = nil then
- Info.DataSet := ADataSet
- else
- begin
- Info.DataSet := AField.DataSet;
- if AField.DataType = ftADT then
- begin
- with TADTField(AField) do
- for j := 0 to FieldCount - 1 do
- RefreshInfo(ADataSet, Fields[j], TInfoArray(Info.FieldInfos)[j]);
- end;
- end;
- end;
- var
- i: Integer;
- List: TList;
- begin
- List := TList.Create;
- try
- ADataSet.GetDetailDataSets(List);
- for i := 0 to ADataSet.FieldCount - 1 do
- RefreshInfo(ADataSet, ADataSet.Fields[i], Info[i]);
- for i := 0 to List.Count - 1 do
- RefreshInfo(TDataSet(List[i]), nil, Info[ADataSet.FieldCount + i]);
- finally
- List.Free;
- end;
- end;
- function TDataPacketWriter.InitPutProcs(ADataSet: TDataSet;
- var GlobalIdx: Integer): TInfoArray;
- procedure InitInfoStruct(var Info: TPutFieldInfo; AField: TField;
- var GlobalIdx, LocalIdx: Integer);
- begin
- FillChar(Info, SizeOf(Info), 0);
- with Info do
- begin
- IsDetail := AField = nil;
- Field := AField;
- Inc(GlobalIdx);
- LocalFieldIndex := LocalIdx;
- Inc(LocalIdx);
- if Field <> nil then
- begin
- FieldNo := Field.FieldNo;
- Size := Field.DataSize;
- DataSet := Field.DataSet;
- end;
- end;
- end;
- procedure InitFieldProc(ADataSet: TDataSet; AField: TField;
- var Info: TPutFieldInfo; var GlobalIdx, LocalIdx: Integer);
- var
- i: Integer;
- NestedIdx: Integer;
- begin
- with Info do
- begin
- InitInfoStruct(Info, AField, GlobalIdx, LocalIdx);
- if AField = nil then { Linked dataset }
- begin
- Opened := not ADataSet.Active;
- if Opened then ADataSet.Open;
- DataSet := ADataSet;
- PutProc := PutDataSetField;
- TInfoArray(FieldInfos) := InitPutProcs(DataSet, GlobalIdx);
- end else
- begin
- case Field.DataType of
- ftString, ftFixedChar, ftGUID:
- begin
- PutProc := PutStringField;
- Dec(Size); { Don't count the null terminator }
- end;
- ftWideString:
- begin
- PutProc := PutWideStringField;
- Size := AField.Size * 2;
- end;
- ftVarBytes:
- begin
- PutProc := PutVarBytesField;
- Dec(Size, 2); { Don't write size bytes }
- end;
- ftADT:
- with TADTField(Field) do
- begin
- PutProc := PutADTField;
- SetLength(TInfoArray(FieldInfos), FieldCount);
- for i := 0 to FieldCount - 1 do
- InitFieldProc(ADataSet, Fields[i], TInfoArray(FieldInfos)[i],
- GlobalIdx, LocalIdx);
- end;
- ftArray:
- with TArrayField(Field) do
- begin
- PutProc := PutArrayField;
- SetLength(TInfoArray(FieldInfos), 1);
- NestedIdx := LocalIdx;
- InitFieldProc(ADataSet, Fields[0], TInfoArray(FieldInfos)[0],
- GlobalIdx, LocalIdx);
- LocalIdx := (LocalIdx - NestedIdx) * (FieldCount - 1) + LocalIdx;
- end;
- ftDataSet, ftReference:
- with TDataSetField(Field).NestedDataSet do
- begin
- PutProc := PutDataSetField;
- NestedIdx := 1;
- SetLength(TInfoArray(FieldInfos), FieldCount);
- for i := 0 to FieldCount - 1 do
- InitFieldProc(TDataSetField(Field).NestedDataSet, Fields[i],
- TInfoArray(FieldInfos)[i], GlobalIdx, NestedIdx);
- end;
- ftSmallint, ftInteger, ftWord, ftBoolean, ftFloat, ftCurrency, ftBCD,
- ftDate, ftTime, ftDateTime, ftAutoInc, ftLargeint, ftBytes, ftTimeStamp, ftFMTBcd:
- PutProc := PutField;
- ftBlob, ftMemo, ftGraphic, ftFmtMemo, ftParadoxOle, ftDBaseOle, ftTypedBinary, ftOraBlob, ftOraClob:
- PutProc := PutBlobField;
- else
- DatabaseErrorFmt(SUnknownFieldType, [Field.FieldName]);
- end;
- if Field.FieldKind <> fkData then
- PutProc := PutCalcField;
- end;
- end;
- end;
- var
- i, LocalIdx: Integer;
- List: TList;
- begin
- LocalIdx := 1;
- List := TList.Create;
- try
- ADataSet.GetDetailDataSets(List);
- SetLength(Result, ADataSet.FieldCount + List.Count);
- for i := 0 to ADataSet.FieldCount - 1 do
- InitFieldProc(ADataSet, ADataSet.Fields[i], Result[i], GlobalIdx, LocalIdx);
- for i := 0 to List.Count - 1 do
- InitFieldProc(TDataSet(List[i]), nil, Result[ADataSet.FieldCount + i],
- GlobalIdx, LocalIdx);
- finally
- List.Free;
- end;
- end;
- procedure TDataPacketWriter.GetDataPacket(DataSet: TDataSet;
- var RecsOut: Integer; out Data: OleVariant);
- procedure CheckMetaData(DataSet: TDataSet);
- var
- Idx: Integer;
- TempPacket: TDataPacket;
- Version: Integer;
- begin
- Idx := 1;
- if (FPutFieldInfo = nil) or (grMetaData in PacketOptions) then
- begin
- CreateDBClientObject(CLSID_DSWriter, IDSWriter, FIDSWriter);
- if FPutFieldInfo <> nil then
- begin
- FreeInfoRecords(FPutFieldInfo);
- FPutFieldInfo := nil;
- end;
- FPutFieldInfo := InitPutProcs(DataSet, Idx);
- if poFetchBlobsOnDemand in Options then
- Version := PACKETVERSION_3 else
- Version := PACKETVERSION_1;
- if grXMLUTF8 in PacketOptions then
- FIDSWriter.SetXMLMode(xmlUTF8)
- else if grXML in PacketOptions then
- FIDSWriter.SetXMLMode(xmlON)
- else
- FIDSWriter.SetXMLMode(0);
- Check(FIDSWriter.Init_Sequential(Version, Idx - 1));
- WriteMetaData(DataSet, FPutFieldInfo);
- if not (grMetaData in PacketOptions) then
- begin
- FIDSWriter.GetDataPacket(TempPacket);
- SafeArrayCheck(SafeArrayDestroy(TempPacket));
- TempPacket := nil;
- end;
- end;
- if not (grMetaData in PacketOptions) then
- Check(FIDSWriter.Reset);
- end;
- var
- DataPacket: TDataPacket;
- begin
- CheckMetaData(DataSet);
- RecsOut := WriteDataSet(DataSet, FPutFieldInfo, RecsOut);
- FIDSWriter.GetDataPacket(DataPacket);
- DataPacketToVariant(DataPacket, Data);
- end;
- procedure TDataPacketWriter.Reset;
- procedure CloseDetailDatasets(const Info: TInfoArray);
- var
- i: integer;
- begin
- for i := 0 to High(Info) do
- if Info[i].IsDetail and (Info[i].Opened or Info[i].Dataset.Active) then
- begin
- Info[i].DataSet.Close;
- Info[i].Opened := False;
- CloseDetailDatasets(TInfoArray(Info[i].FieldInfos));
- end;
- end;
- begin
- CloseDetailDatasets(FPutFieldInfo);
- end;
- { TPacketDataSet }
- constructor TPacketDataSet.Create(AOwner: TComponent);
- begin
- inherited;
- FetchOnDemand := False;
- end;
- procedure TPacketDataSet.CreateFromDelta(Source: TPacketDataSet);
- var
- TempBase: IDSBase;
- begin
- Source.Check(Source.DSBase.Clone(2, True, False, TempBase));
- DSBase := TempBase;
- Open;
- end;
- procedure TPacketDataSet.InternalInitRecord(Buffer: PChar);
- var
- I: Integer;
- begin
- inherited InternalInitRecord(Buffer);
- { Initialize new records in the error result dataset to unchanged values }
- for I := 1 to FieldCount do
- DSBase.PutBlank(PByte(Buffer), 0, I, BLANK_NOTCHANGED);
- end;
- procedure TPacketDataSet.InternalOpen;
- var
- MDSem: DWord;
- begin
- inherited InternalOpen;
- FOldRecBuf := AllocRecordBuffer;
- FCurRecBuf := AllocRecordBuffer;
- DSBase.GetProp(dspropMD_SEMANTICS, @MDSem);
- MDSem := MDSem and mdCASCADEMOD;
- DSBase.SetProp(dspropMD_SEMANTICS, MDSem);
- end;
- procedure TPacketDataSet.InternalClose;
- begin
- inherited InternalClose;
- FreeRecordBuffer(FOldRecBuf);
- FreeRecordBuffer(FCurRecBuf);
- end;
- function TPacketDataSet.GetStateFieldValue(State: TDataSetState; Field: TField): Variant;
- begin
- { When reading an OldValue, return the CurValue instead if we have one }
- if FUseCurValues and (State = dsOldValue) and HasCurValues then
- begin
- Result := inherited GetStateFieldValue(dsCurValue, Field);
- if not VarIsClear(Result) then Exit;
- end;
- Result := inherited GetStateFieldValue(State, Field);
- end;
- function TPacketDataSet.GetStreamMetaData: Boolean;
- var
- Value: Integer;
- begin
- DSBase.GetProp(DSProp(dspropDONTINCLMETADATA), @Value);
- Result := Value <> 0;
- end;
- procedure TPacketDataSet.SetStreamMetaData(Value: Boolean);
- begin
- DSBase.SetProp(DSProp(dspropDONTINCLMETADATA), Integer(not Value));
- end;
- function TPacketDataSet.UpdateKind: TUpdateKind;
- begin
- case UpdateStatus of
- usInserted: Result := ukInsert;
- usDeleted: Result := ukDelete;
- else
- Result := ukModify;
- end;
- end;
- procedure TPacketDataSet.DataEvent(Event: TDataEvent; Info: Integer);
- begin
- if Event in [deDataSetScroll, deDataSetChange] then
- begin
- FNewValuesModified := False;
- FCurValues := nil;
- end;
- inherited DataEvent(Event, Info);
- end;
- function TPacketDataSet.HasCurValues: Boolean;
- begin
- Result := FCurValues <> nil;
- end;
- procedure TPacketDataSet.InitAltRecBuffers(CheckModified: Boolean);
- var
- No: Integer;
- begin
- if UpdateStatus in [usUnmodified, usDeleted] then
- GetCurrentRecord(FOldRecBuf);
- if CheckModified and (UpdateStatus = usUnmodified) then
- begin
- No := RecNo;
- Next;
- if UpdateStatus <> usModified then
- RecNo := No;
- end;
- if UpdateStatus = usInserted then
- SetAltRecBuffers(ActiveBuffer, ActiveBuffer, FCurRecBuf) else
- SetAltRecBuffers(FOldRecBuf, ActiveBuffer, FCurRecBuf);
- end;
- procedure TPacketDataSet.SetFieldData(Field: TField; Buffer: Pointer);
- begin
- { Set a flag when any of the field's NewValue properties are modified }
- if State = dsNewValue then
- FNewValuesModified := True;
- if FWritingCurValues then
- Check(DSCursor.PutField(FCurRecBuf, Field.FieldNo, Buffer)) else
- inherited SetFieldData(Field, Buffer);
- end;
- procedure TPacketDataSet.SetWritingCurValues(const Value: Boolean);
- begin
- if Value then
- begin
- FCurValues := FCurRecBuf;
- InitRecord(FCurValues);
- end else
- InitAltRecBuffers;
- FWritingCurValues := Value;
- end;
- procedure TPacketDataSet.AssignCurValues(Source: TDataSet);
- var
- I: Integer;
- NewValue: Variant;
- Field, SourceField: TField;
- begin
- WritingCurValues := True;
- try
- for i := 0 to FieldCount - 1 do
- begin
- Field := Fields[i];
- SourceField := Source.FindField(Field.FieldName);
- if (SourceField <> nil) and not Field.IsBlob and
- not (Field.DataType in [ftBytes, ftVarBytes]) and
- (Field.OldValue <> SourceField.Value) then
- begin
- NewValue := Field.NewValue;
- if VarIsClear(Field.NewValue) or
- (NewValue <> SourceField.Value) then
- Field.Assign(SourceField);
- end;
- end;
- finally
- WritingCurValues := False;
- end;
- end;
- procedure TPacketDataSet.AssignCurValues(const CurValues: Variant);
- var
- I: Integer;
- Field: TField;
- CurValue: Variant;
- begin
- WritingCurValues := True;
- try
- if VarIsNull(CurValues) then
- FCurValues := nil
- else
- for I := VarArrayLowBound(CurValues, 1) to VarArrayHighBound(CurValues, 1) do
- begin
- if VarIsArray(CurValues[I]) then
- begin
- CurValue := CurValues[I][1];
- Field := FieldByName(CurValues[I][0])
- end else
- begin
- CurValue := CurValues[I];
- Field := Fields[I];
- end;
- if not VarIsClear(CurValue) then
- if (Field.OldValue <> CurValue) then
- Fields[I].Value := CurValue;
- end;
- finally
- WritingCurValues := False;
- end;
- end;
- function TPacketDataSet.HasMergeConflicts: Boolean;
- var
- I: Integer;
- CurVal, NewVal: Variant;
- begin
- Result := False;
- for I := 0 to FieldCount - 1 do
- with Fields[I] do
- begin
- CurVal := CurValue;
- if VarIsClear(CurVal) then Continue;
- NewVal := NewValue;
- if VarIsClear(NewVal) then Continue;
- if CurVal = NewVal then Continue;
- Result := True;
- Break;
- end;
- end;
- { TCustomProvider }
- constructor TCustomProvider.Create(AOwner: TComponent);
- var
- ProvContainer: IProviderContainer;
- begin
- inherited Create(AOwner);
- FExported := True;
- {$IFDEF MSWINDOWS}
- if AOwner is TRemoteDataModule then
- TRemoteDataModule(AOwner).RegisterProvider(Self)
- else if AOwner is TCRemoteDataModule then
- TCRemoteDataModule(AOwner).RegisterProvider(Self)
- else if Assigned(AOwner) then
- if AOwner.GetInterface(IProviderContainer, ProvContainer) then
- ProvContainer.RegisterProvider(Self);
- {$ENDIF}
- {$IFDEF LINUX}
- if Assigned(AOwner) then
- if AOwner.GetInterface(IProviderContainer, ProvContainer) then
- ProvContainer.RegisterProvider(Self);
- {$ENDIF}
- end;
- destructor TCustomProvider.Destroy;
- var
- ProvContainer: IProviderContainer;
- begin
- {$IFDEF MSWINDOWS}
- if Owner is TRemoteDataModule then
- TRemoteDataModule(Owner).UnRegisterProvider(Self)
- else if Owner is TCRemoteDataModule then
- TCRemoteDataModule(Owner).UnRegisterProvider(Self)
- else if Assigned(Owner) then
- if Owner.GetInterface(IProviderContainer, ProvContainer) then
- ProvContainer.UnRegisterProvider(Self);
- {$ENDIF}
- {$IFDEF LINUX}
- if Assigned(Owner) then
- if Owner.GetInterface(IProviderContainer, ProvContainer) then
- ProvContainer.UnRegisterProvider(Self);
- {$ENDIF}
- inherited Destroy;
- end;
- function TCustomProvider.GetData: OleVariant;
- var
- Recs: Integer;
- Options: TGetRecordOptions;
- begin
- Options := [grMetaData];
- Result := GetRecords(-1, Recs, Byte(Options));
- end;
- procedure TCustomProvider.DoAfterApplyUpdates(var OwnerData: OleVariant);
- begin
- if Assigned(FAfterApplyUpdates) then FAfterApplyUpdates(Self, OwnerData);
- end;
- procedure TCustomProvider.DoBeforeApplyUpdates(var OwnerData: OleVariant);
- begin
- if Assigned(FBeforeApplyUpdates) then FBeforeApplyUpdates(Self, OwnerData);
- end;
- function TCustomProvider.ApplyUpdates(Const Delta: OleVariant; MaxErrors: Integer;