git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.SDAC@3 6f543ec7-021b-7e4c-98c9-62eafc7fb9a8
696 lines
21 KiB
ObjectPascal
696 lines
21 KiB
ObjectPascal
//////////////////////////////////////////////////
|
|
// DB Access Components
|
|
// Copyright © 1998-2007 Core Lab. All right reserved.
|
|
// DB Access
|
|
//////////////////////////////////////////////////
|
|
{$IFNDEF CLR}
|
|
|
|
{$I Dac.inc}
|
|
|
|
unit CRBatchMove;
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF VER6P}
|
|
Variants,
|
|
{$ENDIF}
|
|
Classes, DB, DBAccess, SysUtils;
|
|
|
|
type
|
|
TCRBatchMode = (bmAppend, bmUpdate, bmAppendUpdate, bmDelete);
|
|
|
|
TCRBatchMoveProgressEvent = procedure (Sender: TObject; Percent: integer) of object;
|
|
TDALocate = function: boolean of object;
|
|
|
|
TCRFieldMappingMode = (mmFieldIndex, mmFieldName);
|
|
|
|
TCRBatchMove = class(TComponent)
|
|
private
|
|
FFldDestKeys: TFieldArray;
|
|
FStrDestKeys: string;
|
|
FSrcKeyFields: array of TField;
|
|
FDestKeyFields: array of boolean;
|
|
FKeyValues: array of Variant;
|
|
FFieldMap: array of word;
|
|
FPSDestination: IProviderSupport;
|
|
Locate: TDALocate;
|
|
procedure SetMappings(Value: TStrings);
|
|
procedure SetSource(Value: TDataSet);
|
|
procedure SetDestination(Value: TDataSet);
|
|
function GetProviderSupport(DataSet: TDataSet): IProviderSupport;
|
|
function LocateForCustomDaDataSet: boolean;
|
|
function LocateForDataSet: boolean;
|
|
|
|
protected
|
|
FDestination: TDataSet;
|
|
FSource: TDataSet;
|
|
FMode: TCRBatchMode;
|
|
FAbortOnKeyViol: boolean;
|
|
FAbortOnProblem: boolean;
|
|
FRecordCount: Longint;
|
|
FMovedCount: Longint;
|
|
FKeyViolCount: Longint;
|
|
FProblemCount: Longint;
|
|
FChangedCount: Longint;
|
|
FMappings: TStrings;
|
|
FFieldMappingMode: TCRFieldMappingMode;
|
|
FCommitCount: integer;
|
|
FOnBatchMoveProgress: TCRBatchMoveProgressEvent;
|
|
FTransactionNeeds: boolean;
|
|
FAppliedCount: Longint;
|
|
FDestCountKeys: word;
|
|
|
|
procedure DoBatchMoveProgress(Percent: integer);
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
function GetKeyValues: Variant;
|
|
procedure SetFieldsValues(SetKeyFields: boolean);
|
|
procedure Append;
|
|
procedure Update;
|
|
procedure AppendUpdate;
|
|
procedure Delete;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Execute;
|
|
|
|
property ChangedCount: Longint read FChangedCount;
|
|
property KeyViolCount: Longint read FKeyViolCount;
|
|
property MovedCount: Longint read FMovedCount;
|
|
property ProblemCount: Longint read FProblemCount;
|
|
published
|
|
property AbortOnKeyViol: boolean read FAbortOnKeyViol write FAbortOnKeyViol default True;
|
|
property AbortOnProblem: boolean read FAbortOnProblem write FAbortOnProblem default True;
|
|
property CommitCount: integer read FCommitCount write FCommitCount default 0;
|
|
property Destination: TDataSet read FDestination write SetDestination;
|
|
property Mappings: TStrings read FMappings write SetMappings;
|
|
property FieldMappingMode: TCRFieldMappingMode read FFieldMappingMode write FFieldMappingMode default mmFieldIndex;
|
|
property Mode: TCRBatchMode read FMode write FMode default bmAppend;
|
|
property RecordCount: Longint read FRecordCount write FRecordCount default 0;
|
|
property Source: TDataSet read FSource write SetSource;
|
|
property OnBatchMoveProgress: TCRBatchMoveProgressEvent read FOnBatchMoveProgress write FOnBatchMoveProgress;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF VER6P}
|
|
StrUtils,
|
|
{$ENDIF}
|
|
{$IFDEF CLR}
|
|
System.Xml, System.Runtime.InteropServices,
|
|
{$ELSE}
|
|
CLRClasses,
|
|
{$ENDIF}
|
|
CRParser, DAConsts, MemData, MemDS;
|
|
|
|
{ TCRBatchMove }
|
|
|
|
constructor TCRBatchMove.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
FAbortOnKeyViol := True;
|
|
FAbortOnProblem := True;
|
|
FCommitCount := 0;
|
|
FMode := bmAppend;
|
|
FMappings := TStringList.Create;
|
|
FFieldMappingMode := mmFieldIndex;
|
|
end;
|
|
|
|
destructor TCRBatchMove.Destroy;
|
|
begin
|
|
Source := nil;
|
|
Destination := nil;
|
|
FMappings.Free;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCRBatchMove.SetSource(Value: TDataSet);
|
|
begin
|
|
if FSource <> Value then begin
|
|
if FSource <> nil then
|
|
FSource.RemoveFreeNotification(Self);
|
|
FSource := Value;
|
|
if FSource <> nil then
|
|
FSource.FreeNotification(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TCRBatchMove.SetDestination(Value: TDataSet);
|
|
begin
|
|
if FDestination <> Value then begin
|
|
if FDestination <> nil then
|
|
FDestination.RemoveFreeNotification(Self);
|
|
FDestination := Value;
|
|
if FDestination <> nil then
|
|
FDestination.FreeNotification(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TCRBatchMove.SetMappings(Value: TStrings);
|
|
begin
|
|
FMappings.Assign(Value);
|
|
end;
|
|
|
|
procedure TCRBatchMove.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
|
|
if Operation = opRemove then
|
|
begin
|
|
if Destination = AComponent then
|
|
Destination := nil;
|
|
if Source = AComponent then
|
|
Source := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TCRBatchMove.DoBatchMoveProgress(Percent: integer);
|
|
begin
|
|
if Assigned(FOnBatchMoveProgress) then
|
|
FOnBatchMoveProgress(Self, Percent);
|
|
end;
|
|
|
|
function TCRBatchMove.GetProviderSupport(DataSet: TDataSet): IProviderSupport;
|
|
begin
|
|
Result := nil;
|
|
if DataSet <> nil then
|
|
Result := IProviderSupport(DataSet);
|
|
end;
|
|
|
|
function TCRBatchMove.GetKeyValues: Variant;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to FDestCountKeys - 1 do begin
|
|
if FSrcKeyFields[i] <> nil then
|
|
FKeyValues[i] := FSrcKeyFields[i].AsVariant
|
|
else
|
|
FKeyValues[i] := ''
|
|
end;
|
|
|
|
if FDestCountKeys > 1 then
|
|
Result := VarArrayOf(FKeyValues)
|
|
else
|
|
if FDestCountKeys > 0 then
|
|
Result := FKeyValues[0]
|
|
else
|
|
Result := Null;
|
|
end;
|
|
|
|
procedure TCRBatchMove.SetFieldsValues(SetKeyFields: boolean);
|
|
var
|
|
fn: integer;
|
|
SrcField, DestField: TField;
|
|
SrcFieldDesc, DestFieldDesc: TFieldDesc;
|
|
SrcBlob, DestBlob: TBlob;
|
|
SkipNulls: boolean;
|
|
bs: TStringStream;
|
|
SrcStream, DestStream: TStream;
|
|
SrcPtr: IntPtr;
|
|
Optimization: Boolean;
|
|
{$IFDEF CLR}
|
|
Data: TBytes;
|
|
{$ENDIF}
|
|
begin
|
|
SkipNulls := (Mode = bmAppend) or (Mode = bmAppend) and SetKeyFields;
|
|
for fn := 0 to Destination.FieldCount - 1 do begin
|
|
if (FFieldMap[fn] = 0) or (not Destination.Fields[fn].CanModify) or
|
|
(FDestKeyFields[fn] and (not SetkeyFields)) or
|
|
Source.Fields[FFieldMap[fn] - 1].IsNull and SkipNulls then
|
|
Continue;
|
|
|
|
SrcField := Source.Fields[FFieldMap[fn] - 1];
|
|
Assert(SrcField <> nil);
|
|
DestField := Destination.Fields[fn];
|
|
Assert(DestField <> nil);
|
|
|
|
try
|
|
if SrcField.IsNull then
|
|
DestField.Clear
|
|
else
|
|
case DestField.DataType of
|
|
ftString, ftFixedChar:
|
|
case SrcField.DataType of
|
|
ftMemo, ftFmtMemo{$IFDEF VER10P}, ftWideMemo{$ENDIF}: begin
|
|
Assert(SrcField is TBlobField);
|
|
bs := TStringStream.Create('');
|
|
try
|
|
TBlobField(SrcField).SaveToStream(bs);
|
|
DestField.AsString := bs.DataString;
|
|
finally
|
|
bs.Free;
|
|
end;
|
|
end;
|
|
else
|
|
DestField.AsString := SrcField.AsString;
|
|
end;
|
|
ftWideString{$IFDEF VER10P}, ftFixedWideChar{$ENDIF}:
|
|
case SrcField.DataType of
|
|
ftMemo, ftFmtMemo{$IFDEF VER10P}, ftWideMemo{$ENDIF}: begin
|
|
Assert(SrcField is TBlobField);
|
|
bs := TStringStream.Create('');
|
|
try
|
|
TBlobField(SrcField).SaveToStream(bs);
|
|
Assert(DestField is TWideStringField);
|
|
TWideStringField(DestField).Value := bs.DataString;
|
|
finally
|
|
bs.Free;
|
|
end;
|
|
end;
|
|
ftWideString{$IFDEF VER10P}, ftFixedWideChar{$ENDIF}: begin
|
|
Assert(SrcField is TWideStringField);
|
|
Assert(DestField is TWideStringField);
|
|
TWideStringField(DestField).Value := TWideStringField(SrcField).Value;
|
|
end
|
|
else
|
|
DestField.AsString := SrcField.AsString;
|
|
end;
|
|
ftSmallint, ftInteger, ftWord, ftAutoInc:
|
|
DestField.AsInteger := SrcField.AsInteger;
|
|
ftLargeint: begin
|
|
Assert(DestField is TLargeIntField);
|
|
case SrcField.DataType of
|
|
ftLargeInt:
|
|
TLargeIntField(DestField).AsLargeInt := TLargeIntField(SrcField).AsLargeInt;
|
|
else
|
|
{$IFDEF VER6P}
|
|
TLargeIntField(DestField).AsLargeInt := SrcField.AsVariant;
|
|
{$ELSE}
|
|
DestField.AsString := SrcField.AsString;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
ftBoolean:
|
|
DestField.AsBoolean := SrcField.AsBoolean;
|
|
ftFloat:
|
|
DestField.AsFloat := SrcField.AsFloat;
|
|
ftCurrency, ftBCD:
|
|
DestField.AsCurrency := SrcField.AsCurrency;
|
|
{$IFDEF VER6P}
|
|
ftTimeStamp:
|
|
DestField.AsSQLTimeStamp := SrcField.AsSQLTimeStamp;
|
|
ftFMTBCD:
|
|
DestField.AsCurrency := SrcField.AsCurrency;
|
|
{$ENDIF}
|
|
ftDate, ftTime, ftDateTime:
|
|
DestField.AsDateTime := SrcField.AsDateTime;
|
|
ftBytes, ftVarBytes:
|
|
DestField.AsVariant := SrcField.AsVariant;
|
|
ftBlob, ftOraBlob, ftOraClob: begin
|
|
DestStream := nil;
|
|
try
|
|
if SrcField is TBlobField then begin
|
|
Optimization := False;
|
|
if (SrcField.DataSet is TMemDataSet) and (DestField.DataSet is TMemDataSet) then begin
|
|
// TCustomDADataSet optimization
|
|
SrcFieldDesc := TMemDataSet(SrcField.DataSet).GetFieldDesc(SrcField);
|
|
DestFieldDesc := TMemDataSet(SrcField.DataSet).GetFieldDesc(SrcField);
|
|
if SrcFieldDesc.DataType = DestFieldDesc.DataType then begin
|
|
SrcBlob := TMemDataSet(SrcField.DataSet).GetBlob(SrcField);
|
|
DestBlob := TMemDataSet(DestField.DataSet).GetBlob(DestField);
|
|
if SrcBlob.ClassType = DestBlob.ClassType then begin
|
|
{$IFDEF HAVE_COMPRESS}
|
|
if (SrcField.DataSet is TCustomDADataSet) and (DestField.DataSet is TCustomDADataSet) then
|
|
Optimization := TCustomDADataSet(SrcField.DataSet).Options.CompressBlobMode = TCustomDADataSet(DestField.DataSet).Options.CompressBlobMode
|
|
else
|
|
Optimization := True;
|
|
{$ENDIF}
|
|
if Optimization then begin
|
|
TBlobUtils.SetModified(SrcBlob, True);
|
|
TMemDSUtils.SetBlob(TMemDataSet(DestField.DataSet), DestField, SrcBlob);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if not Optimization then begin
|
|
DestStream := DestField.DataSet.CreateBlobStream(DestField, bmWrite);
|
|
SrcStream := SrcField.DataSet.CreateBlobStream(SrcField, bmRead);
|
|
try
|
|
DestStream.CopyFrom(SrcStream, 0);
|
|
finally
|
|
SrcStream.Free;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if SrcField.DataSize > 0 then begin
|
|
DestStream := DestField.DataSet.CreateBlobStream(DestField, bmWrite);
|
|
SrcPtr := Marshal.AllocHGlobal(SrcField.DataSize);
|
|
try
|
|
SrcField.GetData(SrcPtr);
|
|
{$IFDEF CLR}
|
|
SetLength(Data, SrcField.DataSize);
|
|
Marshal.Copy(SrcPtr, Data, 0, SrcField.DataSize);
|
|
DestStream.ReadBuffer(Data, SrcField.DataSize);
|
|
{$ELSE}
|
|
DestStream.ReadBuffer(SrcPtr^, SrcField.DataSize);
|
|
{$ENDIF}
|
|
finally
|
|
Marshal.FreeHGlobal(SrcPtr);
|
|
end;
|
|
end
|
|
else
|
|
DestField.AsVariant := SrcField.AsVariant;
|
|
finally
|
|
DestStream.Free;
|
|
end;
|
|
end;
|
|
ftMemo{$IFDEF VER10P}, ftWideMemo{$ENDIF}:
|
|
DestField.AsString := SrcField.AsString;
|
|
else
|
|
DestField.AsVariant := SrcField.AsVariant;
|
|
end;
|
|
except
|
|
on Exception do begin
|
|
Inc(FProblemCount);
|
|
if FAbortOnProblem then
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
function TCRBatchMove.LocateForCustomDaDataSet: boolean;
|
|
begin
|
|
Result := TCustomDADataSet(Destination).Locate(FFldDestKeys, GetKeyValues, []);
|
|
end;
|
|
|
|
function TCRBatchMove.LocateForDataSet: boolean;
|
|
begin
|
|
Result := Destination.Locate(FStrDestKeys, GetKeyValues, []);
|
|
end;
|
|
|
|
procedure TCRBatchMove.Append;
|
|
begin
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSStartTransaction;
|
|
|
|
Destination.Append;
|
|
SetFieldsValues(True);
|
|
Destination.Post;
|
|
|
|
Inc(FAppliedCount);
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSEndTransaction(True);
|
|
end;
|
|
|
|
procedure TCRBatchMove.Update;
|
|
begin
|
|
if Locate then begin
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSStartTransaction;
|
|
|
|
Destination.Edit;
|
|
SetFieldsValues(False);
|
|
Destination.Post;
|
|
Inc(FChangedCount);
|
|
|
|
Inc(FAppliedCount);
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSEndTransaction(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TCRBatchMove.AppendUpdate;
|
|
begin
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSStartTransaction;
|
|
|
|
if Locate then begin
|
|
Destination.Edit;
|
|
SetFieldsValues(False);
|
|
Destination.Post;
|
|
Inc(FChangedCount);
|
|
end
|
|
else begin
|
|
Destination.Append;
|
|
SetFieldsValues(True);
|
|
Destination.Post;
|
|
end;
|
|
|
|
Inc(FAppliedCount);
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSEndTransaction(True);
|
|
end;
|
|
|
|
procedure TCRBatchMove.Delete;
|
|
begin
|
|
if Locate then begin
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSStartTransaction;
|
|
|
|
Destination.Delete;
|
|
Inc(FChangedCount);
|
|
|
|
Inc(FAppliedCount);
|
|
if FTransactionNeeds and ((FAppliedCount mod FCommitCount) = 0) then
|
|
FPSDestination.PSEndTransaction(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TCRBatchMove.Execute;
|
|
type
|
|
TAction = procedure of object;
|
|
var
|
|
OldSourceActive, OldDestinationActive: Boolean;
|
|
bookmark: TBookmarkStr;
|
|
DestName, SourceName: string;
|
|
SrcRecCount: integer;
|
|
DestFieldCount: word;
|
|
Action: TAction;
|
|
row: Integer;
|
|
|
|
procedure GetKeyFields;
|
|
var
|
|
i, p1, p2: integer;
|
|
fieldNo: integer;
|
|
KeyFields: TKeyAndDataFields;
|
|
|
|
procedure SetKeyField;
|
|
begin
|
|
FDestKeyFields[fieldNo - 1] := True;
|
|
if FFieldMap[fieldNo - 1] > 0 then
|
|
FSrcKeyFields[FDestCountKeys] := Source.Fields[FFieldMap[fieldNo - 1] - 1]
|
|
else
|
|
FSrcKeyFields[FDestCountKeys] := nil;
|
|
end;
|
|
|
|
begin
|
|
DestFieldCount := Destination.FieldCount;
|
|
SetLength(FSrcKeyFields, DestFieldCount);
|
|
SetLength(FDestKeyFields, DestFieldCount);
|
|
for i := 0 to DestFieldCount - 1 do
|
|
FDestKeyFields[i] := False;
|
|
|
|
FDestCountKeys := 0;
|
|
if Destination is TCustomDADataSet then begin
|
|
TDBAccessUtils.GetKeyAndDataFields(TCustomDADataSet(Destination), KeyFields, True);
|
|
|
|
SetLength(FFldDestKeys, Length(KeyFields.KeyFieldDescs));
|
|
for i := 0 to Length(FFldDestKeys) - 1 do begin
|
|
FFldDestKeys[i] := TCustomDADataSet(Destination).GetField(KeyFields.KeyFieldDescs[i]);
|
|
fieldNo := KeyFields.KeyFieldDescs[i].FieldNo;
|
|
SetKeyField;
|
|
Inc(FDestCountKeys);
|
|
end;
|
|
end
|
|
else begin
|
|
FStrDestKeys := FPSDestination.PSGetKeyFields;
|
|
p1 := 1;
|
|
p2 := Pos(';', FStrDestKeys);
|
|
while p2 > 0 do begin
|
|
fieldNo := Destination.FieldByName(Copy(FStrDestKeys, p1, p2 - 1)).FieldNo;
|
|
SetKeyField;
|
|
Inc(FDestCountKeys);
|
|
p1 := p2 + 1;
|
|
p2 := PosEx(';', FStrDestKeys, p1);
|
|
end;
|
|
|
|
if Length(FStrDestKeys) > 0 then begin
|
|
fieldNo := Destination.FieldByName(Copy(FStrDestKeys, p1, Length(FStrDestKeys))).FieldNo;
|
|
SetKeyField;
|
|
Inc(FDestCountKeys);
|
|
end;
|
|
end;
|
|
|
|
SetLength(FSrcKeyFields, FDestCountKeys);
|
|
SetLength(FKeyValues, FDestCountKeys);
|
|
end;
|
|
|
|
procedure GetMappingNames(num: integer);
|
|
var
|
|
p: Integer;
|
|
Mapping: string;
|
|
begin
|
|
Mapping := FMappings[num];
|
|
p := Pos('=', Mapping);
|
|
if p > 0 then begin
|
|
DestName := Copy(Mapping, 1, p - 1);
|
|
SourceName := Copy(Mapping, p + 1, 255);
|
|
end
|
|
else begin
|
|
DestName := Mapping;
|
|
SourceName := Mapping;
|
|
end;
|
|
end;
|
|
|
|
procedure SetMapping;
|
|
var
|
|
i: integer;
|
|
SrcField, DestField: TField;
|
|
begin
|
|
DestFieldCount := Destination.FieldCount;
|
|
SetLength(FFieldMap, DestFieldCount);
|
|
// SetLength(FFieldComp, DestFieldCount);
|
|
|
|
if FMappings.Count <> 0 then
|
|
begin
|
|
for i := 0 to DestFieldCount - 1 do
|
|
FFieldMap[i] := 0;
|
|
|
|
for i := 0 to FMappings.Count - 1 do begin
|
|
GetMappingNames(i);
|
|
SrcField := Source.FindField(SourceName);
|
|
if SrcField = nil then
|
|
raise Exception.Create(SCannotFindField + ' ' + SourceName);
|
|
DestField := Destination.FindField(DestName);
|
|
if DestField = nil then
|
|
raise Exception.Create(SCannotFindField + ' ' + DestName);
|
|
FFieldMap[DestField.Index] := SrcField.Index + 1;
|
|
end;
|
|
end
|
|
else
|
|
case FFieldMappingMode of
|
|
mmFieldIndex:
|
|
for i := 0 to DestFieldCount - 1 do
|
|
if i < Source.FieldCount then
|
|
FFieldMap[i] := i + 1
|
|
else
|
|
FFieldMap[i] := 0;
|
|
mmFieldName:
|
|
for i := 0 to DestFieldCount - 1 do begin
|
|
SrcField := Source.FindField(Destination.Fields[i].FieldName);
|
|
if SrcField <> nil then
|
|
FFieldMap[i] := SrcField.Index + 1
|
|
else
|
|
FFieldMap[i] := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
IsKeyViolation: boolean;
|
|
|
|
begin
|
|
if (Destination = nil) or (Source = nil) or (Destination = Source) then
|
|
DatabaseError(SInvalidBatchMove, Self);
|
|
OldSourceActive := Source.Active;
|
|
OldDestinationActive := Destination.Active;
|
|
try
|
|
Source.DisableControls;
|
|
Destination.DisableControls;
|
|
Source.Open;
|
|
Source.CheckBrowseMode;
|
|
Source.UpdateCursorPos;
|
|
Destination.Open;
|
|
Destination.CheckBrowseMode;
|
|
Source.CursorPosChanged;
|
|
FChangedCount := 0;
|
|
FKeyViolCount := 0;
|
|
FProblemCount := 0;
|
|
FMovedCount := 0;
|
|
FAppliedCount := 0;
|
|
|
|
FPSDestination := GetProviderSupport(Destination);
|
|
if Destination is TCustomDADataSet then
|
|
Locate := LocateForCustomDaDataSet
|
|
else
|
|
Locate := LocateForDataSet;
|
|
|
|
SetMapping;
|
|
GetKeyFields;
|
|
SrcRecCount := Source.RecordCount;
|
|
|
|
FTransactionNeeds := (not FPSDestination.PSInTransaction) and (FCommitCount > 0);
|
|
if FRecordCount = 0 then begin
|
|
bookmark := Source.Bookmark;
|
|
Source.First;
|
|
end;
|
|
|
|
Action := nil;
|
|
case FMode of
|
|
bmAppend:
|
|
Action := Append;
|
|
bmUpdate:
|
|
Action := Update;
|
|
bmAppendUpdate:
|
|
Action := AppendUpdate;
|
|
bmDelete:
|
|
Action := Delete;
|
|
else
|
|
Assert(False);
|
|
end;
|
|
|
|
try
|
|
for row := 0 to SrcRecCount - 1 do begin
|
|
try
|
|
if (FRecordCount >= FAppliedCount) and (FRecordCount > 0) then
|
|
Exit;
|
|
Inc(FMovedCount);
|
|
|
|
Action;
|
|
except
|
|
on E: EDatabaseError do begin
|
|
Destination.Cancel;
|
|
|
|
if not (Destination is TCustomDADataSet) then
|
|
IsKeyViolation := True
|
|
else
|
|
if E is EDAError then
|
|
IsKeyViolation := TDBAccessUtils.IsKeyViolation(TCustomDADataSet(Destination).Connection, EDAError(E))
|
|
else
|
|
IsKeyViolation := False;
|
|
|
|
if IsKeyViolation then begin
|
|
Inc(FKeyViolCount);
|
|
if FAbortOnKeyViol or (FMode = bmDelete) then begin
|
|
if FTransactionNeeds then
|
|
FPSDestination.PSEndTransaction(False);
|
|
raise;
|
|
end;
|
|
end
|
|
else
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
DoBatchMoveProgress(Round((row * 100) / SrcRecCount));
|
|
Source.Next;
|
|
end;
|
|
|
|
finally
|
|
if FTransactionNeeds and FPSDestination.PSInTransaction then
|
|
FPSDestination.PSEndTransaction(True);
|
|
end;
|
|
|
|
finally
|
|
if FRecordCount = 0 then
|
|
Source.Bookmark := bookmark;
|
|
if OldDestinationActive then
|
|
Destination.First;
|
|
Destination.Active := OldDestinationActive;
|
|
Source.Active := OldSourceActive;
|
|
Destination.EnableControls;
|
|
Source.EnableControls;
|
|
end;
|
|
end;
|
|
|
|
end.
|