mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-10-24 17:01:44 +02:00
* update tdbf to release 6.9.1
git-svn-id: trunk@6721 -
This commit is contained in:
parent
c13ff3729b
commit
3c581e3f42
@ -117,7 +117,6 @@ type
|
|||||||
FParser: TDbfParser;
|
FParser: TDbfParser;
|
||||||
FFieldNames: string;
|
FFieldNames: string;
|
||||||
FValidExpression: Boolean;
|
FValidExpression: Boolean;
|
||||||
FKeyTranslation: boolean;
|
|
||||||
FOnMasterChange: TNotifyEvent;
|
FOnMasterChange: TNotifyEvent;
|
||||||
FOnMasterDisable: TNotifyEvent;
|
FOnMasterDisable: TNotifyEvent;
|
||||||
|
|
||||||
@ -135,7 +134,6 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
property FieldNames: string read FFieldNames write SetFieldNames;
|
property FieldNames: string read FFieldNames write SetFieldNames;
|
||||||
property KeyTranslation: boolean read FKeyTranslation;
|
|
||||||
property ValidExpression: Boolean read FValidExpression write FValidExpression;
|
property ValidExpression: Boolean read FValidExpression write FValidExpression;
|
||||||
property FieldsVal: PChar read GetFieldsVal;
|
property FieldsVal: PChar read GetFieldsVal;
|
||||||
property Parser: TDbfParser read FParser;
|
property Parser: TDbfParser read FParser;
|
||||||
@ -223,6 +221,7 @@ type
|
|||||||
function ParseIndexName(const AIndexName: string): string;
|
function ParseIndexName(const AIndexName: string): string;
|
||||||
procedure ParseFilter(const AFilter: string);
|
procedure ParseFilter(const AFilter: string);
|
||||||
function GetDbfFieldDefs: TDbfFieldDefs;
|
function GetDbfFieldDefs: TDbfFieldDefs;
|
||||||
|
function ReadCurrentRecord(Buffer: PChar; var Acceptable: Boolean): TGetResult;
|
||||||
function SearchKeyBuffer(Buffer: PChar; SearchType: TSearchKeyType): Boolean;
|
function SearchKeyBuffer(Buffer: PChar; SearchType: TSearchKeyType): Boolean;
|
||||||
procedure SetRangeBuffer(LowRange: PChar; HighRange: PChar);
|
procedure SetRangeBuffer(LowRange: PChar; HighRange: PChar);
|
||||||
|
|
||||||
@ -289,7 +288,7 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
{ abstract methods }
|
{ abstract methods }
|
||||||
function GetFieldData(Field: TField; Buffer: Pointer): Boolean;
|
function GetFieldData(Field: TField; Buffer: Pointer): Boolean;
|
||||||
{$ifdef SUPPORT_OVERLOAD} overload; {$endif} override; {virtual abstract}
|
{$ifdef SUPPORT_OVERLOAD} overload; {$endif} override; {virtual abstract}
|
||||||
{ virtual methods (mostly optionnal) }
|
{ virtual methods (mostly optionnal) }
|
||||||
procedure Resync(Mode: TResyncMode); override;
|
procedure Resync(Mode: TResyncMode); override;
|
||||||
@ -441,6 +440,8 @@ type
|
|||||||
property AfterCancel;
|
property AfterCancel;
|
||||||
property BeforeDelete;
|
property BeforeDelete;
|
||||||
property AfterDelete;
|
property AfterDelete;
|
||||||
|
property BeforeRefresh;
|
||||||
|
property AfterRefresh;
|
||||||
property BeforeScroll;
|
property BeforeScroll;
|
||||||
property AfterScroll;
|
property AfterScroll;
|
||||||
property OnCalcFields;
|
property OnCalcFields;
|
||||||
@ -794,12 +795,29 @@ begin
|
|||||||
OnFilterRecord(Self, Acceptable);
|
OnFilterRecord(Self, Acceptable);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbf.ReadCurrentRecord(Buffer: PChar; var Acceptable: Boolean): TGetResult;
|
||||||
|
var
|
||||||
|
lPhysicalRecNo: Integer;
|
||||||
|
pRecord: pDbfRecord;
|
||||||
|
begin
|
||||||
|
lPhysicalRecNo := FCursor.PhysicalRecNo;
|
||||||
|
if (lPhysicalRecNo = 0) or not FDbfFile.IsRecordPresent(lPhysicalRecNo) then
|
||||||
|
begin
|
||||||
|
Result := grError;
|
||||||
|
Acceptable := false;
|
||||||
|
end else begin
|
||||||
|
Result := grOK;
|
||||||
|
pRecord := pDbfRecord(Buffer);
|
||||||
|
FDbfFile.ReadRecord(lPhysicalRecNo, @pRecord^.DeletedFlag);
|
||||||
|
Acceptable := (FShowDeleted or (pRecord^.DeletedFlag <> '*'))
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbf.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; {override virtual abstract from TDataset}
|
function TDbf.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; {override virtual abstract from TDataset}
|
||||||
var
|
var
|
||||||
pRecord: pDBFRecord;
|
pRecord: pDbfRecord;
|
||||||
acceptable: Boolean;
|
acceptable: Boolean;
|
||||||
SaveState: TDataSetState;
|
SaveState: TDataSetState;
|
||||||
lPhysicalRecNo: Integer;
|
|
||||||
// s: string;
|
// s: string;
|
||||||
begin
|
begin
|
||||||
if FCursor = nil then
|
if FCursor = nil then
|
||||||
@ -808,7 +826,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
pRecord := pDBFRecord(Buffer);
|
pRecord := pDbfRecord(Buffer);
|
||||||
acceptable := false;
|
acceptable := false;
|
||||||
repeat
|
repeat
|
||||||
Result := grOK;
|
Result := grOK;
|
||||||
@ -834,16 +852,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if (Result = grOK) then
|
if (Result = grOK) then
|
||||||
begin
|
Result := ReadCurrentRecord(Buffer, acceptable);
|
||||||
lPhysicalRecNo := FCursor.PhysicalRecNo;
|
|
||||||
if (lPhysicalRecNo = 0) or not FDbfFile.IsRecordPresent(lPhysicalRecNo) then
|
|
||||||
begin
|
|
||||||
Result := grError;
|
|
||||||
end else begin
|
|
||||||
FDbfFile.ReadRecord(lPhysicalRecNo, @pRecord^.DeletedFlag);
|
|
||||||
acceptable := (FShowDeleted or (pRecord^.DeletedFlag <> '*'))
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if (Result = grOK) and acceptable then
|
if (Result = grOK) and acceptable then
|
||||||
begin
|
begin
|
||||||
@ -1267,6 +1276,8 @@ begin
|
|||||||
// SetIndexName will have made the cursor for us if no index selected :-)
|
// SetIndexName will have made the cursor for us if no index selected :-)
|
||||||
// if FCursor = nil then FCursor := TDbfCursor.Create(FDbfFile);
|
// if FCursor = nil then FCursor := TDbfCursor.Create(FDbfFile);
|
||||||
|
|
||||||
|
if FMasterLink.Active and Assigned(FIndexFile) then
|
||||||
|
CheckMasterRange;
|
||||||
InternalFirst;
|
InternalFirst;
|
||||||
|
|
||||||
// FDbfFile.SetIndex(FIndexName);
|
// FDbfFile.SetIndex(FIndexName);
|
||||||
@ -1827,6 +1838,7 @@ var
|
|||||||
searchFlag: TSearchKeyType;
|
searchFlag: TSearchKeyType;
|
||||||
matchRes: Integer;
|
matchRes: Integer;
|
||||||
lTempBuffer: array [0..100] of Char;
|
lTempBuffer: array [0..100] of Char;
|
||||||
|
acceptable, checkmatch: boolean;
|
||||||
begin
|
begin
|
||||||
if loPartialKey in Options then
|
if loPartialKey in Options then
|
||||||
searchFlag := stGreaterEqual
|
searchFlag := stGreaterEqual
|
||||||
@ -1835,23 +1847,31 @@ begin
|
|||||||
if TIndexCursor(FCursor).VariantToBuffer(KeyValues, @lTempBuffer[0]) = etString then
|
if TIndexCursor(FCursor).VariantToBuffer(KeyValues, @lTempBuffer[0]) = etString then
|
||||||
Translate(@lTempBuffer[0], @lTempBuffer[0], true);
|
Translate(@lTempBuffer[0], @lTempBuffer[0], true);
|
||||||
Result := FIndexFile.SearchKey(@lTempBuffer[0], searchFlag);
|
Result := FIndexFile.SearchKey(@lTempBuffer[0], searchFlag);
|
||||||
if Result then
|
if not Result then
|
||||||
begin
|
exit;
|
||||||
Result := GetRecord(TempBuffer, gmCurrent, false) = grOK;
|
|
||||||
if not Result then
|
checkmatch := false;
|
||||||
|
repeat
|
||||||
|
if ReadCurrentRecord(TempBuffer, acceptable) = grError then
|
||||||
begin
|
begin
|
||||||
Result := GetRecord(TempBuffer, gmNext, false) = grOK;
|
Result := false;
|
||||||
if Result then
|
exit;
|
||||||
begin
|
|
||||||
matchRes := TIndexCursor(FCursor).IndexFile.MatchKey(@lTempBuffer[0]);
|
|
||||||
if loPartialKey in Options then
|
|
||||||
Result := matchRes <= 0
|
|
||||||
else
|
|
||||||
Result := matchRes = 0;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
FFilterBuffer := TempBuffer;
|
if acceptable then break;
|
||||||
|
checkmatch := true;
|
||||||
|
FCursor.Next;
|
||||||
|
until false;
|
||||||
|
|
||||||
|
if checkmatch then
|
||||||
|
begin
|
||||||
|
matchRes := TIndexCursor(FCursor).IndexFile.MatchKey(@lTempBuffer[0]);
|
||||||
|
if loPartialKey in Options then
|
||||||
|
Result := matchRes <= 0
|
||||||
|
else
|
||||||
|
Result := matchRes = 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
FFilterBuffer := TempBuffer;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbf.LocateRecord(const KeyFields: String; const KeyValues: Variant;
|
function TDbf.LocateRecord(const KeyFields: String; const KeyValues: Variant;
|
||||||
@ -2798,7 +2818,8 @@ var
|
|||||||
tempBuffer: array[0..300] of char;
|
tempBuffer: array[0..300] of char;
|
||||||
begin
|
begin
|
||||||
fieldsVal := FMasterLink.FieldsVal;
|
fieldsVal := FMasterLink.FieldsVal;
|
||||||
if FMasterLink.KeyTranslation then
|
if (TDbf(FMasterLink.DataSet).DbfFile.UseCodePage <> FDbfFile.UseCodePage)
|
||||||
|
and (FMasterLink.Parser.ResultType = etString) then
|
||||||
begin
|
begin
|
||||||
FMasterLink.DataSet.Translate(fieldsVal, @tempBuffer[0], false);
|
FMasterLink.DataSet.Translate(fieldsVal, @tempBuffer[0], false);
|
||||||
fieldsVal := @tempBuffer[0];
|
fieldsVal := @tempBuffer[0];
|
||||||
@ -2807,7 +2828,7 @@ begin
|
|||||||
fieldsVal := TIndexCursor(FCursor).IndexFile.PrepareKey(fieldsVal, FMasterLink.Parser.ResultType);
|
fieldsVal := TIndexCursor(FCursor).IndexFile.PrepareKey(fieldsVal, FMasterLink.Parser.ResultType);
|
||||||
SetRangeBuffer(fieldsVal, fieldsVal);
|
SetRangeBuffer(fieldsVal, fieldsVal);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbf.MasterChanged(Sender: TObject);
|
procedure TDbf.MasterChanged(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
CheckBrowseMode;
|
CheckBrowseMode;
|
||||||
@ -2835,7 +2856,7 @@ begin
|
|||||||
DatabaseError(SCircularDataLink);
|
DatabaseError(SCircularDataLink);
|
||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
FMasterLink.DataSource := Value;
|
FMasterLink.DataSource := Value;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2950,8 +2971,6 @@ begin
|
|||||||
FValidExpression := false;
|
FValidExpression := false;
|
||||||
FParser.DbfFile := (DataSet as TDbf).DbfFile;
|
FParser.DbfFile := (DataSet as TDbf).DbfFile;
|
||||||
FParser.ParseExpression(FFieldNames);
|
FParser.ParseExpression(FFieldNames);
|
||||||
FKeyTranslation := TDbfFile(FParser.DbfFile).UseCodePage <>
|
|
||||||
FDetailDataSet.DbfFile.UseCodePage;
|
|
||||||
FValidExpression := true;
|
FValidExpression := true;
|
||||||
end else begin
|
end else begin
|
||||||
FParser.ClearExpressions;
|
FParser.ClearExpressions;
|
||||||
|
|||||||
@ -2359,27 +2359,22 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbfFile.Insert(Buffer: PChar): integer;
|
function TDbfFile.Insert(Buffer: PChar): integer;
|
||||||
|
type
|
||||||
|
TErrorContext = (ecNone, ecInsert, ecWriteIndex, ecWriteDbf);
|
||||||
var
|
var
|
||||||
newRecord: Integer;
|
newRecord: Integer;
|
||||||
lIndex: TIndexFile;
|
lIndex: TIndexFile;
|
||||||
error: Boolean;
|
|
||||||
|
|
||||||
procedure RollBackIndexesAndRaise(HighIndex: Integer; IndexError: Boolean);
|
procedure RollBackIndexesAndRaise(Count: Integer; ErrorContext: TErrorContext);
|
||||||
var
|
var
|
||||||
errorMsg: string;
|
errorMsg: string;
|
||||||
I: Integer;
|
I: Integer;
|
||||||
begin
|
begin
|
||||||
// rollback committed indexes
|
// rollback committed indexes
|
||||||
error := IndexError;
|
for I := 0 to Count-1 do
|
||||||
for I := 0 to HighIndex do
|
|
||||||
begin
|
begin
|
||||||
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
||||||
lIndex.Delete(newRecord, Buffer);
|
lIndex.Delete(newRecord, Buffer);
|
||||||
if lIndex.WriteError then
|
|
||||||
begin
|
|
||||||
lIndex.ResetError;
|
|
||||||
error := true;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// reset any dbf file error
|
// reset any dbf file error
|
||||||
@ -2387,15 +2382,17 @@ var
|
|||||||
|
|
||||||
// if part of indexes committed -> always index error msg
|
// if part of indexes committed -> always index error msg
|
||||||
// if error while rolling back index -> index error msg
|
// if error while rolling back index -> index error msg
|
||||||
if error then
|
case ErrorContext of
|
||||||
errorMsg := STRING_WRITE_INDEX_ERROR
|
ecInsert: begin TIndexFile(FIndexFiles.Items[Count]).InsertError; exit; end;
|
||||||
else
|
ecWriteIndex: errorMsg := STRING_WRITE_INDEX_ERROR;
|
||||||
errorMsg := STRING_WRITE_ERROR;
|
ecWriteDbf: errorMsg := STRING_WRITE_ERROR;
|
||||||
|
end;
|
||||||
raise EDbfWriteError.Create(errorMsg);
|
raise EDbfWriteError.Create(errorMsg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
|
error: TErrorContext;
|
||||||
begin
|
begin
|
||||||
// get new record index
|
// get new record index
|
||||||
Result := 0;
|
Result := 0;
|
||||||
@ -2405,34 +2402,24 @@ begin
|
|||||||
Inc(newRecord);
|
Inc(newRecord);
|
||||||
// write autoinc value
|
// write autoinc value
|
||||||
ApplyAutoIncToBuffer(Buffer);
|
ApplyAutoIncToBuffer(Buffer);
|
||||||
// check indexes -> possible key violation
|
error := ecNone;
|
||||||
I := 0; error := false;
|
I := 0;
|
||||||
while (I < FIndexFiles.Count) and not error do
|
while I < FIndexFiles.Count do
|
||||||
begin
|
begin
|
||||||
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
||||||
error := lIndex.CheckKeyViolation(Buffer);
|
if not lIndex.Insert(newRecord, Buffer) then
|
||||||
Inc(I);
|
error := ecInsert;
|
||||||
end;
|
|
||||||
// error occured while inserting? -> abort
|
|
||||||
if error then
|
|
||||||
begin
|
|
||||||
UnlockPage(newRecord);
|
|
||||||
lIndex.InsertError;
|
|
||||||
// don't have to exit -- unreachable code
|
|
||||||
end;
|
|
||||||
|
|
||||||
// no key violation, insert record into index(es)
|
|
||||||
for I := 0 to FIndexFiles.Count-1 do
|
|
||||||
begin
|
|
||||||
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
|
||||||
lIndex.Insert(newRecord, Buffer);
|
|
||||||
if lIndex.WriteError then
|
if lIndex.WriteError then
|
||||||
|
error := ecWriteIndex;
|
||||||
|
if error <> ecNone then
|
||||||
begin
|
begin
|
||||||
// if there's an index write error, I shouldn't
|
// if there's an index write error, I shouldn't
|
||||||
// try to write the dbf header and the new record,
|
// try to write the dbf header and the new record,
|
||||||
// but raise an exception right away
|
// but raise an exception right away
|
||||||
RollBackIndexesAndRaise(I, True);
|
UnlockPage(newRecord);
|
||||||
|
RollBackIndexesAndRaise(I, ecWriteIndex);
|
||||||
end;
|
end;
|
||||||
|
Inc(I);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// indexes ok -> continue inserting
|
// indexes ok -> continue inserting
|
||||||
@ -2455,7 +2442,8 @@ begin
|
|||||||
// At this point I should "roll back"
|
// At this point I should "roll back"
|
||||||
// the already written index records.
|
// the already written index records.
|
||||||
// if this fails, I'm in deep trouble!
|
// if this fails, I'm in deep trouble!
|
||||||
RollbackIndexesAndRaise(FIndexFiles.Count-1, False);
|
UnlockPage(newRecord);
|
||||||
|
RollbackIndexesAndRaise(FIndexFiles.Count, ecWriteDbf);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// write locking info
|
// write locking info
|
||||||
@ -2479,7 +2467,7 @@ begin
|
|||||||
WriteHeader;
|
WriteHeader;
|
||||||
UnlockPage(0);
|
UnlockPage(0);
|
||||||
// roll back indexes too
|
// roll back indexes too
|
||||||
RollbackIndexesAndRaise(FIndexFiles.Count-1, False);
|
RollbackIndexesAndRaise(FIndexFiles.Count, ecWriteDbf);
|
||||||
end else
|
end else
|
||||||
Result := newRecord;
|
Result := newRecord;
|
||||||
end;
|
end;
|
||||||
@ -2533,13 +2521,26 @@ end;
|
|||||||
procedure TDbfFile.UnlockRecord(RecNo: Integer; Buffer: PChar);
|
procedure TDbfFile.UnlockRecord(RecNo: Integer; Buffer: PChar);
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
lIndex: TIndexFile;
|
lIndex, lErrorIndex: TIndexFile;
|
||||||
begin
|
begin
|
||||||
// update indexes, possible key violation
|
// update indexes, possible key violation
|
||||||
for I := 0 to FIndexFiles.Count - 1 do
|
I := 0;
|
||||||
|
while I < FIndexFiles.Count do
|
||||||
begin
|
begin
|
||||||
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
||||||
lIndex.Update(RecNo, FPrevBuffer, Buffer);
|
if not lIndex.Update(RecNo, FPrevBuffer, Buffer) then
|
||||||
|
begin
|
||||||
|
// error -> rollback
|
||||||
|
lErrorIndex := lIndex;
|
||||||
|
while I > 0 do
|
||||||
|
begin
|
||||||
|
Dec(I);
|
||||||
|
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
||||||
|
lIndex.Update(RecNo, Buffer, FPrevBuffer);
|
||||||
|
end;
|
||||||
|
lErrorIndex.InsertError;
|
||||||
|
end;
|
||||||
|
Inc(I);
|
||||||
end;
|
end;
|
||||||
// write new record buffer, all keys ok
|
// write new record buffer, all keys ok
|
||||||
WriteRecord(RecNo, Buffer);
|
WriteRecord(RecNo, Buffer);
|
||||||
@ -2563,13 +2564,24 @@ end;
|
|||||||
procedure TDbfFile.RecordRecalled(RecNo: Integer; Buffer: PChar);
|
procedure TDbfFile.RecordRecalled(RecNo: Integer; Buffer: PChar);
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
lIndex: TIndexFile;
|
lIndex, lErrorIndex: TIndexFile;
|
||||||
begin
|
begin
|
||||||
// notify indexes: record recalled
|
// notify indexes: record recalled
|
||||||
for I := 0 to FIndexFiles.Count - 1 do
|
I := 0;
|
||||||
|
while I < FIndexFiles.Count do
|
||||||
begin
|
begin
|
||||||
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
lIndex := TIndexFile(FIndexFiles.Items[I]);
|
||||||
lIndex.RecordRecalled(RecNo, Buffer);
|
if not lIndex.RecordRecalled(RecNo, Buffer) then
|
||||||
|
begin
|
||||||
|
lErrorIndex := lIndex;
|
||||||
|
while I > 0 do
|
||||||
|
begin
|
||||||
|
Dec(I);
|
||||||
|
lIndex.RecordDeleted(RecNo, Buffer);
|
||||||
|
end;
|
||||||
|
lErrorIndex.InsertError;
|
||||||
|
end;
|
||||||
|
Inc(I);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@ -106,9 +106,11 @@ type
|
|||||||
FLowBracket: Integer; // = FLowIndex if FPageNo = FLowPage
|
FLowBracket: Integer; // = FLowIndex if FPageNo = FLowPage
|
||||||
FLowIndex: Integer;
|
FLowIndex: Integer;
|
||||||
FLowPage: Integer;
|
FLowPage: Integer;
|
||||||
|
FLowPageTemp: Integer;
|
||||||
FHighBracket: Integer; // = FHighIndex if FPageNo = FHighPage
|
FHighBracket: Integer; // = FHighIndex if FPageNo = FHighPage
|
||||||
FHighIndex: Integer;
|
FHighIndex: Integer;
|
||||||
FHighPage: Integer;
|
FHighPage: Integer;
|
||||||
|
FHighPageTemp: Integer;
|
||||||
|
|
||||||
procedure LocalInsert(RecNo: Integer; Buffer: PChar; LowerPageNo: Integer);
|
procedure LocalInsert(RecNo: Integer; Buffer: PChar; LowerPageNo: Integer);
|
||||||
procedure LocalDelete;
|
procedure LocalDelete;
|
||||||
@ -164,6 +166,8 @@ type
|
|||||||
procedure RecalcWeight;
|
procedure RecalcWeight;
|
||||||
procedure UpdateWeight;
|
procedure UpdateWeight;
|
||||||
procedure Flush;
|
procedure Flush;
|
||||||
|
procedure SaveBracket;
|
||||||
|
procedure RestoreBracket;
|
||||||
|
|
||||||
property Key: PChar read GetKeyData;
|
property Key: PChar read GetKeyData;
|
||||||
property Entry: Pointer read FEntry;
|
property Entry: Pointer read FEntry;
|
||||||
@ -224,6 +228,7 @@ type
|
|||||||
{$endif}
|
{$endif}
|
||||||
protected
|
protected
|
||||||
FIndexName: string;
|
FIndexName: string;
|
||||||
|
FLastError: string;
|
||||||
FParsers: array[0..MaxIndexes-1] of TDbfIndexParser;
|
FParsers: array[0..MaxIndexes-1] of TDbfIndexParser;
|
||||||
FIndexHeaders: array[0..MaxIndexes-1] of Pointer;
|
FIndexHeaders: array[0..MaxIndexes-1] of Pointer;
|
||||||
FIndexHeaderModified: array[0..MaxIndexes-1] of Boolean;
|
FIndexHeaderModified: array[0..MaxIndexes-1] of Boolean;
|
||||||
@ -242,6 +247,7 @@ type
|
|||||||
FTagOffset: Integer;
|
FTagOffset: Integer;
|
||||||
FHeaderPageNo: Integer;
|
FHeaderPageNo: Integer;
|
||||||
FSelectedIndex: Integer;
|
FSelectedIndex: Integer;
|
||||||
|
FRangeIndex: Integer;
|
||||||
FIsDescending: Boolean;
|
FIsDescending: Boolean;
|
||||||
FUniqueMode: TIndexUniqueType;
|
FUniqueMode: TIndexUniqueType;
|
||||||
FModifyMode: TIndexModifyMode;
|
FModifyMode: TIndexModifyMode;
|
||||||
@ -270,6 +276,7 @@ type
|
|||||||
function GetNewPageNo: Integer;
|
function GetNewPageNo: Integer;
|
||||||
procedure TouchHeader(AHeader: Pointer);
|
procedure TouchHeader(AHeader: Pointer);
|
||||||
function CreateTempFile(BaseName: string): TPagedFile;
|
function CreateTempFile(BaseName: string): TPagedFile;
|
||||||
|
procedure ConstructInsertErrorMsg;
|
||||||
procedure WriteIndexHeader(AIndex: Integer);
|
procedure WriteIndexHeader(AIndex: Integer);
|
||||||
procedure SelectIndexVars(AIndex: Integer);
|
procedure SelectIndexVars(AIndex: Integer);
|
||||||
procedure CalcKeyProperties;
|
procedure CalcKeyProperties;
|
||||||
@ -278,11 +285,12 @@ type
|
|||||||
function CalcTagOffset(AIndex: Integer): Pointer;
|
function CalcTagOffset(AIndex: Integer): Pointer;
|
||||||
|
|
||||||
function FindKey(AInsert: boolean): Integer;
|
function FindKey(AInsert: boolean): Integer;
|
||||||
procedure InsertKey(Buffer: PChar);
|
function InsertKey(Buffer: PChar): Boolean;
|
||||||
procedure DeleteKey(Buffer: PChar);
|
procedure DeleteKey(Buffer: PChar);
|
||||||
procedure InsertCurrent;
|
function InsertCurrent: Boolean;
|
||||||
procedure DeleteCurrent;
|
procedure DeleteCurrent;
|
||||||
procedure UpdateCurrent(PrevBuffer, NewBuffer: PChar);
|
function UpdateCurrent(PrevBuffer, NewBuffer: PChar): Boolean;
|
||||||
|
function UpdateIndex(Index: Integer; PrevBuffer, NewBuffer: PChar): Boolean;
|
||||||
procedure ReadIndexes;
|
procedure ReadIndexes;
|
||||||
procedure Resync(Relative: boolean);
|
procedure Resync(Relative: boolean);
|
||||||
procedure ResyncRoot;
|
procedure ResyncRoot;
|
||||||
@ -329,12 +337,12 @@ type
|
|||||||
procedure AddNewLevel;
|
procedure AddNewLevel;
|
||||||
procedure UnlockHeader;
|
procedure UnlockHeader;
|
||||||
procedure InsertError;
|
procedure InsertError;
|
||||||
procedure Insert(RecNo: Integer; Buffer: PChar);
|
function Insert(RecNo: Integer; Buffer: PChar): Boolean;
|
||||||
procedure Update(RecNo: Integer; PrevBuffer, NewBuffer: PChar);
|
function Update(RecNo: Integer; PrevBuffer, NewBuffer: PChar): Boolean;
|
||||||
procedure Delete(RecNo: Integer; Buffer: PChar);
|
procedure Delete(RecNo: Integer; Buffer: PChar);
|
||||||
function CheckKeyViolation(Buffer: PChar): Boolean;
|
function CheckKeyViolation(Buffer: PChar): Boolean;
|
||||||
procedure RecordDeleted(RecNo: Integer; Buffer: PChar);
|
procedure RecordDeleted(RecNo: Integer; Buffer: PChar);
|
||||||
procedure RecordRecalled(RecNo: Integer; Buffer: PChar);
|
function RecordRecalled(RecNo: Integer; Buffer: PChar): Boolean;
|
||||||
procedure DeleteIndex(const AIndexName: string);
|
procedure DeleteIndex(const AIndexName: string);
|
||||||
procedure RepageFile;
|
procedure RepageFile;
|
||||||
procedure CompactFile;
|
procedure CompactFile;
|
||||||
@ -345,6 +353,8 @@ type
|
|||||||
function SearchKey(Key: PChar; SearchType: TSearchKeyType): Boolean;
|
function SearchKey(Key: PChar; SearchType: TSearchKeyType): Boolean;
|
||||||
function Find(RecNo: Integer; Buffer: PChar): Integer;
|
function Find(RecNo: Integer; Buffer: PChar): Integer;
|
||||||
function IndexOf(const AIndexName: string): Integer;
|
function IndexOf(const AIndexName: string): Integer;
|
||||||
|
procedure DisableRange;
|
||||||
|
procedure EnableRange;
|
||||||
|
|
||||||
procedure GetIndexNames(const AList: TStrings);
|
procedure GetIndexNames(const AList: TStrings);
|
||||||
procedure GetIndexInfo(const AIndexName: string; IndexDef: TDbfIndexDef);
|
procedure GetIndexInfo(const AIndexName: string; IndexDef: TDbfIndexDef);
|
||||||
@ -633,7 +643,7 @@ end;
|
|||||||
|
|
||||||
procedure IncIntLE(var AVariable: Integer; Amount: Integer);
|
procedure IncIntLE(var AVariable: Integer; Amount: Integer);
|
||||||
begin
|
begin
|
||||||
AVariable := SwapIntLE(SwapIntLE(AVariable) + Amount);
|
AVariable := SwapIntLE(DWord(Integer(SwapIntLE(AVariable)) + Amount));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//==========================================================
|
//==========================================================
|
||||||
@ -656,9 +666,8 @@ begin
|
|||||||
EnumSystemLocales(@LocaleCallBack, LCID_SUPPORTED);
|
EnumSystemLocales(@LocaleCallBack, LCID_SUPPORTED);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//==========================================================
|
{ TIndexPage }
|
||||||
//============ TIndexPage
|
|
||||||
//==========================================================
|
|
||||||
constructor TIndexPage.Create(Parent: TIndexFile);
|
constructor TIndexPage.Create(Parent: TIndexFile);
|
||||||
begin
|
begin
|
||||||
FIndexFile := Parent;
|
FIndexFile := Parent;
|
||||||
@ -1386,6 +1395,18 @@ begin
|
|||||||
FLowerPage.RecurLast;
|
FLowerPage.RecurLast;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TIndexPage.SaveBracket;
|
||||||
|
begin
|
||||||
|
FLowPageTemp := FLowPage;
|
||||||
|
FHighPageTemp := FHighPage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TIndexPage.RestoreBracket;
|
||||||
|
begin
|
||||||
|
FLowPage := FLowPageTemp;
|
||||||
|
FHighPage := FHighPageTemp;
|
||||||
|
end;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
//============ Mdx specific access routines
|
//============ Mdx specific access routines
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
@ -1733,6 +1754,7 @@ begin
|
|||||||
FUpdateMode := umCurrent;
|
FUpdateMode := umCurrent;
|
||||||
FModifyMode := mmNormal;
|
FModifyMode := mmNormal;
|
||||||
FTempMode := TDbfFile(ADbfFile).TempMode;
|
FTempMode := TDbfFile(ADbfFile).TempMode;
|
||||||
|
FRangeIndex := -1;
|
||||||
SelectIndexVars(-1);
|
SelectIndexVars(-1);
|
||||||
for I := 0 to MaxIndexes - 1 do
|
for I := 0 to MaxIndexes - 1 do
|
||||||
begin
|
begin
|
||||||
@ -2772,9 +2794,9 @@ begin
|
|||||||
UnlockPage(0);
|
UnlockPage(0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.Insert(RecNo: Integer; Buffer: PChar); {override;}
|
function TIndexFile.Insert(RecNo: Integer; Buffer: PChar): Boolean; {override;}
|
||||||
var
|
var
|
||||||
I, curSel: Integer;
|
I, curSel, count: Integer;
|
||||||
begin
|
begin
|
||||||
// check if updating all or only current
|
// check if updating all or only current
|
||||||
FUserRecNo := RecNo;
|
FUserRecNo := RecNo;
|
||||||
@ -2782,15 +2804,28 @@ begin
|
|||||||
begin
|
begin
|
||||||
// remember currently selected index
|
// remember currently selected index
|
||||||
curSel := FSelectedIndex;
|
curSel := FSelectedIndex;
|
||||||
for I := 0 to SwapWordLE(PMdxHdr(Header)^.TagsUsed) - 1 do
|
Result := true;
|
||||||
|
I := 0;
|
||||||
|
count := SwapWordLE(PMdxHdr(Header)^.TagsUsed);
|
||||||
|
while I < count do
|
||||||
begin
|
begin
|
||||||
SelectIndexVars(I);
|
SelectIndexVars(I);
|
||||||
InsertKey(Buffer);
|
Result := InsertKey(Buffer);
|
||||||
|
if not Result then
|
||||||
|
begin
|
||||||
|
while I > 0 do
|
||||||
|
begin
|
||||||
|
Dec(I);
|
||||||
|
DeleteKey(Buffer);
|
||||||
|
end;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
Inc(I);
|
||||||
end;
|
end;
|
||||||
// restore previous selected index
|
// restore previous selected index
|
||||||
SelectIndexVars(curSel);
|
SelectIndexVars(curSel);
|
||||||
end else begin
|
end else begin
|
||||||
InsertKey(Buffer);
|
Result := InsertKey(Buffer);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// check range, disabled by insert
|
// check range, disabled by insert
|
||||||
@ -2949,8 +2984,9 @@ begin
|
|||||||
TranslateString(GetACP, FCodePage, Result, Result, KeyLen);
|
TranslateString(GetACP, FCodePage, Result, Result, KeyLen);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.InsertKey(Buffer: PChar);
|
function TIndexFile.InsertKey(Buffer: PChar): boolean;
|
||||||
begin
|
begin
|
||||||
|
Result := true;
|
||||||
// ignore deleted records
|
// ignore deleted records
|
||||||
if (FModifyMode = mmNormal) and (FUniqueMode = iuDistinct) and (Buffer^ = '*') then
|
if (FModifyMode = mmNormal) and (FUniqueMode = iuDistinct) and (Buffer^ = '*') then
|
||||||
exit;
|
exit;
|
||||||
@ -2960,16 +2996,17 @@ begin
|
|||||||
// get key from buffer
|
// get key from buffer
|
||||||
FUserKey := ExtractKeyFromBuffer(Buffer);
|
FUserKey := ExtractKeyFromBuffer(Buffer);
|
||||||
// patch through
|
// patch through
|
||||||
InsertCurrent;
|
Result := InsertCurrent;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.InsertCurrent;
|
function TIndexFile.InsertCurrent: boolean;
|
||||||
// insert in current index
|
// insert in current index
|
||||||
// assumes: FUserKey is an OEM key
|
// assumes: FUserKey is an OEM key
|
||||||
begin
|
begin
|
||||||
// only insert if not recalling or mode = distinct
|
// only insert if not recalling or mode = distinct
|
||||||
// modify = mmDeleteRecall /\ unique <> distinct -> key already present
|
// modify = mmDeleteRecall /\ unique <> distinct -> key already present
|
||||||
|
Result := true;
|
||||||
if (FModifyMode <> mmDeleteRecall) or (FUniqueMode = iuDistinct) then
|
if (FModifyMode <> mmDeleteRecall) or (FUniqueMode = iuDistinct) then
|
||||||
begin
|
begin
|
||||||
// temporarily remove range to find correct location of key
|
// temporarily remove range to find correct location of key
|
||||||
@ -2989,20 +3026,31 @@ begin
|
|||||||
begin
|
begin
|
||||||
// raising -> reset modify mode
|
// raising -> reset modify mode
|
||||||
FModifyMode := mmNormal;
|
FModifyMode := mmNormal;
|
||||||
InsertError;
|
ConstructInsertErrorMsg;
|
||||||
|
Result := false;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.InsertError;
|
procedure TIndexFile.ConstructInsertErrorMsg;
|
||||||
var
|
var
|
||||||
InfoKey: string;
|
InfoKey: string;
|
||||||
begin
|
begin
|
||||||
// prepare info for user
|
if Length(FLastError) > 0 then exit;
|
||||||
InfoKey := FUserKey;
|
InfoKey := FUserKey;
|
||||||
SetLength(InfoKey, KeyLen);
|
SetLength(InfoKey, KeyLen);
|
||||||
raise EDbfError.CreateFmt(STRING_KEY_VIOLATION, [GetName, PhysicalRecNo, TrimRight(InfoKey)]);
|
FLastError := Format(STRING_KEY_VIOLATION, [GetName,
|
||||||
|
PhysicalRecNo, TrimRight(InfoKey)]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TIndexFile.InsertError;
|
||||||
|
var
|
||||||
|
errorStr: string;
|
||||||
|
begin
|
||||||
|
errorStr := FLastError;
|
||||||
|
FLastError := '';
|
||||||
|
raise EDbfError.Create(errorStr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.Delete(RecNo: Integer; Buffer: PChar);
|
procedure TIndexFile.Delete(RecNo: Integer; Buffer: PChar);
|
||||||
@ -3059,9 +3107,15 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.Update(RecNo: Integer; PrevBuffer, NewBuffer: PChar);
|
function TIndexFile.UpdateIndex(Index: Integer; PrevBuffer, NewBuffer: PChar): Boolean;
|
||||||
|
begin
|
||||||
|
SelectIndexVars(Index);
|
||||||
|
Result := UpdateCurrent(PrevBuffer, NewBuffer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TIndexFile.Update(RecNo: Integer; PrevBuffer, NewBuffer: PChar): Boolean;
|
||||||
var
|
var
|
||||||
I, curSel: Integer;
|
I, curSel, count: Integer;
|
||||||
begin
|
begin
|
||||||
// check if updating all or only current
|
// check if updating all or only current
|
||||||
FUserRecNo := RecNo;
|
FUserRecNo := RecNo;
|
||||||
@ -3069,42 +3123,60 @@ begin
|
|||||||
begin
|
begin
|
||||||
// remember currently selected index
|
// remember currently selected index
|
||||||
curSel := FSelectedIndex;
|
curSel := FSelectedIndex;
|
||||||
for I := 0 to SwapWordLE(PMdxHdr(Header)^.TagsUsed) - 1 do
|
Result := true;
|
||||||
|
I := 0;
|
||||||
|
count := SwapWordLE(PMdxHdr(Header)^.TagsUsed);
|
||||||
|
while I < count do
|
||||||
begin
|
begin
|
||||||
SelectIndexVars(I);
|
Result := UpdateIndex(I, PrevBuffer, NewBuffer);
|
||||||
UpdateCurrent(PrevBuffer, NewBuffer);
|
if not Result then
|
||||||
|
begin
|
||||||
|
// rollback updates to previous indexes
|
||||||
|
while I > 0 do
|
||||||
|
begin
|
||||||
|
Dec(I);
|
||||||
|
UpdateIndex(I, NewBuffer, PrevBuffer);
|
||||||
|
end;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
Inc(I);
|
||||||
end;
|
end;
|
||||||
// restore previous selected index
|
// restore previous selected index
|
||||||
SelectIndexVars(curSel);
|
SelectIndexVars(curSel);
|
||||||
end else begin
|
end else begin
|
||||||
UpdateCurrent(PrevBuffer, NewBuffer);
|
Result := UpdateCurrent(PrevBuffer, NewBuffer);
|
||||||
end;
|
end;
|
||||||
// check range, disabled by delete/insert
|
// check range, disabled by delete/insert
|
||||||
if (FRoot.LowPage = 0) and (FRoot.HighPage = 0) then
|
if (FRoot.LowPage = 0) and (FRoot.HighPage = 0) then
|
||||||
ResyncRange(true);
|
ResyncRange(true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.UpdateCurrent(PrevBuffer, NewBuffer: PChar);
|
function TIndexFile.UpdateCurrent(PrevBuffer, NewBuffer: PChar): boolean;
|
||||||
var
|
var
|
||||||
|
InsertKey, DeleteKey: PChar;
|
||||||
TempBuffer: array [0..100] of Char;
|
TempBuffer: array [0..100] of Char;
|
||||||
begin
|
begin
|
||||||
|
Result := true;
|
||||||
if FCanEdit and (PIndexHdr(FIndexHeader)^.KeyLen <> 0) then
|
if FCanEdit and (PIndexHdr(FIndexHeader)^.KeyLen <> 0) then
|
||||||
begin
|
begin
|
||||||
// get key from newbuffer
|
DeleteKey := ExtractKeyFromBuffer(PrevBuffer);
|
||||||
FUserKey := ExtractKeyFromBuffer(NewBuffer);
|
Move(DeleteKey^, TempBuffer, SwapWordLE(PIndexHdr(FIndexHeader)^.KeyLen));
|
||||||
Move(FUserKey^, TempBuffer, SwapWordLE(PIndexHdr(FIndexHeader)^.KeyLen));
|
DeleteKey := @TempBuffer[0];
|
||||||
// get key from prevbuffer
|
InsertKey := ExtractKeyFromBuffer(NewBuffer);
|
||||||
FUserKey := ExtractKeyFromBuffer(PrevBuffer);
|
|
||||||
|
|
||||||
// compare to see if anything changed
|
// compare to see if anything changed
|
||||||
if CompareKey(@TempBuffer[0]) <> 0 then
|
if CompareKeys(DeleteKey, InsertKey) <> 0 then
|
||||||
begin
|
begin
|
||||||
// first set userkey to key to delete
|
FUserKey := DeleteKey;
|
||||||
// FUserKey = KeyFrom(PrevBuffer)
|
|
||||||
DeleteCurrent;
|
DeleteCurrent;
|
||||||
// now set userkey to key to insert
|
FUserKey := InsertKey;
|
||||||
FUserKey := @TempBuffer[0];
|
Result := InsertCurrent;
|
||||||
InsertCurrent;
|
if not Result then
|
||||||
|
begin
|
||||||
|
FUserKey := DeleteKey;
|
||||||
|
InsertCurrent;
|
||||||
|
FUserKey := InsertKey;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -3333,11 +3405,11 @@ begin
|
|||||||
FModifyMode := mmNormal;
|
FModifyMode := mmNormal;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TIndexFile.RecordRecalled(RecNo: Integer; Buffer: PChar);
|
function TIndexFile.RecordRecalled(RecNo: Integer; Buffer: PChar): Boolean;
|
||||||
begin
|
begin
|
||||||
// are we distinct -> then reinsert record in index
|
// are we distinct -> then reinsert record in index
|
||||||
FModifyMode := mmDeleteRecall;
|
FModifyMode := mmDeleteRecall;
|
||||||
Insert(RecNo, Buffer);
|
Result := Insert(RecNo, Buffer);
|
||||||
FModifyMode := mmNormal;
|
FModifyMode := mmNormal;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -3664,6 +3736,30 @@ begin
|
|||||||
until TempPage = nil;
|
until TempPage = nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TIndexFile.DisableRange;
|
||||||
|
var
|
||||||
|
TempPage: TIndexPage;
|
||||||
|
begin
|
||||||
|
TempPage := FRoot;
|
||||||
|
repeat
|
||||||
|
TempPage.SaveBracket;
|
||||||
|
TempPage := TempPage.LowerPage;
|
||||||
|
until TempPage = nil;
|
||||||
|
CancelRange;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TIndexFile.EnableRange;
|
||||||
|
var
|
||||||
|
TempPage: TIndexPage;
|
||||||
|
begin
|
||||||
|
TempPage := FRoot;
|
||||||
|
repeat
|
||||||
|
TempPage.RestoreBracket;
|
||||||
|
TempPage := TempPage.LowerPage;
|
||||||
|
until TempPage = nil;
|
||||||
|
FRangeActive := true;
|
||||||
|
end;
|
||||||
|
|
||||||
function MemComp(P1, P2: Pointer; const Length: Integer): Integer;
|
function MemComp(P1, P2: Pointer; const Length: Integer): Integer;
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
@ -3781,9 +3877,22 @@ begin
|
|||||||
found := IndexOf(AIndexName);
|
found := IndexOf(AIndexName);
|
||||||
end else
|
end else
|
||||||
found := 0;
|
found := 0;
|
||||||
|
// if changing index, range is N/A anymore
|
||||||
|
if FRangeActive and (found <> FSelectedIndex) then
|
||||||
|
begin
|
||||||
|
FRangeIndex := FSelectedIndex;
|
||||||
|
DisableRange;
|
||||||
|
end;
|
||||||
// we can now select by index
|
// we can now select by index
|
||||||
if found >= 0 then
|
if found >= 0 then
|
||||||
|
begin
|
||||||
SelectIndexVars(found);
|
SelectIndexVars(found);
|
||||||
|
if found = FRangeIndex then
|
||||||
|
begin
|
||||||
|
EnableRange;
|
||||||
|
FRangeIndex := -1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TIndexFile.CalcTagOffset(AIndex: Integer): Pointer;
|
function TIndexFile.CalcTagOffset(AIndex: Integer): Pointer;
|
||||||
|
|||||||
@ -40,6 +40,8 @@ V6.9.1
|
|||||||
- fix index result too long bug
|
- fix index result too long bug
|
||||||
- add support for big endian
|
- add support for big endian
|
||||||
- fix non-raw string field filter
|
- fix non-raw string field filter
|
||||||
|
- fix index inserts/updates to be reverted on key violations
|
||||||
|
- allow lookups to ignore active filter
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
V6.9.0
|
V6.9.0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user