Componentes.Terceros.RemObj.../internal/5.0.24.615/1/Data Abstract for Delphi/Source/uDABin2DataStreamer.pas

1501 lines
57 KiB
ObjectPascal

unit uDABin2DataStreamer;
{----------------------------------------------------------------------------}
{ Data Abstract Library - Core Library }
{ }
{ compiler: Delphi 6 and up }
{ platform: Win32 }
{ }
{ (c)opyright RemObjects Software. all rights reserved. }
{ }
{ Using this code requires a valid license of the Data Abstract }
{ which can be obtained at http://www.remobjects.com. }
{----------------------------------------------------------------------------}
{$I DataAbstract.inc}
interface
uses
Classes,
uDAInterfaces, uDADelta,
uDADataStreamer;
type
TBIN2AdapterSignature = array[0..7] of char;
const
BIN2AdapterSignature: TBIN2AdapterSignature = 'DABIN200';
type
TDASmallFieldInfo = packed record
Name: String;
Datatype: TDADataType;
Size: integer;
end;
TDADataForAppendBin2 = class(TDADataForAppend)
public
FieldsInfo: array of TDASmallFieldInfo;
end;
TDAElementType = (etDataset, etDelta);
{ TElementInfo }
TDAElementInfo = class
ElementType: TDAElementType;
Name: Ansistring;
Offset: integer;
end;
type
TDABin2DataStreamer = class(TDADataStreamer)
private
fInfoIntOffset: integer;
fHasReducedDelta: Boolean;
procedure ReadElementInfo;
procedure WriteElementInfo(ElementInfo: TDAElementInfo);
procedure AddElementInfo(ElementType: TDAElementType; ElementName: string; Offset: integer);
function GetElementInfo(ElementType: TDAElementType; const Name: string): TDAElementInfo;
procedure ReadAndApplySchema(const Destination: IDADataset; ApplySchema: boolean);
procedure WriteSchema(const Fields: TDAFieldCollection; const Params: TDAParamCollection; aFieldsIndex: array of integer); overload;
procedure WriteField(const AField: TDAField);
procedure WriteParam(const AParam: TDAParam);
procedure ReadParam(const AParam: TDAParam; const aParamPropertiesCount: integer);
procedure ReadField(const AField: TDAField; const aFieldPropertiesCount: integer);
protected
// To override
function DoCreateStream: TStream; override;
procedure DoInitialize(Mode: TDAAdapterInitialization); override;
procedure DoFinalize; override;
function DoWriteDataset(const Source: IDADataset; Options: TDAWriteOptions; MaxRows: integer; ADynFieldNames: array of string): integer; override;
function DoBeginWriteDataset( const Source: IDADataset; const Schema: TDADataset;
Options: TDAWriteOptions; MaxRows: integer;
ADynFieldNames: array of string): TDADataForAppend; override;
function DoWriteDatasetData(const Source: IDADataset; var aDataForAppend: TDADataForAppend; aDataIndex: Integer = -1): Integer; override;
function DoEndWriteDataset(aDataForAppend: TDADataForAppend): Integer; override;
procedure DoWriteDelta(const Source: IDADelta); override;
procedure DoReadDataset(const DatasetName: string; const Destination: IDADataset; ApplySchema: boolean); override;
procedure DoReadDelta(const DeltaName: string; const Destination: IDADelta); override;
public
function HasReducedDelta: Boolean; override;
published
property BufferSize;
property SendReducedDelta;
end;
implementation
uses
SysUtils, Variants, FMTBcd, uROBinaryHelpers,
uROClasses, uDAEngine, uDAClasses;
const
field_count = 34;
param_count = 11;
TAlignmentStrings: array[Low(TAlignment)..High(TAlignment)] of string =
('taLeftJustify', 'taRightJustify', 'taCenter');
TDABlobTypeStrings: array[Low(TDABlobType)..High(TDABlobType)] of string =
('dabtUnknown', 'dabtBlob', 'dabtMemo', 'dabtOraBlob',
'dabtOraClob', 'dabtGraphic', 'dabtTypedBinary');
TDADataTypeStrings: array[Low(TDADataType)..High(TDADataType)] of string =
('datUnknown', 'datString', 'datDateTime', 'datFloat',
'datCurrency', 'datAutoInc', 'datInteger', 'datLargeInt',
'datBoolean', 'datMemo', 'datBlob', 'datWideString',
'datWideMemo', 'datLargeAutoInc', 'datByte', 'datShortInt',
'datWord', 'datSmallInt', 'datCardinal', 'datLargeUInt',
'datGuid', 'datXml', 'datDecimal', 'datSingleFloat');
TDAParamTypeStrings:array[Low(TDAParamType)..High(TDAParamType)] of string =
('daptUnknown', 'daptInput', 'daptOutput', 'daptInputOutput',
'daptResult');
// from uDAMemDataset
const
ft_Reference = [datString, datMemo, datBlob, datWideString, datWideMemo];
function TAlignmentStringsToTAlignment(aValue: string): TAlignment;
begin
for Result := Low(TAlignment) to High(TAlignment) do
if SameText(TAlignmentStrings[Result], aValue) then Exit;
raise Exception.Create('Unknown TAlignment value: '''+aValue+'''');
end;
function TDABlobTypeStringsToTDABlobType(aValue: string): TDABlobType;
begin
for Result := Low(TDABlobType) to High(TDABlobType) do
if SameText(TDABlobTypeStrings[Result], aValue) then Exit;
raise Exception.Create('Unknown TDABlobType value: '''+aValue+'''');
end;
function TDADataTypeStringsToTDADataType(aValue: string): TDADataType;
begin
for Result := Low(TDADataType) to High(TDADataType) do
if SameText(TDADataTypeStrings[Result], aValue) then Exit;
raise Exception.Create('Unknown TDADataType value: '''+aValue+'''');
end;
function TDAParamTypeStringsToTDAParamType(aValue: string): TDAParamType;
begin
for Result := Low(TDAParamType) to High(TDAParamType) do
if SameText(TDAParamTypeStrings[Result], aValue) then Exit;
raise Exception.Create('Unknown TDAParamType value: '''+aValue+'''');
end;
procedure SetBitMask(Buffer: Pchar; const Index: Integer; const Value: boolean);
var
i: byte;
begin
i := Index shr 3;
if Value then
Buffer[I] := Chr(ord(Buffer[I]) or (1 shl (Index and 7)))
else
Buffer[I] := Chr(ord(Buffer[I]) and not (1 shl (Index and 7)))
end;
function GetBitMask(Buffer: Pchar; const Index: Integer): boolean;
begin
Result := (ord(Buffer[Index shr 3]) shr (Index and 7)) and 1 = 1;
end;
procedure ClearBitMask(Buffer: Pchar; BitMaskSize:integer; Value: byte = 0 );
begin
FillChar(Buffer^, BitMaskSize, Value);
end;
function ReadBooleanFromStream(Stream: TStream): ByteBool;
begin
Stream.Read(Result, SizeOf(ByteBool));
end;
procedure WriteBooleanToStream(Stream: TStream; const Value: ByteBool);
begin
Stream.Write(Value, SizeOf(ByteBool));
end;
function ReadByteFromStream(Stream: TStream): Byte;
begin
Stream.Read(Result, SizeOf(Byte));
end;
procedure WriteByteToStream(Stream: TStream; const Value: Byte);
begin
Stream.Write(Value, SizeOf(Byte));
end;
function ReadShortIntFromStream(Stream: TStream): ShortInt;
begin
Stream.Read(Result, SizeOf(ShortInt));
end;
procedure WriteShortIntToStream(Stream: TStream; const Value: ShortInt);
begin
Stream.Write(Value, SizeOf(ShortInt));
end;
function ReadWordFromStream(Stream: TStream): Word;
begin
Stream.Read(Result, SizeOf(Word));
end;
procedure WriteWordToStream(Stream: TStream; const Value: Word);
begin
Stream.Write(Value, SizeOf(Word));
end;
function ReadGUIDFromStream(Stream: TStream): string;
begin
SetLength(Result,38);
Result[1]:='{';
Stream.Read(Result[2], 36 {Length(GuidString)-2});
Result[38]:='}'
end;
procedure WriteGUIDToStream(Stream: TStream; const Value: string);
begin
if Length(Value) <> 38 then RaiseError('Invalid GUID: '+Value);
Stream.Write(Value[2], 36 {Length(GuidString)-2});
end;
function ReadDecimalFromStream(Stream: TStream): TDecimal;
begin
Stream.Read(Result, Sizeof(Result));
end;
function ReadBCDFromStream(Stream: TStream): TBCD;
begin
Result := DecimalToBCD(ReadDecimalFromStream(Stream));
end;
procedure WriteDecimalToStream(Stream: TStream; const Value: TDecimal);
begin
Stream.Write(Value, Sizeof(Value));
end;
procedure WriteBCDToStream(Stream: TStream; const Value: TBCD);
begin
WriteDecimalToStream(Stream,BCDToDecimal(Value));
end;
function ReadSingleFromStream(Stream: TStream): Single;
begin
Stream.Read(Result, SizeOf(Single));
end;
procedure WriteSingleToStream(Stream: TStream; const Value: Single);
begin
Stream.Write(Value, SizeOf(Single));
end;
function ReadSmallIntFromStream(Stream: TStream): SmallInt;
begin
Stream.Read(Result, SizeOf(SmallInt));
end;
procedure WriteSmallIntToStream(Stream: TStream; const Value: SmallInt);
begin
Stream.Write(Value, SizeOf(SmallInt));
end;
function ReadCardinalFromStream(Stream: TStream): Cardinal;
begin
Stream.Read(Result, SizeOf(Cardinal));
end;
procedure WriteCardinalToStream(Stream: TStream; const Value: Cardinal);
begin
Stream.Write(Value, SizeOf(Cardinal));
end;
function ReadCurrencyFromStream(Stream: TStream): Currency;
begin
Stream.Read(Result, SizeOf(Currency));
end;
procedure WriteCurrencyToStream(Stream: TStream; const Value: Currency);
begin
Stream.Write(Value, SizeOf(Currency));
end;
function ReadDoubleFromStream(Stream: TStream): Double;
begin
Stream.Read(Result, SizeOf(Double));
end;
procedure WriteDoubleToStream(Stream: TStream; const Value: Double);
begin
Stream.Write(Value, SizeOf(Double));
end;
function ReadDateTimeFromStream(Stream: TStream): TDateTime;
begin
Stream.Read(Result, SizeOf(TDateTime));
end;
procedure WriteDateTimeToStream(Stream: TStream; const Value: TDateTime);
begin
Stream.Write(Value, SizeOf(TDateTime));
end;
procedure Writeint64ToStream(Stream: TStream; const Value: int64);
begin
Stream.Write(Value, SizeOf(int64));
end;
function Readint64FromStream(Stream: TStream): int64;
begin
Stream.Read(Result, SizeOf(int64));
end;
procedure WriteIntegerToStream(Stream: TStream; const Value: Integer);
begin
Stream.Write(Value, SizeOf(integer));
end;
function ReadIntegerFromStream(Stream: TStream): Integer;
begin
Stream.Read(Result, SizeOf(integer));
end;
function ReadAnsistringFromStream(Stream: TStream): AnsiString;
var
Len: Cardinal;
begin
Len := ReadIntegerFromStream(Stream);
SetLength(Result, Len);
Stream.Read(Pointer(Result)^, len);
end;
procedure WriteAnsistringToStream(Stream: TStream; const AString: Ansistring);
var
Len: Cardinal;
begin
Len := Length(AString);
WriteIntegerToStream(Stream, Len);
Stream.Write(Pointer(AString)^, len);
end;
procedure WriteWidestringToStream(Stream: TStream; const AString: Widestring);
var
Len: Cardinal;
begin
Len := Length(AString) * sizeOf(WideChar);
WriteIntegerToStream(Stream, Len);
Stream.Write(Pointer(AString)^, len);
end;
function ReadWidestringFromStream(Stream: TStream): WideString;
var
Len: Cardinal;
begin
Len := ReadIntegerFromStream(Stream);
SetLength(Result, Len div sizeOf(WideChar));
Stream.Read(Pointer(Result)^, len);
end;
procedure BlobToStreamAsStr(Stream: TStream; Value: Variant);
var
p: pointer;
lSize: cardinal;
begin
case VarType(Value) of
varEmpty: WriteIntegerToStream(Stream, 0);
varOleStr: WriteWidestringToStream(Stream, Value);
varString: WriteAnsistringToStream(Stream, Value);
8209: begin { 8209 is binary array }
lSize := VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1) + 1;
p := VarArrayLock(Value);
try
WriteIntegerToStream(Stream, lSize);
Stream.Write(p^, lSize);
finally
VarArrayUnlock(Value);
end;
end;
else
raise Exception.CreateFmt('Invalid variant type (%d) for Blob.', [VarType(Value)]);
end;
end;
function WriteVariantToStream(Stream: TStream; Value: Variant; DataType: TDADataType): Boolean;
begin
Result := True;
case Datatype of
datWideString, datWideMemo, datXml: WriteWidestringToStream(Stream, VarToWideStr(Value));
datString, datMemo: WriteAnsistringToStream(Stream, VarToStr(Value));
datDateTime: WriteDateTimeToStream(Stream, VarToDateTime(Value));
datFloat: WriteDoubleToStream(Stream, Value);
datBoolean: WriteBooleanToStream(Stream, Value);
datCurrency: WriteCurrencyToStream(Stream, Value);
datAutoInc, datInteger: WriteIntegerToStream(Stream, Value);
datLargeInt, datLargeAutoInc, datLargeUInt: Writeint64ToStream(Stream, Value);
datBlob: BlobToStreamAsStr(Stream, Value);
datByte: WriteByteToStream(Stream, Value);
datShortInt: WriteShortIntToStream(Stream, Value);
datWord: WriteWordToStream(Stream, Value);
datSmallInt: WriteSmallIntToStream(Stream, Value);
datCardinal: WriteCardinalToStream(Stream, Value);
datGuid: WriteGuidToStream(Stream, VarToStr(Value));
datSingleFloat: WriteSingleToStream(Stream, Value);
datDecimal: WriteDecimalToStream(Stream, VariantToDecimal(Value));
else
Result := False;
end;
end;
function ReadVariantFromStream(Stream: TStream; DataType: TDADataType): Variant;
begin
case Datatype of
datWideString, datWideMemo, datXml: Result := ReadWidestringFromStream(Stream);
datString, datMemo, DatBlob: Result := ReadAnsistringFromStream(Stream);
datDateTime: Result := ReadDateTimeFromStream(Stream);
datFloat: Result := ReadDoubleFromStream(Stream);
datCurrency: Result := ReadCurrencyFromStream(Stream);
datBoolean: Result := ReadBooleanFromStream(Stream);
datAutoInc, datInteger: Result := ReadIntegerFromStream(Stream);
datLargeInt, datLargeAutoInc, datLargeUInt: Result := Readint64FromStream(Stream);
datByte: Result := ReadByteFromStream(Stream);
datShortInt: Result := ReadShortIntFromStream(Stream);
datWord: Result := ReadWordFromStream(Stream);
datSmallInt: Result := ReadSmallIntFromStream(Stream);
datCardinal: Result := ReadCardinalFromStream(Stream);
datGuid: Result := ReadGUIDFromStream(Stream);
datSingleFloat: Result := ReadSingleFromStream(Stream);
datDecimal: Result := DecimalToVariant(ReadDecimalFromStream(Stream));
else
Result := varNull;
end;
end;
{ TDABin2DataStreamer }
procedure TDABin2DataStreamer.AddElementInfo(ElementType: TDAElementType;
ElementName: string; Offset: integer);
var
element: TDAElementInfo;
begin
element := TDAElementInfo.Create;
element.ElementType := ElementType;
element.Name := ElementName;
element.Offset := Offset;
if ElementType = etDataset then
AddingDataset(ElementName, element)
else
AddingDelta(ElementName, element);
end;
function TDABin2DataStreamer.DoCreateStream: TStream;
begin
// outdated, for backward capability
result := nil;
end;
procedure TDABin2DataStreamer.DoFinalize;
var
finalpos, i: integer;
begin
if (AdapterInitialization in AdapterWriteModes) then try
finalpos := Data.Position;
// Element count. WIll be read by the DoInitialize method
WriteIntegerToStream(Data, DatasetCount + DeltaCount);
for i := 0 to (DatasetCount - 1) do
WriteElementInfo(TDAElementInfo(DatasetInfoObjects[i]));
for i := 0 to (DeltaCount - 1) do
WriteElementInfo(TDAElementInfo(DeltaInfoObjects[i]));
Data.Position := fInfoIntOffset;
WriteIntegerToStream(Data, finalpos);
except
beep;
raise;
end;
end;
procedure TDABin2DataStreamer.DoInitialize(Mode: TDAAdapterInitialization);
var
signature: TBIN2AdapterSignature;
currpos, i: integer;
begin
if (Mode in AdapterReadModes) then begin
// Checks the signature
signature := BIN2AdapterSignature;
Data.Read(signature, SizeOf(signature));
if (signature <> BIN2AdapterSignature) then raise Exception.Create('Incompatible binary2 adapter stream');
fInfoIntOffset := ReadIntegerFromStream(Data);
currpos := Data.Position;
// Reads the information attached at the end of the stream
if (Data.Position = fInfoIntOffset) then Exit; // Nothing to read!
Data.Position := fInfoIntOffset;
// Number of elements
i := ReadIntegerFromStream(Data);
for i := i downto 1 do
ReadElementInfo;
// Restores its position and continues
Data.Position := currpos;
end
else if (Mode in AdapterWriteModes) then begin
// Writes the signature
signature := BIN2AdapterSignature;
Data.Write(signature, SizeOf(signature));
// This integer will contain the offset of the stream information (datasetcount, names, etc)
// which will be attached at the end of the stream since this is a sequential write
fInfoIntOffset := Data.Position;
WriteIntegerToStream(Data, 0);
end;
end;
{$IFDEF FPC}
type
PDateTime = ^TDateTime;
{$ENDIF}
procedure BitmaskToNativeBuf(Bitmask, buf: pChar; BitMaskSize: integer);
var
j: integer;
i: integer;
begin
j := BitMaskSize;
for i:=0 to j-1 do begin
buf[i] := chr((ord(bitmask[i]) shl 1) and $FE);
if i > 0 then buf[i]:= chr(ord(buf[i]) + ((ord(bitmask[i-1]) shr 7) and 1));
end;
end;
procedure TDABin2DataStreamer.DoReadDataset(const DatasetName: string;
const Destination: IDADataset; ApplySchema: boolean);
var
elementinfo: TDAElementInfo;
editable: IDAEditableDataset;
schemaend, cnt, i, k: integer;
fld: TDAField;
schemapresent: boolean;
val: Variant;
readonlyfields: array of boolean;
//
Realfldcount: integer;
info: array of TDASmallFieldInfo;
BitMask: string;
streamer_BitMaskSize, memdataset_BitMaskSize: integer;
RealFields: array of integer;
Buf: Pchar;
buf1: pointer;
memdataset: IDAMemDatasetBatchAdding;
s: string;
lErrorMessage: String;
begin
if Destination.Active and ApplySchema then raise Exception.Create('Cannot apply a schema if the destination is active');
elementinfo := GetElementInfo(etDataset, DatasetName);
Data.Position := elementinfo.Offset;
editable := Destination as IDAEditableDataset;
Destination.DisableControls;
try
editable.DisableEventHandlers;
try
if ApplySchema then begin
// Checks to see if the schema is present
schemapresent := ReadBooleanFromStream(Data);
schemaend := ReadIntegerFromStream(Data);
if schemapresent and ApplySchema then begin
ReadAndApplySchema(Destination, ApplySchema);
end
else if (schemaend > 0) then
Data.Position := schemaend;
Exit;
end
else begin
{schemapresent :=} ReadBooleanFromStream(Data);
schemaend := ReadIntegerFromStream(Data);
if (schemaend > 0) then
Data.Position := schemaend;
// Reads the row count
cnt := ReadIntegerFromStream(Data);
if (cnt = -1) then Exit; // Only schema is present!
if not Destination.Active then Destination.Open;
with editable do try
// Temporarily sets all fields as writable
Destination.DisableConstraints;
Realfldcount := ReadIntegerFromStream(Data);
SetLength(info, Realfldcount);
//Data.Read(pointer(info)^, Sizeof(TDASmallFieldInfo) * Realfldcount);
for i := 0 to Realfldcount - 1 do begin
info[i].Name := ReadAnsistringFromStream(Data);
info[i].Datatype := TDADataType(ReadByteFromStream(Data));
info[i].Size := ReadIntegerFromStream(Data);
end;
SetLength(RealFields, Fields.Count);
k := 0;
SetLength(readonlyfields, Fields.Count);
for i := 0 to (Fields.Count - 1) do begin
readonlyfields[i] := Fields[i].ReadOnly;
Fields[i].ReadOnly := FALSE;
if Fields[i].Calculated or Fields[i].Lookup then Continue;
RealFields[k] := i;
if (k >= Realfldcount) then
lErrorMessage := lErrorMessage + 'Fields count mismatch' + #10#13
else begin
if (Fields[i].Name <> Info[k].Name) then lErrorMessage := lErrorMessage + Format('Name mismatch: %s expected but %s found in stream.', [Fields[i].Name, Info[k].Name]) + #10#13;
if (Fields[i].DataType <> Info[k].Datatype) then lErrorMessage := lErrorMessage + Format('Data type mismatch for column ''%s.%s'': %s expected but %s found in stream.', [DatasetName, Fields[i].Name, TDADataTypeStrings[Fields[i].DataType], TDADataTypeStrings[Info[k].Datatype]]) + #10#13;
if (Fields[i].Size <> Info[k].Size) then lErrorMessage := lErrorMessage + Format('Size mismatch for column ''%s.%s'': %d expected but %d found in stream.', [DatasetName, Fields[i].Name, Fields[i].Size, Info[k].Size]) + #10#13;
end;
inc(k);
end;
if (k <> Realfldcount) then lErrorMessage := lErrorMessage + Format('Fields count mismatch: %d expected but %d found in the stream', [Realfldcount, k]) + #10#13;
if (Length(lErrorMessage) > 0) then begin
lErrorMessage := 'Format of the data in the stream doesn''t match the destination table format.'+ #10#13 + #10#13 + lErrorMessage;
RaiseError(lErrorMessage);
end;
SetLength(RealFields, Realfldcount);
streamer_BitMaskSize := (Realfldcount + 7) div 8;
SetLength(BitMask, streamer_BitMaskSize);
// bitmask has different value that in ReadDelta/WriteDelta !!!
// 0 = field is not null
// 1 = field is null
// Inserts the records
try
if Destination.QueryInterface(IDAMemDatasetBatchAdding, memdataset) <> s_ok then memdataset := nil;
if (memdataset = nil) or Assigned(OnReadFieldValue) then begin
// standard mode
while (cnt > 0) do try
Append;
// read bitmask
Data.Read(pointer(BitMask)^, streamer_BitMaskSize);
for i := 0 to Realfldcount - 1 do begin
fld := Fields[RealFields[i]];
if GetBitMask(Pchar(BitMask), i) then
//
else begin
case fld.Datatype of
datWideString, datWideMemo, datXml: fld.AsWideString := ReadWidestringFromStream(Data);
datString, datMemo, DatBlob: fld.AsString := ReadAnsistringFromStream(Data);
datDateTime: fld.AsDateTime := ReadDateTimeFromStream(Data);
datFloat: fld.AsFloat := ReadDoubleFromStream(Data);
datCurrency: fld.AsCurrency := ReadCurrencyFromStream(Data);
datBoolean: fld.AsBoolean := ReadBooleanFromStream(Data);
datAutoInc, datInteger: fld.AsInteger := ReadIntegerFromStream(Data);
datLargeInt, datLargeAutoInc, datLargeUInt: fld.AsLargeInt := Readint64FromStream(Data);
datByte: fld.AsByte := ReadByteFromStream(Data);
datShortInt: fld.AsShortInt := ReadShortIntFromStream(Data);
datWord: fld.AsWord := ReadWordFromStream(Data);
datSmallInt: fld.AsSmallInt := ReadSmallIntFromStream(Data);
datCardinal: fld.AsCardinal := ReadCardinalFromStream(Data);
datGuid: fld.AsString := ReadGuidFromStream(Data);
datSingleFloat: fld.AsSingle := ReadSingleFromStream(Data);
datDecimal: fld.AsDecimal := ReadBCDFromStream(Data);
end;
end;
if Assigned(OnReadFieldValue) then begin
val := fld.Value;
OnReadFieldValue(fld, val);
fld.Value := val;
end;
end;
try
Post;
except
// Introduced to restore the dsBrowse state of the datatable
// in case of errors
Cancel;
raise;
end;
finally
Dec(cnt);
end;
end
else begin
// superfast mode
memdataset_BitMaskSize := (Realfldcount + 1 {RECID} + 7) div 8;
SetLength(BitMask, memdataset_BitMaskSize);
while (cnt > 0) do try
Buf := memdataset.AllocRecordBuffer;
try
Data.Read(pointer(BitMask)^, streamer_BitMaskSize);
BitmaskToNativeBuf(pointer(BitMask),buf, memdataset_BitMaskSize);
//Data.Read(buf^, BitMaskSize);
for i := 0 to Realfldcount - 1 do begin
fld := Fields[RealFields[i]];
if GetBitMask(Pchar(BitMask), i) then
//
else begin
buf1 := memdataset.GetFieldNativeBuffer(Buf, fld.BindedField);
case fld.DataType of
datWideString, datXml: memdataset.SetWideString(buf1,fld.BindedField,ReadWidestringFromStream(Data));//PWideString(buf1)^ := ReadWidestringFromStream(Data);
datString: memdataset.SetAnsiString(buf1,fld.BindedField,ReadAnsistringFromStream(Data));//PAnsiString(buf1)^ := ReadAnsistringFromStream(Data);
datDateTime: PDateTime(buf1)^ := TimeStampToMSecs(DateTimeToTimeStamp(ReadDateTimeFromStream(Data)));
datFloat: PDouble(buf1)^ := ReadDoubleFromStream(Data);
datCurrency: PDouble(buf1)^ := ReadCurrencyFromStream(Data);
datBoolean: PBoolean(buf1)^ := ReadBooleanFromStream(Data);
datLargeInt, datLargeAutoInc, datLargeUInt: PInt64(buf1)^ := Readint64FromStream(Data);
datAutoInc, datInteger: PInteger(buf1)^ := ReadIntegerFromStream(Data);
datCardinal: PCardinal(buf1)^ := ReadCardinalFromStream(Data);
datWord: PWord(buf1)^ := ReadWordFromStream(Data);
datShortInt: PSmallInt(buf1)^ := ReadShortIntFromStream(Data);
datSmallInt: PSmallInt(buf1)^ := ReadSmallIntFromStream(Data);
datByte: PSmallInt(buf1)^ := ReadByteFromStream(Data);
datSingleFloat: PDouble(buf1)^ := ReadSingleFromStream(Data);
datDecimal: PBCD(buf1)^ := ReadBCDFromStream(Data);
datGuid: begin
s := ReadGUIDFromStream(Data);
Move(pointer(s)^, pointer(buf1)^, 38 {Length(GuidString)});
end;
datWideMemo, datMemo, DatBlob: begin
s := ReadAnsistringFromStream(Data);
PPointer(buf1)^ := memdataset.MakeBlobFromString(s);
end;
end;
end;
end;
memdataset.AppendBuffer(Buf);
except
memdataset.FreeRecordBuffer(buf);
raise;
end;
finally
Dec(cnt);
end;
memdataset.FinalizeBatchAdding;
end;
except
raise;
end;
finally
// Restores the read-only property
for i := 0 to (Fields.Count - 1) do
Fields[i].ReadOnly := readonlyfields[i];
Destination.EnableConstraints;
end;
end;
finally
editable.EnableEventHandlers;
end;
finally
Destination.EnableControls;
end;
end;
procedure TDABin2DataStreamer.DoReadDelta(const DeltaName: string;
const Destination: IDADelta);
var
elementinfo: TDAElementInfo;
msg, str: string;
recid, i, cnt, x: integer;
change: TDADeltaChange;
changetype: TDAChangeType;
status: TDAChangeStatus;
BitMask: string;
BitMaskSize: integer;
begin
elementinfo := GetElementInfo(etDelta, DeltaName);
Data.Position := elementinfo.Offset;
// Number of changes
cnt := ReadIntegerFromStream(Data);
// Field number, names and types
Destination.ClearFieldNames;
i := ReadIntegerFromStream(Data);
for i := i downto 1 do begin
str := ReadAnsiStringFromStream(Data);
Destination.AddFieldName(str);
Destination.LoggedFieldTypes[Destination.LoggedFieldCount - 1] := TDADataType(ReadByteFromStream(Data));
end;
// Key fields
Destination.ClearKeyFieldNames;
i := ReadIntegerFromStream(Data);
for i := i downto 1 do begin
str := ReadAnsiStringFromStream(Data);
Destination.AddKeyFieldName(str);
end;
if (cnt = 0) then Exit;
BitMaskSize := (Destination.LoggedFieldCount + 7) div 8;
SetLength(BitMask, BitMaskSize);
// mode of Delta
fHasReducedDelta := ReadBooleanFromStream(Data);
// Actual changes
cnt := ReadIntegerFromStream(Data);
for i := 1 to cnt do begin
changetype := TDAChangeType(ReadIntegerFromStream(Data));
recid := ReadIntegerFromStream(Data);
status := TDAChangeStatus(ReadIntegerFromStream(Data));
msg := ReadAnsiStringFromStream(Data);
change := Destination.Add(recid, changetype, status, msg);
// bitmask has different value that in ReadDeataset/WriteDataset !!!
// 1 = field is not null
// 0 = field is null
Data.Read(pointer(BitMask)^, BitMaskSize);
// Old values
for x := 0 to (Destination.LoggedFieldCount - 1) do
if GetBitMask(Pchar(BitMask),x) then
change.OldValues[x] := ReadVariantFromStream(Data, Destination.LoggedFieldTypes[x]);
Data.Read(pointer(BitMask)^, BitMaskSize);
// new values
for x := 0 to (Destination.LoggedFieldCount - 1) do
if GetBitMask(Pchar(BitMask),x) then
change.NewValues[x] := ReadVariantFromStream(Data, Destination.LoggedFieldTypes[x]);
end;
end;
function TDABin2DataStreamer.DoWriteDataset(const Source: IDADataset;
Options: TDAWriteOptions; MaxRows: integer; ADynFieldNames: array of string): integer;
var
lDataForAppend: TDADataForAppend;
begin
lDataForAppend := DoBeginWriteDataset(Source, {schema}nil, Options, MaxRows, ADynFieldNames);
if woRows in Options then begin
DoWriteDatasetData(Source, lDataForAppend);
result := DoEndWriteDataset(lDataForAppend);
end
else begin
result := -1;
end;
end;
procedure TDABin2DataStreamer.DoWriteDelta(const Source: IDADelta);
var
i, x: integer;
pk_array: array of boolean;
BitMask_Old,BitMask_new: string;
BitMaskSize: integer;
old_val,new_val: variant;
l_bitmaskflag: boolean;
fLocalSendReducedDelta: Boolean;
begin
// This information will be used later to complete the stream (see DoInitialize)
AddElementInfo(etDelta, Source.LogicalName, Data.Position);
// Number of changes
WriteIntegertoStream(Data, Source.Count);
// Numnber of fields, field names and their types
WriteIntegertoStream(Data, Source.LoggedFieldCount);
for i := 0 to (Source.LoggedFieldCount - 1) do begin
WriteAnsiStringtoStream(Data, Source.LoggedFieldNames[i]);
WriteByteToStream(Data, Ord(Source.LoggedFieldTypes[i]));
end;
// Key fields
WriteIntegertoStream(Data, Source.KeyFieldCount);
for i := 0 to (Source.KeyFieldCount - 1) do begin
WriteAnsiStringtoStream(Data, Source.KeyFieldNames[i]);
end;
if (Source.Count = 0) then Exit;
// mode of Delta
WriteBooleanToStream(Data, SendReducedDelta);
// Actual changes
WriteIntegertoStream(Data, Source.Count);
BitMaskSize := (Source.LoggedFieldCount + 7) div 8;
SetLength(BitMask_old, BitMaskSize);
SetLength(BitMask_new, BitMaskSize);
fLocalSendReducedDelta := SendReducedDelta and (Source.KeyFieldCount >0);
if fLocalSendReducedDelta then begin
SetLength(pk_array, Source.LoggedFieldCount);
for i := 0 to Source.LoggedFieldCount - 1 do
pk_array[i]:=False;
for i := 0 to Source.KeyFieldCount - 1 do begin
x := Source.IndexOfLoggedField(Source.KeyFieldNames[i]);
if x <> -1 then pk_array[x]:=True;
end;
end;
for i := 0 to (Source.Count - 1) do begin
// Change type, RecID, status and message
WriteIntegertoStream(Data, integer(Source.Changes[i].ChangeType));
WriteIntegertoStream(Data, Source.Changes[i].RecID);
WriteIntegertoStream(Data, integer(Source.Changes[i].Status));
WriteAnsiStringtoStream(Data, Source.Changes[i].Message);
// bitmask has different value that in ReadDeataset/WriteDataset !!!
// 1 = field is not null
// 0 = field is null
ClearBitMask(Pchar(BitMask_old),BitMaskSize,0);
ClearBitMask(Pchar(BitMask_New),BitMaskSize,0);
if fLocalSendReducedDelta then begin
for x := 0 to (Source.LoggedFieldCount - 1) do begin
old_val:=Source.Changes[i].OldValues[x];
new_val:=Source.Changes[i].NewValues[x];
l_bitmaskflag:=pk_array[x] or not ROVariantsEqual(old_val,new_val);
SetBitMask(Pchar(BitMask_Old), x, l_bitmaskflag and not (VarIsNull(old_val) or (VarIsEmpty(old_val))));
SetBitMask(Pchar(BitMask_new), x, l_bitmaskflag and not (VarIsNull(new_val) or (VarIsEmpty(new_val))));
end;
end else begin
for x := 0 to (Source.LoggedFieldCount - 1) do begin
old_val:=Source.Changes[i].OldValues[x];
new_val:=Source.Changes[i].NewValues[x];
SetBitMask(Pchar(BitMask_Old), x, not (VarIsNull(old_val) or (VarIsEmpty(old_val))));
SetBitMask(Pchar(BitMask_new), x, not (VarIsNull(new_val) or (VarIsEmpty(new_val))));
end;
end;
// old
Data.Write(pointer(BitMask_Old)^, BitMaskSize);
for x := 0 to (Source.LoggedFieldCount - 1) do
if GetBitMask(Pchar(BitMask_Old),x) then
WriteVariantToStream(Data,Source.Changes[i].OldValues[x],Source.LoggedFieldTypes[x]);
// new
Data.Write(pointer(BitMask_new)^, BitMaskSize);
for x := 0 to (Source.LoggedFieldCount - 1) do
if GetBitMask(Pchar(BitMask_new),x) then
WriteVariantToStream(Data,Source.Changes[i].NewValues[x],Source.LoggedFieldTypes[x]);
end;
end;
function TDABin2DataStreamer.GetElementInfo(ElementType: TDAElementType;
const Name: string): TDAElementInfo;
begin
result := nil;
case ElementType of
etDataset: result := TDAElementInfo(DatasetInfoObjects[GetDatasetIndex(Name)]);
etDelta: result := TDAElementInfo(DeltaInfoObjects[GetDeltaIndex(Name)]);
end;
end;
function TDABin2DataStreamer.HasReducedDelta: Boolean;
begin
Result:= fHasReducedDelta;
end;
procedure TDABin2DataStreamer.ReadAndApplySchema(
const Destination: IDADataset; ApplySchema: boolean);
var
lField_cnt: integer;
lparam_cnt: integer;
i: integer;
cnt: integer;
begin
Destination.Fields.Clear;
cnt := ReadIntegerFromStream(Data);
lField_cnt:= ReadIntegerFromStream(Data);
for i := 0 to (cnt - 1) do
ReadField(Destination.Fields.Add, lField_cnt);
Destination.Params.Clear;
cnt := ReadIntegerFromStream(Data);
lparam_cnt:= ReadIntegerFromStream(Data);
for i := 0 to (cnt - 1) do
ReadParam(Destination.Params.Add, lparam_cnt);
end;
procedure TDABin2DataStreamer.ReadElementInfo;
var
et: TDAElementType;
nme: string;
ofs: integer;
begin
et := TDAElementType(ReadIntegerFromStream(Data));
nme := ReadAnsistringFromStream(Data);
ofs := ReadIntegerFromStream(Data);
AddElementInfo(et, nme, ofs);
end;
procedure TDABin2DataStreamer.WriteElementInfo(
ElementInfo: TDAElementInfo);
begin
WriteIntegerToStream(Data, integer(ElementInfo.ElementType));
WriteAnsiStringToStream(Data, ElementInfo.Name);
WriteIntegerToStream(Data, ElementInfo.Offset);
end;
procedure TDABin2DataStreamer.WriteSchema(const Fields: TDAFieldCollection; const Params: TDAParamCollection; aFieldsIndex: array of integer);
var
i: integer;
begin
WriteIntegerToStream(Data, Length(aFieldsIndex));
WriteIntegerToStream(Data, field_count);
for i := 0 to High(aFieldsIndex) do
WriteField(Fields[aFieldsIndex[i]]);
WriteIntegerToStream(Data, Params.Count);
WriteIntegerToStream(Data, param_count);
for i := 0 to Params.Count - 1 do
WriteParam(Params[i]);
end;
function TDABin2DataStreamer.DoBeginWriteDataset(
const Source: IDADataset; const Schema: TDADataset;
Options: TDAWriteOptions; MaxRows: integer;
ADynFieldNames: array of string): TDADataForAppend;
var
max, cntpos, currpos, k, i, Realfldcnt: integer;
fld: TDAField;
wrtschema: boolean;
info: array of TDASmallFieldInfo;
RealFields: array of integer;
lfields: array of integer;
lDataForAppend : TDADataForAppendBin2;
lSchemaFields: TDAFieldCollection;
lSchemaParams: TDAParamCollection;
lLogicalName: String;
begin
lDataForAppend := TDADataForAppendBin2.Create();
result := lDataForAppend;
if Assigned(Schema) then begin
lDataForAppend.TableSchema := Schema;
if Schema is TDAUnionDataTable then begin
fld := Schema.FindField(def_SourceTableFieldName);
if not Assigned(fld) then begin
fld := Schema.Fields.Add();
fld.Name := def_SourceTableFieldName;
fld.DataType := datInteger;
fld.InPrimaryKey := true;
fld.ServerAutoRefresh := true;
end;
end;
lSchemaFields := Schema.Fields;
lSchemaParams := Schema.Params;
lLogicalName := Schema.Name;
end else begin
if Assigned(Source) then begin
lSchemaFields := Source.Fields;
lSchemaParams := Source.Params;
lLogicalName := Source.LogicalName;
end else begin
raise EDAException.Create('Schema or source should be assigned.');
end;
end;
if Length(ADynFieldNames) > 0 then begin
SetLength(lfields, Length(ADynFieldNames));
For i:=0 to High(ADynFieldNames) do begin
fld := lSchemaFields.FindField(ADynFieldNames[i]);
if fld <> nil then
lfields[i]:= fld.Index
else
lfields[i]:= -1; // TODO: shoudln't this raise an exception "field not found", or the like?
end;
end else begin
SetLength(lfields, lSchemaFields.Count);
For i:=0 to lSchemaFields.Count-1 do
lfields[i]:=i;
end;
// This information will be used later to complete the stream (see DoInitialize)
AddElementInfo(etDataset, lLogicalName, Data.Position);
// Writes a boolean flag that indicates if the schema is being written
wrtschema := (woSchema in Options) or (Length(ADynFieldNames)>0);
WriteBooleanToStream(Data, wrtschema);
// Write the offset to jump to if the reader wants to skip the schema
currpos := Data.Position;
WriteIntegerToStream(Data, 0);
if wrtschema then begin
WriteSchema(lSchemaFields, lSchemaParams, lfields);
// Writes the offset of the schema's end
k := Data.Position;
Data.Position := currpos;
WriteIntegerToStream(Data, k);
Data.Position := k;
end;
// Writes the row count
if not (woRows in Options) then begin
WriteIntegerToStream(Data, -1);
Exit;
end
else begin
cntpos := Data.Position;
WriteIntegerToStream(Data, 0);
max := MaxRows;
end;
// write datatypes+offsets
SetLength(info, lSchemaFields.Count);
SetLength(RealFields, lSchemaFields.Count);
Realfldcnt := 0;
for i := 0 to High(lfields) do begin
if lSchemaFields[lfields[i]].Calculated or lSchemaFields[lfields[i]].Lookup then Continue;
RealFields[Realfldcnt] := lfields[i];
info[Realfldcnt].Name := lSchemaFields[lfields[i]].Name;
info[Realfldcnt].Datatype := lSchemaFields[lfields[i]].DataType;
info[Realfldcnt].Size := lSchemaFields[lfields[i]].Size;
inc(Realfldcnt);
end;
SetLength(info, Realfldcnt);
SetLength(RealFields, Realfldcnt);
WriteIntegerToStream(Data, Realfldcnt);
//Data.Write(pointer(info)^, Sizeof(TDASmallFieldInfo) * Realfldcnt);
for i := 0 to Realfldcnt - 1 do begin
WriteAnsistringToStream(Data, info[i].Name);
WriteByteToStream(Data, Byte(info[i].DataType));
WriteIntegerToStream(Data, info[i].Size);
end;
// prepare DataForAppend structure...
SetLength(lDataForAppend.RealFields, Realfldcnt);
SetLength(lDataForAppend.FieldsInfo, Realfldcnt);
for i := Low(RealFields) to High(RealFields) do begin
lDataForAppend.RealFields[i] := RealFields[i];
lDataForAppend.FieldsInfo[i].Name := info[i].Name;
lDataForAppend.FieldsInfo[i].Datatype := info[i].Datatype;
lDataForAppend.FieldsInfo[i].Size := info[i].Size;
end;
lDataForAppend.MaxRowCount := max;
lDataForAppend.CountOfRecordsPosition := cntpos;
k := 0;
lDataForAppend.EndDataPosition := Data.Position;
lDataForAppend.RecordCount := k;
result := lDataForAppend;
end;
function TDABin2DataStreamer.DoWriteDatasetData(const Source: IDADataset; var aDataForAppend: TDADataForAppend; aDataIndex: Integer = -1): Integer;
var
max, currpos, k, i, bitmaskpos, Realfldcnt: integer;
fld: TDAField;
val: Variant;
info: array of TDASmallFieldInfo;
BitMask: string;
BitMaskSize: integer;
RealFields: array of integer;
ev1, ev2: boolean;
NeedWriteBitMask: Boolean;
lDataForAppend: TDADataForAppendBin2;
lMapToFieldName: String;
lColumnMappings: TDAColumnMappingCollection;
lColumnMapping: TDAColumnMapping;
begin
lDataForAppend := aDataForAppend as TDADataForAppendBin2;
Realfldcnt := Length(lDataForAppend.RealFields);
Data.Position := lDataForAppend.EndDataPosition;
SetLength(info, Realfldcnt);
SetLength(RealFields, Realfldcnt);
for i := 0 to Realfldcnt - 1 do begin
info[i].Name := lDataForAppend.FieldsInfo[i].Name;
info[i].Datatype := lDataForAppend.FieldsInfo[i].Datatype;
info[i].Size := lDataForAppend.FieldsInfo[i].Size;
// these arrays always have the same size
RealFields[i] := lDataForAppend.RealFields[i];
end;
max := lDataForAppend.MaxRowCount;
k := lDataForAppend.RecordCount;
// Mapping fields of Source table to the streamed dataset
if Assigned(lDataForAppend.TableSchema) and (lDataForAppend.TableSchema is TDAUnionDataTable) then begin
lColumnMappings := TDAUnionSourceTable(TDAUnionDataTable(lDataForAppend.TableSchema).SourceTables.ItemByName(Source.Name)).ColumnMappings;
for i := 0 to Realfldcnt - 1 do begin
if info[i].Name = def_SourceTableFieldName then begin
RealFields[i] := -10;
continue;
end;
lMapToFieldName := info[i].Name;
if Assigned(lColumnMappings) then begin
lColumnMapping := lColumnMappings.MappingByDatasetField(info[i].Name);
if Assigned(lColumnMapping) and (lColumnMapping.TableField <> '') then
lMapToFieldName := lColumnMapping.TableField;
end;
RealFields[i] := Source.FieldByName(lMapToFieldName).Index;
end;
end;
with Source do try
DisableControls;
if not Source.Active then Source.Open;
BitMaskSize := (Realfldcnt + 7) div 8;
SetLength(BitMask, BitMaskSize);
// bitmask has different value that in ReadDelta/WriteDelta !!!
// 0 = field is not null
// 1 = field is null
ev1 := Assigned(OnBeforeFieldValueSerialization);
ev2 := Assigned(OnWriteFieldValue);
try
if ev1 or ev2 then begin
// with events
while (k <> max) and not EOF do begin
ClearBitMask(Pchar(BitMask),BitMaskSize); // all is not Null
bitmaskpos := Data.Position;
Data.Write(pointer(BitMask)^, BitMaskSize);
NeedWriteBitMask := False;
for i := 0 to (Realfldcnt - 1) do begin
//RealFields[i] = -10 then this is @SourceTable field
if RealFields[i] = -10 then begin
//We shouldn't fire events since this is special internal field
val := aDataIndex;
end else begin
fld := Fields[RealFields[i]];
val := FieldValues[RealFields[i]];
if ev1 then OnBeforeFieldValueSerialization(fld, val);
if ev2 then OnWriteFieldValue(fld, val);
end;
if VarIsNull(Val) or VarIsEmpty(Val) then begin
NeedWriteBitMask := True;
SetBitMask(Pchar(BitMask), i, True);
// if info[i].Datatype in ft_Reference then WriteIntegerToStream(Data, 0); // size=0
end else begin
if not WriteVariantToStream(Data, val, Info[i].Datatype) then begin
NeedWriteBitMask := True;
SetBitMask(Pchar(BitMask), i, True);
end;
end;
if NeedWriteBitMask then begin
currpos := Data.Position;
Data.Position := bitmaskpos;
Data.Write(pointer(BitMask)^, BitMaskSize);
Data.Position := currpos;
end;
end;
// Inc(result);
Inc(k);
Source.Next;
if Source.EOF then Break;
end;
end
else begin
// Writes the actual records
// without events
while (k <> max) and not EOF do begin
ClearBitMask(Pchar(BitMask),BitMaskSize); // all is not Null
for i := 0 to (Realfldcnt - 1) do
//RealFields[i] = -10 then this is @SourceTable field
if ((RealFields[i] <> -10) and (Fields[RealFields[i]].IsNull)) then
SetBitMask(Pchar(BitMask), i, True);
Data.Write(pointer(BitMask)^, BitMaskSize);
for i := 0 to (Realfldcnt - 1) do begin
//RealFields[i] = -10 then this is @SourceTable field
if RealFields[i] = -10 then begin
WriteIntegerToStream(Data, aDataIndex);
end else begin
fld := Fields[RealFields[i]];
if GetBitMask(Pchar(BitMask), i) then begin
// if info[i].Datatype in ft_Reference then WriteIntegerToStream(Data, 0); // size=0
end else begin
case Info[i].Datatype of
datWideString, datWideMemo, datXml: WriteWidestringToStream(Data, fld.AsWideString);
datString, datMemo, datBlob: WriteAnsistringToStream(Data, fld.AsString);
datDateTime: WriteDateTimeToStream(Data, fld.AsDateTime);
datFloat: WriteDoubleToStream(Data, fld.AsFloat);
datBoolean: WriteBooleanToStream(Data, fld.AsBoolean);
datCurrency: WriteCurrencyToStream(Data, fld.AsCurrency);
datAutoInc, datInteger: WriteIntegerToStream(Data, fld.AsInteger);
datLargeInt, datLargeAutoInc, datLargeUInt: Writeint64ToStream(Data, fld.AsLargeInt);
datByte: WriteByteToStream(Data, fld.AsByte);
datShortInt: WriteShortIntToStream(Data, fld.AsShortInt);
datWord: WriteWordToStream(Data, fld.AsWord);
datSmallInt: WriteSmallIntToStream(Data, fld.AsSmallInt);
datCardinal: WriteCardinalToStream(Data, fld.AsCardinal);
datGuid: WriteGUIDToStream(Data, fld.AsString);
datSingleFloat: WriteSingleToStream(Data, fld.AsSingle);
datDecimal: WriteBCDToStream(Data, fld.AsDecimal);
end;
end;
end;
end;
// Inc(result);
Inc(k);
Source.Next;
if Source.EOF then Break;
end;
end;
except
raise;
end;
lDataForAppend.EndDataPosition := Data.Position;
lDataForAppend.RecordCount := k;
finally
EnableControls;
result := k;
end;
end;
function TDABin2DataStreamer.DoEndWriteDataset(aDataForAppend: TDADataForAppend): Integer;
begin
result := aDataForAppend.RecordCount;
Data.Position := aDataForAppend.CountOfRecordsPosition;
WriteIntegerToStream(Data, aDataForAppend.RecordCount);
Data.Position := aDataForAppend.EndDataPosition;
aDataForAppend.Free();
end;
procedure TDABin2DataStreamer.WriteField(const AField: TDAField);
begin
WriteAnsistringToStream(Data, 'Alignment');
WriteAnsistringToStream(Data, TAlignmentStrings[AField.Alignment]);
WriteAnsistringToStream(Data, 'BlobType');
WriteAnsistringToStream(Data, TDABlobTypeStrings[AField.BlobType]);
WriteAnsistringToStream(Data, 'BusinessClassID');
WriteAnsistringToStream(Data, AField.BusinessClassID);
WriteAnsistringToStream(Data, 'Calculated');
WriteAnsistringToStream(Data, BoolToStr(AField.Calculated,True));
WriteAnsistringToStream(Data, 'CustomAttributes');
WriteAnsistringToStream(Data, AField.CustomAttributes.Text);
WriteAnsistringToStream(Data, 'DataType');
WriteAnsistringToStream(Data, TDADataTypeStrings[AField.DataType]);
WriteAnsistringToStream(Data, 'DecimalPrecision');
WriteAnsistringToStream(Data, IntToStr(AField.DecimalPrecision));
WriteAnsistringToStream(Data, 'DecimalScale');
WriteAnsistringToStream(Data, IntToStr(AField.DecimalScale));
WriteAnsistringToStream(Data, 'DefaultValue');
WriteAnsistringToStream(Data, AField.DefaultValue);
WriteAnsistringToStream(Data, 'Description');
WriteAnsistringToStream(Data, AField.Description);
WriteAnsistringToStream(Data, 'DictionaryEntry');
WriteAnsistringToStream(Data, AField.DictionaryEntry);
WriteAnsistringToStream(Data, 'DisplayFormat');
WriteAnsistringToStream(Data, AField.DisplayFormat);
WriteAnsistringToStream(Data, 'DisplayLabel');
WriteAnsistringToStream(Data, AField.DisplayLabel);
WriteAnsistringToStream(Data, 'DisplayWidth');
WriteAnsistringToStream(Data, IntToStr(AField.DisplayWidth));
WriteAnsistringToStream(Data, 'EditFormat');
WriteAnsistringToStream(Data, AField.EditFormat);
WriteAnsistringToStream(Data, 'EditMask');
WriteAnsistringToStream(Data, AField.EditMask);
WriteAnsistringToStream(Data, 'Expression');
WriteAnsistringToStream(Data, AField.Expression);
WriteAnsistringToStream(Data, 'GeneratorName');
WriteAnsistringToStream(Data, AField.GeneratorName);
WriteAnsistringToStream(Data, 'InPrimaryKey');
WriteAnsistringToStream(Data, BoolToStr(AField.InPrimaryKey,True));
WriteAnsistringToStream(Data, 'KeyFields');
WriteAnsistringToStream(Data, AField.KeyFields);
WriteAnsistringToStream(Data, 'LogChanges');
WriteAnsistringToStream(Data, BoolToStr(AField.LogChanges,True));
WriteAnsistringToStream(Data, 'Lookup');
WriteAnsistringToStream(Data, BoolToStr(AField.Lookup,True));
WriteAnsistringToStream(Data, 'LookupCache');
WriteAnsistringToStream(Data, BoolToStr(AField.LookupCache,True));
WriteAnsistringToStream(Data, 'LookupKeyFields');
WriteAnsistringToStream(Data, AField.LookupKeyFields);
WriteAnsistringToStream(Data, 'LookupResultField');
WriteAnsistringToStream(Data, AField.LookupResultField);
WriteAnsistringToStream(Data, 'LookupSource');
WriteAnsistringToStream(Data, '');
WriteAnsistringToStream(Data, 'Name');
WriteAnsistringToStream(Data, AField.Name);
WriteAnsistringToStream(Data, 'ReadOnly');
WriteAnsistringToStream(Data, BoolToStr(AField.ReadOnly,True));
WriteAnsistringToStream(Data, 'RegExpression');
WriteAnsistringToStream(Data, AField.RegExpression);
WriteAnsistringToStream(Data, 'Required');
WriteAnsistringToStream(Data, BoolToStr(AField.Required,True));
WriteAnsistringToStream(Data, 'ServerAutoRefresh');
WriteAnsistringToStream(Data, BoolToStr(AField.ServerAutoRefresh,True));
WriteAnsistringToStream(Data, 'ServerCalculated');
WriteAnsistringToStream(Data, BoolToStr(AField.ServerCalculated,True));
WriteAnsistringToStream(Data, 'Size');
WriteAnsistringToStream(Data, IntToStr(AField.Size));
WriteAnsistringToStream(Data, 'Visible');
WriteAnsistringToStream(Data, BoolToStr(AField.Visible,True));
end;
procedure TDABin2DataStreamer.WriteParam(const AParam: TDAParam);
begin
WriteAnsistringToStream(Data, 'AsString');
WriteAnsistringToStream(Data, AParam.AsString);
WriteAnsistringToStream(Data, 'BlobType');
WriteAnsistringToStream(Data, TDABlobTypeStrings[AParam.BlobType]);
WriteAnsistringToStream(Data, 'DataType');
WriteAnsistringToStream(Data, TDADataTypeStrings[AParam.DataType]);
WriteAnsistringToStream(Data, 'DecimalPrecision');
WriteAnsistringToStream(Data, IntToStr(AParam.DecimalPrecision));
WriteAnsistringToStream(Data, 'DecimalScale');
WriteAnsistringToStream(Data, IntToStr(AParam.DecimalScale));
WriteAnsistringToStream(Data, 'Description');
WriteAnsistringToStream(Data, AParam.Description);
WriteAnsistringToStream(Data, 'GeneratorName');
WriteAnsistringToStream(Data, AParam.GeneratorName);
WriteAnsistringToStream(Data, 'Name');
WriteAnsistringToStream(Data, AParam.Name);
WriteAnsistringToStream(Data, 'ParamType');
WriteAnsistringToStream(Data, TDAParamTypeStrings[AParam.ParamType]);
WriteAnsistringToStream(Data, 'Size');
WriteAnsistringToStream(Data, IntToStr(AParam.Size));
WriteAnsistringToStream(Data, 'Value');
WriteAnsistringToStream(Data, VarToStr(AParam.Value));
end;
procedure TDABin2DataStreamer.ReadParam(const AParam: TDAParam; const aParamPropertiesCount: integer);
var
i: integer;
sName,sValue: string;
begin
For i := 0 to aParamPropertiesCount-1 do begin
sName := ReadAnsistringFromStream(Data);
sValue := ReadAnsistringFromStream(Data);
if sName = 'AsString' then AParam.AsString:= sValue
else if sName = 'BlobType' then AParam.BlobType := TDABlobTypeStringsToTDABlobType(sValue)
else if sName = 'DataType' then AParam.DataType := TDADataTypeStringsToTDADataType(sValue)
else if sName = 'DecimalPrecision' then AParam.DecimalPrecision := StrToInt(sValue)
else if sName = 'DecimalScale' then AParam.DecimalScale := StrToInt(sValue)
else if sName = 'Description' then AParam.Description := sValue
else if sName = 'GeneratorName' then AParam.GeneratorName := sValue
else if sName = 'Name' then AParam.Name := sValue
else if sName = 'ParamType' then AParam.ParamType := TDAParamTypeStringsToTDAParamType(sValue)
else if sName = 'Size' then AParam.Size := StrToInt(sValue)
else if sName = 'Value' then AParam.Value := sValue
else ;
end;
end;
procedure TDABin2DataStreamer.ReadField(const AField: TDAField;
const aFieldPropertiesCount: integer);
var
i: integer;
sName,sValue: string;
begin
For i := 0 to aFieldPropertiesCount-1 do begin
sName := ReadAnsistringFromStream(Data);
sValue := ReadAnsistringFromStream(Data);
if sName = 'Alignment' then AField.Alignment := TAlignmentStringsToTAlignment(sValue)
else if sName = 'BlobType' then AField.BlobType := TDABlobTypeStringsToTDABlobType(sValue)
else if sName = 'BusinessClassID' then AField.BusinessClassID := sValue
else if sName = 'Calculated' then AField.Calculated := StrToBool(sValue)
else if sName = 'CustomAttributes' then AField.CustomAttributes.Text := sValue
else if sName = 'DataType' then AField.DataType := TDADataTypeStringsToTDADataType(sValue)
else if sName = 'DecimalPrecision' then AField.DecimalPrecision := StrToInt(sValue)
else if sName = 'DecimalScale' then AField.DecimalScale := StrToInt(sValue)
else if sName = 'DefaultValue' then AField.DefaultValue := sValue
else if sName = 'Description' then AField.Description := sValue
else if sName = 'DictionaryEntry' then AField.DictionaryEntry := sValue
else if sName = 'DisplayFormat' then AField.DisplayFormat := sValue
else if sName = 'DisplayLabel' then AField.DisplayLabel := sValue
else if sName = 'DisplayWidth' then AField.DisplayWidth := StrToInt(sValue)
else if sName = 'EditFormat' then AField.EditFormat := sValue
else if sName = 'EditMask' then AField.EditMask := sValue
else if sName = 'Expression' then AField.Expression := sValue
else if sName = 'GeneratorName' then AField.GeneratorName := sValue
else if sName = 'InPrimaryKey' then AField.InPrimaryKey := StrToBool(sValue)
else if sName = 'KeyFields' then AField.KeyFields := sValue
else if sName = 'LogChanges' then AField.LogChanges := StrToBool(sValue)
else if sName = 'Lookup' then AField.Lookup := StrToBool(sValue)
else if sName = 'LookupCache' then AField.LookupCache := StrToBool(sValue)
else if sName = 'LookupKeyFields' then AField.LookupKeyFields := sValue
else if sName = 'LookupResultField' then AField.LookupResultField := sValue
else if sName = 'LookupSource' then // AField.LookupSource:=nil;
else if sName = 'Name' then AField.Name := sValue
else if sName = 'ReadOnly' then AField.ReadOnly := StrToBool(sValue)
else if sName = 'RegExpression' then AField.RegExpression := sValue
else if sName = 'Required' then AField.Required := StrToBool(sValue)
else if sName = 'ServerAutoRefresh' then AField.ServerAutoRefresh := StrToBool(sValue)
else if sName = 'ServerCalculated' then AField.ServerCalculated := StrToBool(sValue)
else if sName = 'Size' then AField.Size := StrToInt(sValue)
else if sName = 'Visible' then AField.Visible := StrToBool(sValue)
else ;
end;
end;
end.