mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-15 00:09:26 +02:00
* Rework default file mechanism in bufdataset to fix bug #34435
git-svn-id: trunk@43643 -
This commit is contained in:
parent
e28b39e395
commit
76a4638a46
@ -353,7 +353,7 @@ type
|
|||||||
|
|
||||||
{ TDataPacketReader }
|
{ TDataPacketReader }
|
||||||
|
|
||||||
TDataPacketFormat = (dfBinary,dfXML,dfXMLUTF8,dfAny);
|
TDataPacketFormat = (dfBinary,dfXML,dfXMLUTF8,dfAny,dfDefault);
|
||||||
|
|
||||||
TDatapacketReaderClass = class of TDatapacketReader;
|
TDatapacketReaderClass = class of TDatapacketReader;
|
||||||
TDataPacketReader = class(TObject)
|
TDataPacketReader = class(TObject)
|
||||||
@ -564,6 +564,9 @@ type
|
|||||||
Property BufIndexes[Aindex : Integer] : TBufIndex Read GetBufIndex;
|
Property BufIndexes[Aindex : Integer] : TBufIndex Read GetBufIndex;
|
||||||
protected
|
protected
|
||||||
// abstract & virtual methods of TDataset
|
// abstract & virtual methods of TDataset
|
||||||
|
class function DefaultReadFileFormat : TDataPacketFormat; virtual;
|
||||||
|
class function DefaultWriteFileFormat : TDataPacketFormat; virtual;
|
||||||
|
class function DefaultPacketClass : TDataPacketReaderClass ; virtual;
|
||||||
procedure SetPacketRecords(aValue : integer); virtual;
|
procedure SetPacketRecords(aValue : integer); virtual;
|
||||||
procedure SetRecNo(Value: Longint); override;
|
procedure SetRecNo(Value: Longint); override;
|
||||||
function GetRecNo: Longint; override;
|
function GetRecNo: Longint; override;
|
||||||
@ -640,9 +643,9 @@ type
|
|||||||
|
|
||||||
procedure SetDatasetPacket(AReader : TDataPacketReader);
|
procedure SetDatasetPacket(AReader : TDataPacketReader);
|
||||||
procedure GetDatasetPacket(AWriter : TDataPacketReader);
|
procedure GetDatasetPacket(AWriter : TDataPacketReader);
|
||||||
procedure LoadFromStream(AStream : TStream; Format: TDataPacketFormat = dfAny);
|
procedure LoadFromStream(AStream : TStream; Format: TDataPacketFormat = dfDefault);
|
||||||
procedure SaveToStream(AStream : TStream; Format: TDataPacketFormat = dfBinary);
|
procedure SaveToStream(AStream : TStream; Format: TDataPacketFormat = dfBinary);
|
||||||
procedure LoadFromFile(AFileName: string = ''; Format: TDataPacketFormat = dfAny);
|
procedure LoadFromFile(AFileName: string = ''; Format: TDataPacketFormat = dfDefault);
|
||||||
procedure SaveToFile(AFileName: string = ''; Format: TDataPacketFormat = dfBinary);
|
procedure SaveToFile(AFileName: string = ''; Format: TDataPacketFormat = dfBinary);
|
||||||
procedure CreateDataset;
|
procedure CreateDataset;
|
||||||
Procedure Clear; // Will close and remove all field definitions.
|
Procedure Clear; // Will close and remove all field definitions.
|
||||||
@ -738,17 +741,18 @@ var
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
for i := 0 to length(RegisteredDatapacketReaders)-1 do if ((AFormat=dfAny) or (AFormat=RegisteredDatapacketReaders[i].Format)) then
|
for i := 0 to length(RegisteredDatapacketReaders)-1 do
|
||||||
begin
|
if ((AFormat=dfAny) or (AFormat=RegisteredDatapacketReaders[i].Format)) then
|
||||||
if (AStream=nil) or (RegisteredDatapacketReaders[i].ReaderClass.RecognizeStream(AStream)) then
|
|
||||||
begin
|
begin
|
||||||
ADataReaderClass := RegisteredDatapacketReaders[i];
|
if (AStream=nil) or (RegisteredDatapacketReaders[i].ReaderClass.RecognizeStream(AStream)) then
|
||||||
Result := True;
|
begin
|
||||||
if (AStream <> nil) then AStream.Seek(0,soFromBeginning);
|
ADataReaderClass := RegisteredDatapacketReaders[i];
|
||||||
break;
|
Result := True;
|
||||||
|
if (AStream <> nil) then AStream.Seek(0,soFromBeginning);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
AStream.Seek(0,soFromBeginning);
|
||||||
end;
|
end;
|
||||||
AStream.Seek(0,soFromBeginning);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DBCompareText(subValue, aValue: pointer; size: integer; options: TLocateOptions): LargeInt;
|
function DBCompareText(subValue, aValue: pointer; size: integer; options: TLocateOptions): LargeInt;
|
||||||
@ -1431,8 +1435,8 @@ end;
|
|||||||
procedure TCustomBufDataset.DoBeforeClose;
|
procedure TCustomBufDataset.DoBeforeClose;
|
||||||
begin
|
begin
|
||||||
inherited DoBeforeClose;
|
inherited DoBeforeClose;
|
||||||
if FFileName<>'' then
|
if (FFileName<>'') then
|
||||||
SaveToFile(FFileName);
|
SaveToFile(FFileName,dfDefault);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomBufDataset.InternalClose;
|
procedure TCustomBufDataset.InternalClose;
|
||||||
@ -2258,6 +2262,22 @@ begin
|
|||||||
FMaxIndexesCount:=FIndexes.Count+2; // Custom+Default order
|
FMaxIndexesCount:=FIndexes.Count+2; // Custom+Default order
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TCustomBufDataset.DefaultReadFileFormat: TDataPacketFormat;
|
||||||
|
begin
|
||||||
|
Result:=dfAny;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TCustomBufDataset.DefaultWriteFileFormat: TDataPacketFormat;
|
||||||
|
begin
|
||||||
|
Result:=dfBinary;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TCustomBufDataset.DefaultPacketClass: TDataPacketReaderClass;
|
||||||
|
begin
|
||||||
|
Result:=TFpcBinaryDatapacketReader;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TCustomBufDataset.SetIndexFieldNames(const AValue: String);
|
procedure TCustomBufDataset.SetIndexFieldNames(const AValue: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -3056,11 +3076,17 @@ end;
|
|||||||
|
|
||||||
function TCustomBufDataset.GetPacketReader(const Format: TDataPacketFormat; const AStream: TStream): TDataPacketReader;
|
function TCustomBufDataset.GetPacketReader(const Format: TDataPacketFormat; const AStream: TStream): TDataPacketReader;
|
||||||
|
|
||||||
var APacketReader: TDataPacketReader;
|
var
|
||||||
APacketReaderReg: TDatapacketReaderRegistration;
|
APacketReader: TDataPacketReader;
|
||||||
|
APacketReaderReg: TDatapacketReaderRegistration;
|
||||||
|
Fmt : TDataPacketFormat;
|
||||||
begin
|
begin
|
||||||
if GetRegisterDatapacketReader(AStream, format, APacketReaderReg) then
|
fmt:=Format;
|
||||||
|
if (Fmt=dfDefault) then
|
||||||
|
fmt:=DefaultReadFileFormat;
|
||||||
|
if fmt=dfDefault then
|
||||||
|
APacketReader := DefaultPacketClass.Create(Self, AStream)
|
||||||
|
else if GetRegisterDatapacketReader(AStream, fmt, APacketReaderReg) then
|
||||||
APacketReader := APacketReaderReg.ReaderClass.Create(Self, AStream)
|
APacketReader := APacketReaderReg.ReaderClass.Create(Self, AStream)
|
||||||
else if TFpcBinaryDatapacketReader.RecognizeStream(AStream) then
|
else if TFpcBinaryDatapacketReader.RecognizeStream(AStream) then
|
||||||
begin
|
begin
|
||||||
@ -3433,11 +3459,17 @@ end;
|
|||||||
procedure TCustomBufDataset.SaveToStream(AStream: TStream; Format: TDataPacketFormat);
|
procedure TCustomBufDataset.SaveToStream(AStream: TStream; Format: TDataPacketFormat);
|
||||||
var APacketReaderReg : TDatapacketReaderRegistration;
|
var APacketReaderReg : TDatapacketReaderRegistration;
|
||||||
APacketWriter : TDataPacketReader;
|
APacketWriter : TDataPacketReader;
|
||||||
|
Fmt : TDataPacketFormat;
|
||||||
begin
|
begin
|
||||||
CheckBiDirectional;
|
CheckBiDirectional;
|
||||||
if GetRegisterDatapacketReader(Nil,format,APacketReaderReg) then
|
fmt:=Format;
|
||||||
|
if Fmt=dfDefault then
|
||||||
|
fmt:=DefaultWriteFileFormat;
|
||||||
|
if fmt=dfDefault then
|
||||||
|
APacketWriter := DefaultPacketClass.Create(Self, AStream)
|
||||||
|
else if GetRegisterDatapacketReader(Nil,fmt,APacketReaderReg) then
|
||||||
APacketWriter := APacketReaderReg.ReaderClass.Create(Self, AStream)
|
APacketWriter := APacketReaderReg.ReaderClass.Create(Self, AStream)
|
||||||
else if Format = dfBinary then
|
else if fmt = dfBinary then
|
||||||
APacketWriter := TFpcBinaryDatapacketReader.Create(Self, AStream)
|
APacketWriter := TFpcBinaryDatapacketReader.Create(Self, AStream)
|
||||||
else
|
else
|
||||||
DatabaseError(SNoReaderClassRegistered,Self);
|
DatabaseError(SNoReaderClassRegistered,Self);
|
||||||
@ -3449,9 +3481,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomBufDataset.LoadFromFile(AFileName: string; Format: TDataPacketFormat);
|
procedure TCustomBufDataset.LoadFromFile(AFileName: string; Format: TDataPacketFormat);
|
||||||
var AFileStream : TFileStream;
|
|
||||||
|
var
|
||||||
|
AFileStream : TFileStream;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if AFileName='' then AFileName := FFileName;
|
if AFileName='' then
|
||||||
|
AFileName := FFileName;
|
||||||
AFileStream := TFileStream.Create(AFileName,fmOpenRead);
|
AFileStream := TFileStream.Create(AFileName,fmOpenRead);
|
||||||
try
|
try
|
||||||
LoadFromStream(AFileStream, Format);
|
LoadFromStream(AFileStream, Format);
|
||||||
@ -3460,11 +3496,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomBufDataset.SaveToFile(AFileName: string;
|
procedure TCustomBufDataset.SaveToFile(AFileName: string; Format: TDataPacketFormat);
|
||||||
Format: TDataPacketFormat);
|
|
||||||
var AFileStream : TFileStream;
|
var
|
||||||
|
AFileStream : TFileStream;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if AFileName='' then AFileName := FFileName;
|
if AFileName='' then
|
||||||
|
AFileName := FFileName;
|
||||||
AFileStream := TFileStream.Create(AFileName,fmCreate);
|
AFileStream := TFileStream.Create(AFileName,fmCreate);
|
||||||
try
|
try
|
||||||
SaveToStream(AFileStream, Format);
|
SaveToStream(AFileStream, Format);
|
||||||
@ -3536,7 +3575,7 @@ begin
|
|||||||
if not assigned(FDatasetReader) then
|
if not assigned(FDatasetReader) then
|
||||||
begin
|
begin
|
||||||
FFileStream := TFileStream.Create(FileName, fmOpenRead);
|
FFileStream := TFileStream.Create(FileName, fmOpenRead);
|
||||||
FDatasetReader := GetPacketReader(dfAny, FFileStream);
|
FDatasetReader := GetPacketReader(dfDefault, FFileStream);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
FieldDefs.Clear;
|
FieldDefs.Clear;
|
||||||
|
@ -95,6 +95,9 @@ Type
|
|||||||
FCSVOptions: TCSVOptions;
|
FCSVOptions: TCSVOptions;
|
||||||
procedure SetCSVOptions(AValue: TCSVOptions);
|
procedure SetCSVOptions(AValue: TCSVOptions);
|
||||||
Protected
|
Protected
|
||||||
|
class function DefaultReadFileFormat : TDataPacketFormat; override;
|
||||||
|
class function DefaultWriteFileFormat : TDataPacketFormat; override;
|
||||||
|
class function DefaultPacketClass : TDataPacketReaderClass ; override;
|
||||||
function GetPacketReader(const Format: TDataPacketFormat; const AStream: TStream): TDataPacketReader; override;
|
function GetPacketReader(const Format: TDataPacketFormat; const AStream: TStream): TDataPacketReader; override;
|
||||||
procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
|
procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
|
||||||
procedure InternalInitFieldDefs; override;
|
procedure InternalInitFieldDefs; override;
|
||||||
@ -305,10 +308,25 @@ begin
|
|||||||
FCSVOptions.Assign(AValue);
|
FCSVOptions.Assign(AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TCustomCSVDataset.DefaultReadFileFormat: TDataPacketFormat;
|
||||||
|
begin
|
||||||
|
Result:=dfDefault;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TCustomCSVDataset.DefaultWriteFileFormat: TDataPacketFormat;
|
||||||
|
begin
|
||||||
|
Result:=dfDefault;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TCustomCSVDataset.DefaultPacketClass: TDataPacketReaderClass;
|
||||||
|
begin
|
||||||
|
Result:=TCSVDataPacketReader;
|
||||||
|
end;
|
||||||
|
|
||||||
function TCustomCSVDataset.GetPacketReader(const Format: TDataPacketFormat;
|
function TCustomCSVDataset.GetPacketReader(const Format: TDataPacketFormat;
|
||||||
const AStream: TStream): TDataPacketReader;
|
const AStream: TStream): TDataPacketReader;
|
||||||
begin
|
begin
|
||||||
If (Format=dfAny) then
|
If (Format in [dfAny,dfDefault]) then
|
||||||
Result:=TCSVDataPacketReader.Create(Self,AStream,FCSVOptions)
|
Result:=TCSVDataPacketReader.Create(Self,AStream,FCSVOptions)
|
||||||
else
|
else
|
||||||
Result:=Inherited GetPacketReader(Format,AStream);
|
Result:=Inherited GetPacketReader(Format,AStream);
|
||||||
|
@ -15,6 +15,7 @@ type
|
|||||||
private
|
private
|
||||||
FCSVDataset: TCSVDataset;
|
FCSVDataset: TCSVDataset;
|
||||||
// Load CSVDataset from CSV stream containing lines
|
// Load CSVDataset from CSV stream containing lines
|
||||||
|
procedure DoOpenClose;
|
||||||
Procedure LoadFromLines(Const Lines: Array of string);
|
Procedure LoadFromLines(Const Lines: Array of string);
|
||||||
// Save CSVDataset to CSV stream, transform to lines
|
// Save CSVDataset to CSV stream, transform to lines
|
||||||
Procedure SaveToLines(Const Lines: TStrings);
|
Procedure SaveToLines(Const Lines: TStrings);
|
||||||
@ -47,6 +48,7 @@ type
|
|||||||
Procedure TestLoadPriorFieldDefsNoFieldNamesWrongCount;
|
Procedure TestLoadPriorFieldDefsNoFieldNamesWrongCount;
|
||||||
Procedure TestLoadPriorFieldDefsFieldNamesWrongCount;
|
Procedure TestLoadPriorFieldDefsFieldNamesWrongCount;
|
||||||
Procedure TestLoadPriorFieldDefsFieldNamesWrongNames;
|
Procedure TestLoadPriorFieldDefsFieldNamesWrongNames;
|
||||||
|
Procedure TestOpenCloseCycle;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -421,6 +423,89 @@ begin
|
|||||||
Fail(OK);
|
Fail(OK);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
FILENAME = 'test.dat';
|
||||||
|
|
||||||
|
procedure TTestCSVDataset.DoOpenClose;
|
||||||
|
|
||||||
|
begin
|
||||||
|
CSVDataset.FileName := FILENAME;
|
||||||
|
With CSVDataset do
|
||||||
|
begin
|
||||||
|
CSVOptions.FirstLineAsFieldNames := True;
|
||||||
|
CSVOptions.DefaultFieldLength := 255;
|
||||||
|
CSVOptions.Delimiter := ',';
|
||||||
|
CSVOptions.QuoteChar := '"';
|
||||||
|
CSVOptions.IgnoreOuterWhitespace := False;
|
||||||
|
CSVOptions.QuoteOuterWhitespace := True;
|
||||||
|
end;
|
||||||
|
// When the program runs for the first time, the data file does not yet exist.
|
||||||
|
// We must create the FieldDefs and create the dataset.
|
||||||
|
if FileExists(CSVDataset.FileName) then
|
||||||
|
CSVDataset.Open
|
||||||
|
else
|
||||||
|
with CSVDataset do
|
||||||
|
begin
|
||||||
|
FieldDefs.Add('FirstName', ftString, 20);
|
||||||
|
FieldDefs.Add('LastName', ftstring, 20);
|
||||||
|
FieldDefs.Add('City', ftString, 20);
|
||||||
|
FieldDefs.Add('Address', ftString, 30);
|
||||||
|
FieldDefs.Add('Birthdate', ftDate);
|
||||||
|
CreateDataset;
|
||||||
|
|
||||||
|
// Open the dataset...
|
||||||
|
Open;
|
||||||
|
|
||||||
|
// ... and add some dummy data:
|
||||||
|
// Names from https://donatellanobatti.blogspot.de/
|
||||||
|
Append;
|
||||||
|
FieldByName('FirstName').AsString := 'Walter';
|
||||||
|
FieldByName('LastName').AsString := 'Mellon';
|
||||||
|
FieldByName('City').AsString := 'Oklahoma City';
|
||||||
|
FieldByName('Address').AsString := '1261, Main Street';
|
||||||
|
FieldbyName('Birthdate').AsDateTime := EncodeDate(1980, 1, 1);
|
||||||
|
Post;
|
||||||
|
|
||||||
|
Append;
|
||||||
|
FieldByName('FirstName').AsString := 'Mario';
|
||||||
|
FieldByName('LastName').AsString := 'Speedwagon';
|
||||||
|
FieldByName('City').AsString := 'Hollywood';
|
||||||
|
FieldByName('Address').AsString := '1500, Hollywood Blvd';
|
||||||
|
FieldbyName('Birthdate').AsDateTime := EncodeDate(1982, 12, 17);
|
||||||
|
Post;
|
||||||
|
|
||||||
|
Append;
|
||||||
|
FieldByName('FirstName').AsString := 'Anna';
|
||||||
|
FieldByName('LastName').AsString := 'Mull';
|
||||||
|
FieldByName('City').AsString := 'Los Angeles';
|
||||||
|
FieldByName('Address').AsString := '2202, Capitol Square';
|
||||||
|
FieldbyName('Birthdate').AsDateTime := EncodeDate(1982, 12, 17);
|
||||||
|
Post;
|
||||||
|
end;
|
||||||
|
// This will write the file;
|
||||||
|
CSVDataset.Close;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCSVDataset.TestOpenCloseCycle;
|
||||||
|
begin
|
||||||
|
if FileExists(FileName) then
|
||||||
|
AssertTrue('Delete before',DeleteFile(FileName));
|
||||||
|
try
|
||||||
|
// This will create the file
|
||||||
|
DoOpenClose;
|
||||||
|
// Recreate to be sure
|
||||||
|
FreeAndNil(FCSVDataset);
|
||||||
|
FCSVDataset:=TCSVDataset.Create(Nil);
|
||||||
|
FCSVDataset.Name:='DS';
|
||||||
|
DoOpenClose;
|
||||||
|
except
|
||||||
|
On E : Exception do
|
||||||
|
Fail('Failed using exception %s : %s',[E.ClassName,E.Message]);
|
||||||
|
end;
|
||||||
|
if FileExists(FileName) then
|
||||||
|
AssertTrue('Delete after',DeleteFile(FileName));
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestCSVDataset.SetUp;
|
procedure TTestCSVDataset.SetUp;
|
||||||
begin
|
begin
|
||||||
FCSVDataset:=TCSVDataset.Create(Nil);
|
FCSVDataset:=TCSVDataset.Create(Nil);
|
||||||
|
Loading…
Reference in New Issue
Block a user