You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5438 8e941d3f-bd1b-0410-a28a-d453659cc2b4
576 lines
17 KiB
ObjectPascal
576 lines
17 KiB
ObjectPascal
{*********************************************************}
|
|
{* Progress meter for import operations *}
|
|
{*********************************************************}
|
|
|
|
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is TurboPower FlashFiler
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* TurboPower Software
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
|
|
{$I ffdefine.inc}
|
|
|
|
unit dgimpdo;
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows,
|
|
SysUtils,
|
|
Dialogs,
|
|
Classes,
|
|
DBTables,
|
|
Graphics,
|
|
Forms,
|
|
Controls,
|
|
StdCtrls,
|
|
DB,
|
|
Buttons,
|
|
ExtCtrls,
|
|
Gauges,
|
|
dbconsts,
|
|
bde,
|
|
bdeconst,
|
|
ffllbase,
|
|
ffsrbde,
|
|
ffdb,
|
|
ffdbbase;
|
|
|
|
type
|
|
TdlgImportProgress = class(TForm)
|
|
Bevel1: TBevel;
|
|
lblProgress: TLabel;
|
|
btnCancel: TBitBtn;
|
|
Label1: TLabel;
|
|
Label2: TLabel;
|
|
edtImportFilename: TEdit;
|
|
edtTablename: TEdit;
|
|
guaProgress: TGauge;
|
|
procedure btnCancelClick(Sender: TObject);
|
|
private
|
|
public
|
|
Terminated : Boolean;
|
|
|
|
procedure ShowProgress(aImportFilename, aTableName : string);
|
|
procedure UpdateProgress(aNumRead, aTotalRecs : Longint);
|
|
end;
|
|
|
|
procedure ConvertBDEDataType(aDataType : TFieldType;
|
|
aSize : LongInt;
|
|
var aFFType : TffFieldType;
|
|
var aFFSize : LongInt;
|
|
var aFFDecPl : Integer);
|
|
|
|
function DoImport(aSourceTable : TTable; { Table to copy from }
|
|
aSourceFields : TStringList; { List of field #'s to copy }
|
|
aDestTable : TffTable; { Table to copy to }
|
|
aBlockInserts : SmallInt; { Transaction batch size }
|
|
var aNumTransferred : LongInt): Boolean; { Number of records copied }
|
|
|
|
var
|
|
dlgImportProgress : TdlgImportProgress;
|
|
|
|
implementation
|
|
|
|
{$R *.DFM}
|
|
|
|
uses
|
|
ffclintf,
|
|
fmmain;
|
|
|
|
procedure ConvertBDEDataType(aDataType : TFieldType;
|
|
aSize : LongInt;
|
|
var aFFType : TffFieldType;
|
|
var aFFSize : LongInt;
|
|
var aFFDecPl : Integer);
|
|
begin
|
|
aFFSize := aSize;
|
|
aFFDecPl := 0;
|
|
case aDatatype of
|
|
{$IFDEF DCC4OrLater}
|
|
ftFixedChar,
|
|
{$ENDIF}
|
|
ftString :
|
|
{Begin !!.01}
|
|
if aSize <= 255 then begin
|
|
{Begin !!.11}
|
|
if frmMain.chkUseANSIFields.Checked then begin
|
|
if frmMain.chkUseZeroTerminatedStrings.Checked then
|
|
aFFType := fftNullAnsiStr
|
|
else
|
|
aFFType := fftShortAnsiStr
|
|
end
|
|
else begin
|
|
if frmMain.chkUseZeroTerminatedStrings.Checked then
|
|
aFFType := fftNullString
|
|
else
|
|
aFFType := fftShortString;
|
|
end
|
|
{End !!.11}
|
|
end
|
|
else begin
|
|
if frmMain.chkUseANSIFields.Checked then
|
|
aFFType := fftNullAnsiStr
|
|
else
|
|
aFFType := fftNullString;
|
|
end;
|
|
{End !!.01}
|
|
ftSmallint:
|
|
aFFType := fftInt16;
|
|
ftInteger:
|
|
aFFType := fftInt32;
|
|
ftWord:
|
|
aFFType := fftWord16;
|
|
ftBoolean:
|
|
aFFType := fftBoolean;
|
|
ftFloat:
|
|
aFFType := fftDouble;
|
|
ftCurrency:
|
|
aFFType := fftCurrency;
|
|
ftBCD:
|
|
aFFType := fftDouble;
|
|
ftDate:
|
|
{Begin !!.11}
|
|
if frmMain.chkUseSysToolsDates.Checked then
|
|
aFFType := fftStDate
|
|
else
|
|
aFFType := fftDateTime;
|
|
{End !!.11}
|
|
ftTime:
|
|
{Begin !!.11}
|
|
if frmMain.chkUseSysToolsTimes.Checked then
|
|
aFFType := fftStTime
|
|
else
|
|
aFFType := fftDateTime;
|
|
{End !!.11}
|
|
ftDateTime:
|
|
aFFType := fftDateTime;
|
|
ftBytes,
|
|
ftVarBytes:
|
|
aFFType := fftByteArray;
|
|
ftBlob:
|
|
aFFType := fftBLOB;
|
|
ftMemo:
|
|
aFFType := fftBLOBMemo;
|
|
ftGraphic:
|
|
aFFType := fftBLOBGraphic;
|
|
ftAutoInc:
|
|
aFFType := fftAutoInc;
|
|
ftFmtMemo:
|
|
aFFType := fftBLOBFmtMemo;
|
|
ftParadoxOle,
|
|
ftDBaseOle:
|
|
aFFType := fftBLOBOleObj;
|
|
ftTypedBinary:
|
|
aFFType := fftBLOBTypedBin;
|
|
end;
|
|
end;
|
|
|
|
function DoImport(aSourceTable : TTable;
|
|
aSourceFields : TStringList;
|
|
aDestTable : TffTable;
|
|
aBlockInserts : SmallInt;
|
|
var aNumTransferred : LongInt) : Boolean;
|
|
|
|
resourcestring
|
|
SInvalidFieldKind = 'Invalid Field Conversion %s <- %s';
|
|
var
|
|
FieldNo : Integer;
|
|
DestFieldNo : Integer;
|
|
TotalRecs : Longint;
|
|
DoThisOne : Boolean;
|
|
DoExplicitTrans : Boolean;
|
|
InTransaction : Boolean;
|
|
MaxAutoInc : Integer;
|
|
TempStr : string; {!!.01}
|
|
|
|
procedure CopyField(aDestField, aSourceField : TField);
|
|
var
|
|
Buffer : Pointer;
|
|
Stream : TMemoryStream;
|
|
begin
|
|
{Begin !!.11}
|
|
if aSourceField.IsNull then begin
|
|
if frmMain.chkEmptyStrings.Checked and
|
|
(aSourceField.Datatype = ftString) then
|
|
aDestField.AsString := ''
|
|
else
|
|
aDestField.Clear;
|
|
end
|
|
else
|
|
{End !!.11}
|
|
case aSourceField.Datatype of
|
|
ftBoolean:
|
|
case aDestField.Datatype of
|
|
ftBoolean:
|
|
aDestField.AsBoolean := aSourceField.AsBoolean;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftString:
|
|
case aDestField.Datatype of
|
|
ftString:
|
|
begin
|
|
{Begin !!.11}
|
|
if frmMain.chkClearEmptyStrings.Checked then begin
|
|
TempStr := aSourceField.AsString;
|
|
if TempStr = '' then
|
|
aDestField.Clear
|
|
else
|
|
aDestField.AsString := TempStr;
|
|
end
|
|
else
|
|
aDestField.AsString := aSourceField.AsString;
|
|
{End !!.11}
|
|
{Begin !!.01}
|
|
if frmMain.chkOEMAnsi.Checked and
|
|
(Length(aDestField.AsString) > 0) then begin
|
|
SetLength(TempStr, Length(aDestField.AsString));
|
|
tempStr := aDestField.AsString;
|
|
OEMToCharBuff(PChar(tempStr), PChar(tempStr), Length(aDestField.AsString));
|
|
aDestField.AsString := tempStr;
|
|
end;
|
|
{End !!.01}
|
|
end;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftAutoInc,
|
|
ftSmallint,
|
|
ftInteger,
|
|
ftWord:
|
|
case aDestField.Datatype of
|
|
ftSmallInt,
|
|
ftInteger,
|
|
ftAutoInc,
|
|
ftWord:
|
|
begin
|
|
aDestField.AsInteger := aSourceField.AsInteger;
|
|
if (aDestField.Datatype = ftAutoInc) and
|
|
(aDestField.AsInteger > MaxAutoInc) then
|
|
MaxAutoInc := aDestField.AsInteger;
|
|
end;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftBCD,
|
|
ftFloat,
|
|
ftCurrency:
|
|
case aDestField.Datatype of
|
|
ftFloat,
|
|
ftCurrency:
|
|
aDestField.AsFloat := aSourceField.AsFloat;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftDate:
|
|
case aDestField.Datatype of
|
|
ftDate,
|
|
ftDateTime:
|
|
aDestField.AsDateTime := aSourceField.AsDateTime;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftTime:
|
|
case aDestField.Datatype of
|
|
ftTime,
|
|
ftDateTime:
|
|
aDestField.AsDateTime := aSourceField.AsDateTime;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftDateTime:
|
|
case aDestField.Datatype of
|
|
ftDate,
|
|
ftTime,
|
|
ftDateTime:
|
|
aDestField.AsDateTime := aSourceField.AsDateTime;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
ftBytes,
|
|
ftVarBytes:
|
|
begin
|
|
GetMem(Buffer, aDestField.DataSize);
|
|
try
|
|
case aDestField.Datatype of
|
|
ftBytes,
|
|
ftVarBytes:
|
|
if aSourceField.GetData(Buffer) then
|
|
aDestField.SetData(Buffer)
|
|
else
|
|
aDestField.SetData(nil);
|
|
ftFmtMemo,
|
|
ftParadoxOle,
|
|
ftDBaseOle,
|
|
ftTypedBinary,
|
|
ftMemo,
|
|
ftGraphic,
|
|
ftBlob:
|
|
if not aSourceField.GetData(Buffer) then
|
|
aDestField.SetData(nil)
|
|
else begin
|
|
Stream := TMemoryStream.Create;
|
|
try
|
|
Stream.Write(Buffer^, aSourceField.DataSize);
|
|
TBLOBField(aDestField).LoadFromStream(Stream);
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
finally
|
|
FreeMem(Buffer, aDestField.DataSize);
|
|
end;
|
|
end;
|
|
ftFmtMemo,
|
|
ftParadoxOle,
|
|
ftDBaseOle,
|
|
ftTypedBinary,
|
|
ftMemo,
|
|
ftGraphic,
|
|
ftBlob:
|
|
begin
|
|
case aDestField.Datatype of
|
|
ftFmtMemo,
|
|
ftParadoxOle,
|
|
ftDBaseOle,
|
|
ftTypedBinary,
|
|
ftMemo,
|
|
ftGraphic,
|
|
ftBlob:
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
try
|
|
TBLOBField(aSourceField).SaveToStream(Stream);
|
|
TBLOBField(aDestField).LoadFromStream(Stream);
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
else
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
end;
|
|
ftUnknown:
|
|
DatabaseErrorFmt(SInvalidFieldKind, [aDestField.DisplayName,
|
|
aSourceField.DisplayName]);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result := False;
|
|
with dlgImportProgress do begin
|
|
Terminated := False;
|
|
ShowProgress(aSourceTable.TableName, aDestTable.TableName);
|
|
try
|
|
|
|
{ If we only have one insert per transaction, then let the server
|
|
do implicit transactions; it'll be faster }
|
|
if aBlockInserts = 0 then aBlockInserts := 1;
|
|
DoExplicitTrans := (aBlockInserts > 1);
|
|
|
|
aSourceTable.Open;
|
|
try
|
|
TotalRecs := aSourceTable.RecordCount;
|
|
aNumTransferred := 0;
|
|
|
|
aDestTable.Open;
|
|
if (DoExplicitTrans) then {!!.05}
|
|
DoExplicitTrans := (not aDestTable.Dictionary.HasBLOBFields);{!!.05}
|
|
try
|
|
MaxAutoInc := 0;
|
|
InTransaction := False;
|
|
try
|
|
while not aSourceTable.EOF do begin
|
|
// UpdateProgress(aNumTransferred + 1, TotalRecs); {Deleted !!.01}
|
|
|
|
{ Blocks inserts within a transaction }
|
|
if DoExplicitTrans and not InTransaction then begin
|
|
frmMain.dbDest.StartTransaction;
|
|
InTransaction := True;
|
|
end;
|
|
|
|
aDestTable.Insert;
|
|
|
|
{ Copy fields one at a time }
|
|
for FieldNo := 0 to aSourceTable.FieldCount - 1 do begin
|
|
|
|
{ Do only selected fields }
|
|
DoThisOne := not Assigned(aSourceFields);
|
|
if not DoThisOne then begin
|
|
DoThisOne := aSourceFields.IndexOf(ANSIUppercase(aSourceTable.Fields[FieldNo].FieldName)) <> -1;
|
|
end;
|
|
|
|
if DoThisOne then begin
|
|
|
|
{ Fields might be in order, avoid expensive FieldByName }
|
|
if (FieldNo < aDestTable.FieldCount) and
|
|
(FFCmpShStrUC(aSourceTable.Fields[FieldNo].FieldName,
|
|
aDestTable.Fields[FieldNo].FieldName,
|
|
255) = 0) then
|
|
DestFieldNo := FieldNo
|
|
else begin
|
|
try
|
|
DestFieldNo := aDestTable.FieldByName(aSourceTable.Fields[FieldNo].FieldName).FieldNo - 1;
|
|
except
|
|
DestFieldNo := -1;
|
|
end;
|
|
end;
|
|
|
|
if DestFieldNo <> -1 then
|
|
try
|
|
{Begin !!.11}
|
|
// aDestTable.Fields[DestFieldNo].Assign(aSourceTable.Fields[FieldNo]);
|
|
{Begin !!.01}
|
|
// if frmMain.chkOEMAnsi.Checked and
|
|
// (aDestTable.Fields[DestFieldNo].Datatype = ftString) and
|
|
// (Length(aDestTable.Fields[DestFieldNo].AsString) > 0) then begin
|
|
// SetLength(TempStr, Length(aDestTable.Fields[DestFieldNo].AsString));
|
|
// tempStr := aDestTable.Fields[DestFieldNo].AsString;
|
|
// OEMToCharBuff(PChar(tempStr), PChar(tempStr), Length(aDestTable.Fields[DestFieldNo].AsString));
|
|
// aDestTable.Fields[DestFieldNo].AsString := tempStr;
|
|
// end;
|
|
{End !!.01}
|
|
CopyField(aDestTable.Fields[DestFieldNo], aSourceTable.Fields[FieldNo]);
|
|
{End !!.11}
|
|
if (aDestTable.Fields[DestFieldNo].Datatype = ftAutoInc) and
|
|
(aDestTable.Fields[DestFieldNo].AsInteger > MaxAutoInc) then
|
|
MaxAutoInc := aDestTable.Fields[DestFieldNo].AsInteger;
|
|
except
|
|
on E:EDatabaseError do begin
|
|
CopyField(aDestTable.Fields[DestFieldNo], aSourceTable.Fields[FieldNo]);
|
|
end;
|
|
else
|
|
raise;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
aDestTable.Post;
|
|
Inc(aNumTransferred); { Increment after successfully posting }
|
|
|
|
{ See if it's time to commit the transaction }
|
|
{Begin !!.01}
|
|
if InTransaction then begin
|
|
if ((aNumTransferred mod aBlockInserts) = 0) then begin
|
|
aDestTable.Database.Commit;
|
|
UpdateProgress(aNumTransferred, TotalRecs);
|
|
InTransaction := False;
|
|
end
|
|
end
|
|
else
|
|
UpdateProgress(aNumTransferred + 1, TotalRecs);
|
|
{End !!.01}
|
|
|
|
{ Check for user termination }
|
|
if Terminated then begin
|
|
if InTransaction then
|
|
aDestTable.Database.Rollback;
|
|
Exit;
|
|
end;
|
|
|
|
aSourceTable.Next;
|
|
end;
|
|
|
|
{update the maximum autoinc value for the dest table}
|
|
aDestTable.SetTableAutoIncValue(MaxAutoInc);
|
|
{ Residual inserts need to be posted? }
|
|
if InTransaction then begin {!!.01}
|
|
aDestTable.Database.Commit;
|
|
UpdateProgress(aNumTransferred + 1, TotalRecs); {!!.01}
|
|
end; {!!.01}
|
|
except
|
|
if InTransaction then
|
|
aDestTable.Database.Rollback;
|
|
raise;
|
|
end;
|
|
finally
|
|
aDestTable.Close;
|
|
end;
|
|
finally
|
|
aSourceTable.Close;
|
|
end;
|
|
finally
|
|
Hide;
|
|
end;
|
|
Result := not Terminated;
|
|
end;
|
|
end;
|
|
|
|
procedure TdlgImportProgress.ShowProgress(aImportFilename, aTableName : string);
|
|
begin
|
|
edtImportFilename.Text := aImportFilename;
|
|
edtTablename.Text := aTableName;
|
|
lblProgress.Hide;
|
|
guaProgress.Progress := 0;
|
|
inherited Show;
|
|
Application.ProcessMessages;
|
|
end;
|
|
|
|
procedure TdlgImportProgress.UpdateProgress(aNumRead, aTotalRecs: LongInt);
|
|
var
|
|
Dividend : LongInt;
|
|
Divisor : LongInt;
|
|
resourcestring
|
|
SProgressStatus = 'Processing record %d of %d';
|
|
begin
|
|
with lblProgress do begin
|
|
Caption := Format(SProgressStatus, [aNumRead, aTotalRecs]);
|
|
Show;
|
|
Application.ProcessMessages;
|
|
end;
|
|
|
|
{ Calculate % completed }
|
|
if (aNumRead >= $1000000) then begin
|
|
Dividend := (aNumRead shr 7) * 100;
|
|
Divisor := aTotalRecs shr 7;
|
|
end
|
|
else begin
|
|
Dividend := aNumRead * 100;
|
|
Divisor := aTotalRecs;
|
|
end;
|
|
|
|
if Divisor <> 0 then
|
|
guaProgress.Progress := Dividend div Divisor;
|
|
end;
|
|
|
|
procedure TdlgImportProgress.btnCancelClick(Sender: TObject);
|
|
resourcestring
|
|
SAbortMsg = 'Abort transferring data?';
|
|
begin
|
|
Terminated := MessageDlg(SAbortMsg, mtConfirmation, [mbYes, mbNo], 0) = mrYes;
|
|
end;
|
|
|
|
end.
|