fix: 5 seek/dbf bugs — 77/77 thorough Harbour compatibility
1. SOFTSEEK: use idx.CurRecNo() for positioning (was checking recNo > 0) - SEEK with SET SOFTSEEK ON now positions at next higher key - SEEK command reads SET SOFTSEEK at runtime (was compile-time only) - rtlDbSeek defaults to GetSetSoftSeek() when no explicit param 2. SET DELETED ON + INDEX: SkipIndexed skips deleted records - GoTopIndexed: skip deleted record at top position - SkipIndexed: inner loop continues past deleted records 3. Compound key (CITY+NAME): field name TrimSpace before lookup - evalKeyExprInner: TrimSpace on fieldName after FIELD-> strip - Fixed "CITY " != "CITY" mismatch from + operator splitting 4. SET INDEX TO filename: treated as string, not variable - gengo uses exprToString for SET INDEX TO (was emitExpr) - Prevents identifier being resolved as local variable 5. hasXBaseCommands: recursive scan into nested blocks - BEGIN SEQUENCE, IF, FOR, DO WHILE, SWITCH bodies now scanned - Fixes missing hbrdd import for DB commands inside blocks Thorough test: 77 items (14 sections) covering exact/partial/soft seek, SET DELETED, duplicate keys, numeric keys, compound keys, empty/single table, state consistency, order switching, full traversal — all identical. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -416,11 +416,15 @@ func (a *DBFArea) Seek(key hbrt.Value, softSeek bool, findLast bool) (bool, erro
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if softSeek && recNo > 0 && !idx.IsEOF() {
|
||||
a.GoTo(recNo)
|
||||
a.FEof = false
|
||||
a.SetFound(false)
|
||||
return false, nil
|
||||
if softSeek && !idx.IsEOF() {
|
||||
// Softseek: position at the next higher key
|
||||
posRecNo := idx.CurRecNo()
|
||||
if posRecNo > 0 {
|
||||
a.GoTo(posRecNo)
|
||||
a.FEof = false
|
||||
a.SetFound(false)
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Not found — go to EOF
|
||||
@@ -464,7 +468,12 @@ func (a *DBFArea) GoTopIndexed() error {
|
||||
a.FEof = true
|
||||
return a.GoTo(rc + 1)
|
||||
}
|
||||
return a.GoTo(idx.CurRecNo())
|
||||
a.GoTo(idx.CurRecNo())
|
||||
// Skip deleted records at top
|
||||
if hbrdd.IsSetDeleted != nil && hbrdd.IsSetDeleted() && a.Deleted() {
|
||||
return a.SkipIndexed(1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GoBottomIndexed positions at the last key in the active index.
|
||||
@@ -525,23 +534,35 @@ func (a *DBFArea) SkipIndexed(count int64) error {
|
||||
idx := a.idxState.indexes[a.idxState.current]
|
||||
hasScope := a.idxState.scopeTop != nil || a.idxState.scopeBottom != nil
|
||||
|
||||
setDel := hbrdd.IsSetDeleted != nil && hbrdd.IsSetDeleted()
|
||||
|
||||
if count > 0 {
|
||||
for i := int64(0); i < count; i++ {
|
||||
idx.SkipNext()
|
||||
if idx.IsEOF() || idx.CurRecNo() == 0 {
|
||||
rc, _ := a.RecCount()
|
||||
a.GoTo(rc + 1)
|
||||
a.FEof = true
|
||||
return nil
|
||||
}
|
||||
// Check bottom scope
|
||||
if hasScope && a.idxState.scopeBottom != nil {
|
||||
if bytes.Compare(idx.CurKey(), a.idxState.scopeBottom) > 0 {
|
||||
for {
|
||||
idx.SkipNext()
|
||||
if idx.IsEOF() || idx.CurRecNo() == 0 {
|
||||
rc, _ := a.RecCount()
|
||||
a.GoTo(rc + 1)
|
||||
a.FEof = true
|
||||
return nil
|
||||
}
|
||||
// Check bottom scope
|
||||
if hasScope && a.idxState.scopeBottom != nil {
|
||||
if bytes.Compare(idx.CurKey(), a.idxState.scopeBottom) > 0 {
|
||||
rc, _ := a.RecCount()
|
||||
a.GoTo(rc + 1)
|
||||
a.FEof = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Skip deleted records
|
||||
if setDel {
|
||||
a.GoTo(idx.CurRecNo())
|
||||
if a.Deleted() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if count < 0 {
|
||||
@@ -737,9 +758,9 @@ func (a *DBFArea) evalKeyExprInner(expr string) []byte {
|
||||
}
|
||||
|
||||
// Strip FIELD-> or _FIELD-> or alias-> prefix (Harbour: M->var, FIELD->var)
|
||||
fieldName := upper
|
||||
fieldName := strings.TrimSpace(upper)
|
||||
if idx := strings.Index(fieldName, "->"); idx >= 0 {
|
||||
fieldName = fieldName[idx+2:]
|
||||
fieldName = strings.TrimSpace(fieldName[idx+2:])
|
||||
}
|
||||
|
||||
// Simple field name
|
||||
|
||||
Reference in New Issue
Block a user