123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- unit fpdbfexport;
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2022 by Michael van Canney and other members of the
- Free Pascal development team
- dbf Export code
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, db, dbf, fpdbexport;
-
- Type
- { TDBFExportFieldItem }
- TDBFExportFieldItem = Class(TExportFieldItem)
- private
- FDestField: TField;
- Protected
- Property DestField : TField Read FDestField;
- end;
- { TDBFExportFormatSettings }
- TTableFormat = (tfDBaseIII,tfDBaseIV,tfDBaseVII,tfFoxPro,tfVisualFoxPro);
-
- TDBFExportFormatSettings = class(TExportFormatSettings)
- private
- FAutoRename: Boolean;
- FTableFormat: TTableFormat;
- public
- Procedure Assign(Source : TPersistent); override;
- Procedure InitSettings; override;
- Published
- Property TableFormat : TTableFormat Read FTableFormat Write FTableFormat;
- Property AutoRenameFields : Boolean Read FAutoRename Write FAutoRename;
- end;
- { TFPCustomDBFExport }
- TFPCustomDBFExport = Class(TCustomDatasetExporter)
- Private
- FDBF : TDBF;
- FFileName: String;
- FAppendData: Boolean;
- function GetSettings: TDBFExportFormatSettings;
- procedure SetSettings(const AValue: TDBFExportFormatSettings);
- Protected
- Procedure CheckExportFieldName(ThisExportField: TExportFieldItem; const MaxFieldNameLength: integer);
- Function BindFields : Boolean; override;
- Function CreateFormatSettings : TCustomExportFormatSettings; override;
- Function CreateExportFields : TExportFields; override;
- Procedure DoBeforeExecute; override;
- Procedure DoAfterExecute; override;
- Procedure DoDataRowStart; override;
- Procedure DoDataRowEnd; override;
- Procedure ExportField(EF : TExportFieldItem); override;
- Property FileName : String Read FFileName Write FFileName;
- Property AppendData : Boolean Read FAppendData Write FAppendData;
- Property DBF : TDBF Read FDBF;
- public
- Property FormatSettings : TDBFExportFormatSettings Read GetSettings Write SetSettings;
- end;
- TFPDBFExport = Class(TFPCustomDBFExport)
- Published
- Property FileName;
- Property Dataset;
- Property ExportFields;
- Property FromCurrent;
- Property RestorePosition;
- Property FormatSettings;
- Property OnExportRow;
- end;
-
- Procedure RegisterDBFExportFormat;
- Procedure UnRegisterDBFExportFormat;
- Const
- SDBFExport = 'DBF';
- SDBFFilter = '*.dbf';
-
- ResourceString
- SErrFailedToDeleteFile = 'Failed to delete existing DBF file: %s';
- SDBFDescription = 'DBF files';
- implementation
- { TFPCustomDBFExport }
- function TFPCustomDBFExport.GetSettings: TDBFExportFormatSettings;
- begin
- Result:=TDBFExportFormatSettings(Inherited FormatSettings);
- end;
- procedure TFPCustomDBFExport.SetSettings(const AValue: TDBFExportFormatSettings
- );
- begin
- Inherited FormatSettings.Assign(AValue);
- end;
- procedure TFPCustomDBFExport.CheckExportFieldName(ThisExportField: TExportFieldItem; const MaxFieldNameLength: integer);
- // Cut off field name at max length, and rename if it already exists
- Const
- CounterInvalid=100;
- Var
- NameCounter : Integer;
- NewFieldName : String;
-
- begin
- If (Length(ThisExportField.ExportedName)>MaxFieldNameLength) then
- begin
- NewFieldName:=Copy(ThisExportField.ExportedName,1,MaxFieldNameLength);
- If ExportFields.IndexOfExportedName(NewFieldName)<>-1 then
- begin
- // Try using 2-character number sequence to generate unique name
- NameCounter:=1;
- Repeat
- NewFieldName:=Copy(ThisExportField.ExportedName,1,MaxFieldNameLength-2)+Format('%.2d',[NameCounter]);
- Until (ExportFields.IndexOfExportedName(NewFieldName)=-1) or (NameCounter=CounterInvalid);
- if NameCounter=CounterInvalid then
- ExportError('Could not create a unique export field name for field %s',[ThisExportField.FieldName]);
- end;
- ThisExportField.ExportedName:=NewFieldName;
- end;
- end;
- function TFPCustomDBFExport.BindFields: Boolean;
- Const
- // Translate tableformat to tablelevel
- Levels : Array[TTableFormat] of integer = (3,4,7,25,30);
-
- Var
- EF : TDBFExportFieldItem;
- i : Integer;
- MaxFieldName: integer;
- begin
- Result:=Inherited;
- // DBase III,IV, and FoxPro have a 10 character field length limit.
- // Visual Foxpro free tables (without .dbc file) also
- // DBase VII has a 32 character field length limit.
- if (FormatSettings.TableFormat=tfDbaseVII) then
- MaxFieldName:=32
- else
- MaxFieldName:=10;
- try
- with FDBF.FieldDefs do
- begin
- Clear;
- For i:=0 to ExportFields.Count-1 do
- begin
- EF:=ExportFields[i] as TDBFExportFieldItem;
- If FormatSettings.AutoRenameFields then
- CheckExportFieldName(EF,MaxFieldName);
- If EF.Enabled and Assigned(EF.Field) then
- Add(EF.ExportedName,EF.Field.DataType,EF.Field.Size);
- end;
- FDBF.TableLevel:=Levels[FormatSettings.TableFormat];
- FDBF.CreateTable;
- FDBF.Exclusive := true;
- FDBF.Open;
- end;
- For i:=0 to ExportFields.Count-1 do
- begin
- EF:=ExportFIelds[i] as TDBFExportFieldItem;
- If EF.Enabled then
- EF.FDestField:=FDBF.FieldByName(EF.ExportedName);
- end;
- except
- UnBindFields;
- Raise;
- end;
- end;
- function TFPCustomDBFExport.CreateFormatSettings: TCustomExportFormatSettings;
- begin
- Result:=TDBFExportFormatSettings.Create(True);
- end;
- function TFPCustomDBFExport.CreateExportFields: TExportFields;
- begin
- Result:=TExportFields.Create(TDBFExportFieldItem);
- end;
- procedure TFPCustomDBFExport.DoBeforeExecute;
- Var
- FE : Boolean;
-
- begin
- Inherited;
- FDBF:=TDBF.Create(Self);
- FDBF.TableName:=FFileName;
- FDBF.DefaultBufferCount:=2;
- FE:=FileExists(FFileName);
- If FAppendData and FE then
- FDBF.Open
- else
- begin
- If FE and Not AppendData then
- begin
- If not DeleteFile(FFileName) then
- Raise EDataExporter.CreateFmt(SErrFailedToDeleteFile,[FFileName]);
- end;
- end;
- end;
- procedure TFPCustomDBFExport.DoAfterExecute;
- begin
- try
- FreeAndNil(FDBF);
- finally
- Inherited;
- end;
- end;
- procedure TFPCustomDBFExport.DoDataRowStart;
- begin
- FDBF.Append;
- end;
- procedure TFPCustomDBFExport.DoDataRowEnd;
- begin
- FDBF.Post;
- end;
- procedure TFPCustomDBFExport.ExportField(EF: TExportFieldItem);
- Var
- F : TDBFExportFieldItem;
-
- begin
- F:=EF as TDBFExportFieldItem;
- With F do
- // Export depending on field datatype;
- // convert to dbf data types where necessary.
- // Fall back to string if unknown datatype
- If FIeld.IsNull then
- DestField.Clear
- else if Field.Datatype in (IntFieldTypes+[ftAutoInc,ftLargeInt]) then
- DestField.AsInteger:=Field.AsInteger
- else if Field.Datatype in [ftBCD,ftCurrency,ftFloat,ftFMTBcd] then
- DestField.AsFloat:=Field.AsFloat
- else if Field.DataType in [ftString,ftFixedChar] then
- DestField.AsString:=Field.AsString
- else if (Field.DataType in ([ftWideMemo,ftWideString,ftFixedWideChar]+BlobFieldTypes)) then
- DestField.AsWideString:=Field.AsWideString
- { Note: we test for the wide text fields before the MemoFieldTypes, in order to
- let ftWideMemo end up at the right place }
- else if Field.DataType in MemoFieldTypes then
- DestField.AsString:=Field.AsString
- else if Field.DataType=ftBoolean then
- DestField.AsBoolean:=Field.AsBoolean
- else if field.DataType in DateFieldTypes then
- DestField.AsDatetime:=Field.AsDateTime
- else
- DestField.AsString:=Field.AsString
- end;
- Procedure RegisterDBFExportFormat;
- begin
- RegisterExportFormat(SDBFExport,SDBFDescription,SDBFFilter,TFPDBFExport);
- end;
- Procedure UnRegisterDBFExportFormat;
- begin
- UnregisterExportFormat(SDBFExport);
- end;
- { TDBFExportFormatSettings }
- procedure TDBFExportFormatSettings.Assign(Source: TPersistent);
- Var
- FS : TDBFExportFormatSettings;
-
- begin
- If Source is TDBFExportFormatSettings then
- begin
- FS:=Source as TDBFExportFormatSettings;
- AutoRenameFields:=FS.AutoRenameFields;
- TableFormat:=FS.TableFormat;
- end;
- inherited Assign(Source);
- end;
- procedure TDBFExportFormatSettings.InitSettings;
- begin
- inherited InitSettings;
- FAutoRename:=true; // sensible to avoid duplicate table names
- FTableFormat:=tfDBaseIV; //often used
- end;
- end.
|