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

270 lines
8.0 KiB
ObjectPascal

{NOTES:
1. Have verification as optional--IFDEF'd out}
{*********************************************************}
{* FlashFiler: Table data dictionary access (server) *}
{*********************************************************}
(* ***** 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 fftbdict;
interface
uses
Windows,
SysUtils,
Classes,
ffconst,
ffllbase,
ffsrmgr,
ffllexcp,
fflldict,
ffsrintf,
ffsrbase,
fffile,
ffsrixhl,
fftbbase,
fftbstrm;
{---Data dictionary class---}
type
TffServerDataDict = class(TffDataDictionary)
protected {private}
protected
public
procedure ForceOffReadOnly;
{-Make dictionary writable}
procedure ReadFromFile(aFI : PffFileInfo; aTI : PffTransInfo);
{-Read the data dictionary from the file}
procedure WriteToFile(aFI : PffFileInfo; aTI : PffTransInfo);
{-Write the data dictionary to the file
Note: the data dictionary can only be written once}
end;
{---Compare routine for composite keys---}
function FFKeyCompareComposite(const Key1, Key2; aData : PffCompareData) : integer
stdcall;
{-Treat Key1 and Key2 as composite keys, compare}
implementation
uses
ffsrlock;
{===TffServerDataDict================================================}
procedure TffServerDataDict.ForceOffReadOnly;
begin
ddReadOnly := false;
end;
{--------}
procedure TffServerDataDict.ReadFromFile(aFI : PffFileInfo; aTI : PffTransInfo);
var
FileHeader : PffBlockHeaderFile;
S : TMemoryStream;
aRelMethod : TffReleaseMethod;
begin
{ Get the file header, block 0. Assume that we only need the lock for the
duration of this call. }
FileHeader := PffBlockHeaderFile(FFBMGetBlock(aFI, aTI, 0, ffc_ReadOnly,
aRelMethod));
try
{ Is there a data dictionary?}
if (FileHeader^.bhfDataDict = 0) then
FFRaiseException(EffServerException, ffStrResServer, fferrDictMissing,
[aFI^.fiName^]);
{ Read the data dictionary from the file via a stream}
S := TMemoryStream.Create;
try
FFTblReadStream(aFI, aTI, FileHeader^.bhfDataDict, S);
S.Seek(0, soFromBeginning);
ReadFromStream(S);
finally
S.Free;
end;{try..finally}
finally
aRelMethod(PffBlock(FileHeader));
end;
{ Because this method is only called for a pre-existing File group,
that means we cannot alter it any more. }
ddReadOnly := true;
end;
{--------}
procedure TffServerDataDict.WriteToFile(aFI : PffFileInfo; aTI : PffTransInfo);
var
FileHeader : PffBlockHeaderFile;
S : TMemoryStream;
aRelMethod : TffReleaseMethod;
begin
{ Verify the data dictionary. }
CheckValid;
{ Get the file header, block 0. }
FileHeader := PffBlockHeaderFile(FFBMGetBlock(aFI, aTI, 0, ffc_MarkDirty,
aRelMethod));
try
{ Write the data dictionary to the file via a stream. }
S := TMemoryStream.Create;
try
WriteToStream(S);
FFTblWriteStream(aFI, aTI, FileHeader^.bhfDataDict, S,
(FileHeader^.bhfDataDict = 0),
ffc_SigDictStream);
finally
S.Free;
end;{try..finally}
finally
aRelMethod(PffBlock(FileHeader));
end;
end;
{====================================================================}
{===Composite Key Compare routine====================================}
function FFKeyCompareComposite(const Key1, Key2; aData : PffCompareData) : integer;
var
K1 : TffByteArray absolute Key1;
K2 : TffByteArray absolute Key2;
IndexDesc : PffIndexDescriptor;
FieldDesc : PffFieldDescriptor;
KeyOffset : integer;
FieldNumber : integer;
CurIndex : integer;
CurDict : TffServerDataDict;
CurFldCount : integer;
CurPartLen : integer;
CurKeyLen : integer;
FldCnt : integer;
LenToUse : integer;
CurAscend : boolean;
CurNoCase : boolean;
Fld1Null : boolean;
Fld2Null : boolean;
begin
with aData^ do begin
CurIndex := cdIndex;
CurKeyLen := cdKeyLen;
CurDict := TffServerDataDict(cdDict);
CurFldCount := cdFldCnt;
CurPartLen := cdPartLen;
CurAscend := cdAscend;
CurNoCase := cdNoCase;
end;
Result := 0;
KeyOffset := 0;
{get the index descriptor}
IndexDesc := CurDict.IndexDescriptor^[CurIndex];
with IndexDesc^ do begin
{calculate the number of complete fields we can compare}
if (CurFldCount = 0) then
if (CurPartLen = 0) then
FldCnt := idCount
else {partial key}
FldCnt := 0
else
if (CurPartLen = 0) then
FldCnt := FFMinI(CurFldCount, idCount)
else {partial key}
FldCnt := FFMinI(CurFldCount, pred(idCount));
{compare each field in the key until we get a non-zero (ie not
equal) result}
if (FldCnt > 0) then
for FieldNumber := 0 to pred(FldCnt) do begin
Fld1Null := FFIsKeyFieldNull(@K1, CurKeyLen, idCount, FieldNumber);
Fld2Null := FFIsKeyFieldNull(@K2, CurKeyLen, idCount, FieldNumber);
FieldDesc := CurDict.FieldDescriptor^[idFields[FieldNumber]];
with FieldDesc^ do begin
if Fld1Null then begin
if Fld2Null then
Result := 0
else
Result := -1;
end
else {Fld1Null is false} begin
if Fld2Null then
Result := 1
else
Result := FFCheckDescend
(CurAscend,
CurDict.IndexHelpers[CurIndex, FieldNumber].CompareKey(K1[KeyOffset],
K2[KeyOffset], FieldDesc, -1, CurNoCase));
end;
if (Result = 0) then
inc(KeyOffset, fdLength)
else
Break;{out of for loop}
end;
end;
{partially compare the last field if required}
if (CurPartLen > 0) then begin
FieldDesc := CurDict.FieldDescriptor^[idFields[FldCnt]];
with FieldDesc^ do
if (fdType >= fftShortString) then begin
Fld1Null := FFIsKeyFieldNull(@K1, CurKeyLen, idCount, FldCnt);
Fld2Null := FFIsKeyFieldNull(@K2, CurKeyLen, idCount, FldCnt);
if Fld1Null then begin
if Fld2Null then
Result := 0
else
Result := -1;
end
else {Fld1Null is false} begin
if Fld2Null then
Result := 1
else begin
if (fdType = fftWideString) then
LenToUse := sizeof(WideChar) * CurPartLen
else if (fdType = fftShortString) or
(fdType = fftShortAnsiStr) then
LenToUse := CurPartLen + 1
else
LenToUse := CurPartLen;
Result := FFCheckDescend
(CurAscend,
CurDict.IndexHelpers[CurIndex, FldCnt].
CompareKey(K1[KeyOffset], K2[KeyOffset], FieldDesc,
LenToUse, CurNoCase));
end;
end;
end;
end;
end;
end;
{====================================================================}
end.