
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5438 8e941d3f-bd1b-0410-a28a-d453659cc2b4
270 lines
8.0 KiB
ObjectPascal
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.
|