mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 04:06:08 +02:00
* fcl-db: clarified Dataset.txt
* fcl-db/dbase tests: fix for failing memo, string test improvement in naming saved dbf files (if enabled) git-svn-id: trunk@24525 -
This commit is contained in:
parent
2fe7dbfc6c
commit
773ee3d21c
@ -4,7 +4,7 @@ Contents
|
||||
+ Fields system
|
||||
+ The buffers
|
||||
+ Dataset implementation
|
||||
+ Scalable Datasets
|
||||
+ Switchable datasets
|
||||
|
||||
===============
|
||||
General remarks
|
||||
@ -231,10 +231,10 @@ procedure SetFieldData(Field: TField; Buffer: Pointer); virtual; abstract;
|
||||
--------------------------------------------------------------------------
|
||||
Move the data in associated with Field from Buffer to the active buffer.
|
||||
|
||||
=================
|
||||
Scalable datasets
|
||||
=================
|
||||
In order to have Scalable database access, the concept of TDatabase and
|
||||
===================
|
||||
Switchable datasets
|
||||
===================
|
||||
In order to have flexible database access, the concept of TDatabase and
|
||||
TDBDataset is introduced. The idea is that, in a visual IDE, the change
|
||||
from one database to another is achieved by simply removing one TDatabase
|
||||
descendent (Say, TMySqlDatabase) with another (Say, TPostGreSQLDatabase)
|
||||
|
@ -2,14 +2,13 @@ unit DBFToolsUnit;
|
||||
|
||||
{ Sets up dbf datasets for testing
|
||||
Tests expect Get*Dataset to return a dataset with structure and test data, but closed.
|
||||
Because of this, we use file-backed dbfs instead of memory backed dbfs
|
||||
}
|
||||
|
||||
{$IFDEF FPC}
|
||||
{$mode objfpc}{$H+}
|
||||
{$ENDIF}
|
||||
|
||||
// If defined, do not delete the dbf files when done but print out location to stdout:
|
||||
// If defined, save the dbf files when done and print out location to stdout:
|
||||
{.$DEFINE KEEPDBFFILES}
|
||||
|
||||
interface
|
||||
@ -42,6 +41,8 @@ type
|
||||
TDBFAutoClean = class(TDBF)
|
||||
private
|
||||
FBackingStream: TMemoryStream;
|
||||
FIndexBackingStream: TMemoryStream;
|
||||
FMemoBackingStream: TMemoryStream;
|
||||
FCreatedBy: string;
|
||||
public
|
||||
// Keeps track of which function created the dataset, useful for troubleshooting
|
||||
@ -68,6 +69,41 @@ implementation
|
||||
uses
|
||||
FmtBCD;
|
||||
|
||||
function GetNewTempDBFName: string;
|
||||
// Scans temp directory for dbf names and adds
|
||||
var
|
||||
Res: TSearchRec;
|
||||
Path, Name: string;
|
||||
FileAttr: LongInt;
|
||||
Attr,NextFileNo: Integer;
|
||||
begin
|
||||
NextFileNo:=0;
|
||||
Attr := faAnyFile;
|
||||
if FindFirst(IncludeTrailingPathDelimiter(GetTempDir)+'*.dbf', Attr, Res) = 0 then
|
||||
begin
|
||||
Path := GetTempDir;
|
||||
repeat
|
||||
Name := ConcatPaths([Path, Res.Name]);
|
||||
FileAttr := FileGetAttr(Name);
|
||||
if FileAttr and faDirectory = 0 then
|
||||
begin
|
||||
// Capture alphabetically latest name
|
||||
try
|
||||
//... only if it is numeric
|
||||
if strtoint(ChangeFileExt(Res.Name,''))>NextFileNo then
|
||||
NextFileNo:=strtoint(ChangeFileExt(Res.Name,''));
|
||||
except
|
||||
// apparently not numeric
|
||||
end;
|
||||
end
|
||||
until FindNext(Res) <> 0;
|
||||
end;
|
||||
FindClose(Res);
|
||||
// now we now the latest file, add 1, and paste the temp directory in front of it
|
||||
NextFileNo:=NextFileNo+1;
|
||||
Result:=IncludeTrailingPathDelimiter(GetTempDir)+IntToStr(NextFileNo)+'.DBF';
|
||||
end;
|
||||
|
||||
{ TDBFAutoClean }
|
||||
|
||||
function TDBFAutoClean.UserRequestedTableLevel: integer;
|
||||
@ -90,13 +126,18 @@ end;
|
||||
|
||||
constructor TDBFAutoClean.Create;
|
||||
begin
|
||||
// Create storage for data:
|
||||
FBackingStream:=TMemoryStream.Create;
|
||||
// Create a unique name:
|
||||
TableName := FormatDateTime('hhnnssz',Now())+'/'+inttostr(random(32767));
|
||||
FIndexBackingStream:=TMemoryStream.Create;
|
||||
FMemoBackingStream:=TMemoryStream.Create;
|
||||
// Create a unique name (within the 10 character DBIII limit):
|
||||
TableName := FormatDateTime('hhnnssz',Now())+'_'+inttostr(random(99));
|
||||
TableLevel := UserRequestedTableLevel;
|
||||
Storage:=stoMemory;
|
||||
UserStream:=FBackingStream;
|
||||
CreateTable; //write out header to disk
|
||||
UserIndexStream:=FIndexBackingStream;
|
||||
UserMemoStream:=FMemoBackingStream;
|
||||
CreateTable; //this will also write out the dbf header to disk/stream
|
||||
end;
|
||||
|
||||
constructor TDBFAutoClean.Create(AOwner: TComponent);
|
||||
@ -113,12 +154,18 @@ var
|
||||
begin
|
||||
{$IFDEF KEEPDBFFILES}
|
||||
Close;
|
||||
FileName := GetTempFileName;
|
||||
FileName := GetNewTempDBFName;
|
||||
FBackingStream.SaveToFile(FileName);
|
||||
FIndexBackingStream.SaveToFile(ChangeFileExt(FileName, '.mdx'));
|
||||
if Self.TableLevel in [TDBF_TABLELEVEL_FOXPRO, TDBF_TABLELEVEL_VISUALFOXPRO] then
|
||||
FMemoBackingStream.SaveToFile(ChangeFileExt(FileName, '.fpt'))
|
||||
else
|
||||
FMemoBackingStream.SaveToFile(ChangeFileExt(FileName, '.dbt'));
|
||||
writeln('TDBFAutoClean: file created by ',CreatedBy,' left file: ',FileName);
|
||||
{$ENDIF}
|
||||
inherited Destroy;
|
||||
FBackingStream.Free;
|
||||
FIndexBackingStream.Free;
|
||||
end;
|
||||
|
||||
|
||||
@ -162,10 +209,10 @@ begin
|
||||
FieldDefs.Add('FWORD', ftWord);
|
||||
FieldDefs.Add('FBOOLEAN', ftBoolean);
|
||||
FieldDefs.Add('FFLOAT', ftFloat);
|
||||
// Field types only available in newer versions
|
||||
if (Result as TDBF).TableLevel >= 25 then
|
||||
// Field types only available in (Visual) FoxPro
|
||||
if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
|
||||
FieldDefs.Add('FCURRENCY', ftCurrency);
|
||||
if (Result as TDBF).TableLevel >= 25 then
|
||||
if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
|
||||
FieldDefs.Add('FBCD', ftBCD);
|
||||
FieldDefs.Add('FDATE', ftDate);
|
||||
FieldDefs.Add('FDATETIME', ftDateTime);
|
||||
@ -182,13 +229,15 @@ begin
|
||||
FieldByName('FINTEGER').AsInteger := testIntValues[i];
|
||||
FieldByName('FBOOLEAN').AsBoolean := testBooleanValues[i];
|
||||
FieldByName('FFLOAT').AsFloat := testFloatValues[i];
|
||||
if (Result as TDBF).TableLevel >= 25 then
|
||||
if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
|
||||
FieldByName('FCURRENCY').AsCurrency := testCurrencyValues[i];
|
||||
// work around missing TBCDField.AsBCD:
|
||||
if (Result as TDBF).TableLevel >= 25 then
|
||||
if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
|
||||
FieldByName('FBCD').AsBCD := StrToBCD(testFmtBCDValues[i],Self.FormatSettings);
|
||||
FieldByName('FDATE').AsDateTime := StrToDate(testDateValues[i], 'yyyy/mm/dd', '-');
|
||||
FieldByName('FDATETIME').AsDateTime := StrToDateTime(testValues[ftDateTime,i], Self.FormatSettings);
|
||||
FieldByName('FLARGEINT').AsLargeInt := testLargeIntValues[i];
|
||||
FieldByName('FMEMO').AsString := testStringValues[i];
|
||||
Post;
|
||||
end;
|
||||
Close;
|
||||
|
@ -2316,6 +2316,8 @@ var i : byte;
|
||||
Fld : TField;
|
||||
|
||||
begin
|
||||
if (uppercase(dbconnectorname)='DBF') then
|
||||
Ignore('TDBF Smallint support only from -999 to 9999');
|
||||
TestfieldDefinition(ftSmallint,2,ds,Fld);
|
||||
|
||||
for i := 0 to testValuesCount-1 do
|
||||
@ -2338,7 +2340,10 @@ begin
|
||||
|
||||
for i := 0 to testValuesCount-1 do
|
||||
begin
|
||||
CheckEquals(testStringValues[i],Fld.AsString);
|
||||
if (uppercase(dbconnectorname)<>'DBF') then
|
||||
CheckEquals(testStringValues[i],Fld.AsString)
|
||||
else {DBF right-trims spaces in string fields }
|
||||
CheckEquals(TrimRight(testStringValues[i]),Fld.AsString);
|
||||
ds.Next;
|
||||
end;
|
||||
ds.close;
|
||||
|
Loading…
Reference in New Issue
Block a user