* update tdbf to release 6.9.1

git-svn-id: trunk@6721 -
This commit is contained in:
micha 2007-03-04 22:10:45 +00:00
parent c13ff3729b
commit 3c581e3f42
4 changed files with 260 additions and 118 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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