Files
lazarus-ccr/components/flashfiler/sourcelaz/bde2ff/dgimpdo.pas
2016-12-07 13:31:59 +00:00

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.