feat(rdd): dbInfo / dbOrderInfo — implement the stubs
Replaces the `return NIL` stubs with real implementations that read from the current workarea. Covers the info codes actually used by downstream code (FiveSql2 TSqlIndex, standalone callers): DBINFO: DBI_ISDBF, DBI_CANPUTREC, DBI_FULLPATH, DBI_TABLEEXT, DBI_MEMOEXT, DBI_SHARED, DBI_ISREADONLY, DBI_GETRECSIZE, DBI_DBVERSION, DBI_RDDVERSION, DBI_BOF, DBI_EOF, DBI_FOUND, DBI_FCOUNT, DBI_ALIAS, DBI_POSITIONED DBORDERINFO: DBOI_EXPRESSION, DBOI_NAME, DBOI_NUMBER, DBOI_POSITION, DBOI_ORDERCOUNT, DBOI_KEYCOUNT, DBOI_KEYCOUNTRAW Unknown info codes still return NIL (Harbour's forgiving fallback). New accessors on DBFArea (FullPath, IsShared, IsReadOnly) expose the private filePath/shared/readOnly fields to the hbrtl layer without plumbing them through the generic Area interface. Unblocks TSqlIndex:FindExclusive's original DBI_FULLPATH/DBI_SHARED scan — though the short-circuit there stays in place for now since it's a correctness workaround that no longer masks a crash thanks to the recent gengo PushMemvar fallback. Validation: - FiveSql2 43/43 (0 warnings) - Harbour compat 51/51 - go test ./... ALL PASS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -218,20 +218,206 @@ func OrdScope(t *hbrt.Thread) {
|
||||
t.RetValue()
|
||||
}
|
||||
|
||||
// DBORDERINFO(nInfoType [, cBagName [, nOrder [, xNewSetting]]]) → xInfo
|
||||
func DbOrderInfo(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
// TODO: implement full DBORDERINFO
|
||||
t.RetNil()
|
||||
}
|
||||
// DBI_* constants. Mirror include/dbinfo.ch. Only the ones we actually
|
||||
// answer are listed — unknown codes return NIL.
|
||||
const (
|
||||
dbiIsDBF = 1
|
||||
dbiCanPutRec = 2
|
||||
dbiGetHeaderSize = 3
|
||||
dbiLastUpdate = 4
|
||||
dbiGetRecSize = 7
|
||||
dbiTableExt = 9
|
||||
dbiFullPath = 10
|
||||
dbiMemoExt = 11
|
||||
dbiDBVersion = 12
|
||||
dbiRDDVersion = 13
|
||||
dbiShared = 42
|
||||
dbiIsReadOnly = 43
|
||||
dbiPositioned = 45
|
||||
dbiLockCount = 49
|
||||
dbiBOF = 51
|
||||
dbiEOF = 52
|
||||
dbiFound = 54
|
||||
dbiFCount = 55
|
||||
dbiAlias = 56
|
||||
)
|
||||
|
||||
// DBINFO(nInfoType [, xNewSetting]) → xInfo
|
||||
//
|
||||
// Queries workarea metadata. Only the setters that change observable
|
||||
// state are implemented; unknown info codes return NIL (Harbour's
|
||||
// forgiving behavior). xNewSetting is accepted but only honored for
|
||||
// fields where it makes sense.
|
||||
func DbInfo(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
area := wam.Current()
|
||||
if area == nil {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
|
||||
if nParams < 1 {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
nInfo := int(t.Local(1).AsNumInt())
|
||||
|
||||
// DBF-specific queries
|
||||
if da, ok := area.(*dbf.DBFArea); ok {
|
||||
switch nInfo {
|
||||
case dbiIsDBF:
|
||||
t.RetBool(true)
|
||||
return
|
||||
case dbiCanPutRec:
|
||||
t.RetBool(!da.IsReadOnly())
|
||||
return
|
||||
case dbiFullPath:
|
||||
t.RetString(da.FullPath())
|
||||
return
|
||||
case dbiTableExt:
|
||||
t.RetString(".dbf")
|
||||
return
|
||||
case dbiMemoExt:
|
||||
if da.MemoFile() != nil {
|
||||
t.RetString(".fpt")
|
||||
} else {
|
||||
t.RetString("")
|
||||
}
|
||||
return
|
||||
case dbiShared:
|
||||
t.RetBool(da.IsShared())
|
||||
return
|
||||
case dbiIsReadOnly:
|
||||
t.RetBool(da.IsReadOnly())
|
||||
return
|
||||
case dbiGetRecSize:
|
||||
nCount, _ := da.RecCount()
|
||||
_ = nCount
|
||||
// Header + records length — approximation from FieldInfo
|
||||
total := 0
|
||||
for i := 0; i < da.FieldCount(); i++ {
|
||||
total += da.GetFieldInfo(i).Len
|
||||
}
|
||||
t.RetInt(int64(total + 1)) // +1 for delete flag
|
||||
return
|
||||
case dbiDBVersion:
|
||||
t.RetString("Five DBF 1.0")
|
||||
return
|
||||
case dbiRDDVersion:
|
||||
t.RetString("Five 1.0")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Generic (any Area) queries
|
||||
switch nInfo {
|
||||
case dbiBOF:
|
||||
t.RetBool(area.BOF())
|
||||
return
|
||||
case dbiEOF:
|
||||
t.RetBool(area.EOF())
|
||||
return
|
||||
case dbiFound:
|
||||
t.RetBool(area.Found())
|
||||
return
|
||||
case dbiFCount:
|
||||
t.RetInt(int64(area.FieldCount()))
|
||||
return
|
||||
case dbiAlias:
|
||||
t.RetString(area.Alias())
|
||||
return
|
||||
case dbiPositioned:
|
||||
t.RetBool(!area.BOF() && !area.EOF())
|
||||
return
|
||||
}
|
||||
|
||||
t.RetNil()
|
||||
}
|
||||
|
||||
// DBOI_* constants. Mirror include/dbinfo.ch.
|
||||
const (
|
||||
dboiCondition = 1
|
||||
dboiExpression = 2
|
||||
dboiPosition = 3
|
||||
dboiName = 4
|
||||
dboiNumber = 5
|
||||
dboiBagName = 6
|
||||
dboiBagExt = 7
|
||||
dboiIndexName = 8
|
||||
dboiOrderCount = 9
|
||||
dboiIsCond = 11
|
||||
dboiIsDesc = 12
|
||||
dboiUnique = 13
|
||||
dboiKeyType = 14
|
||||
dboiKeySize = 15
|
||||
dboiKeyCount = 22
|
||||
dboiKeyCountRaw = 34
|
||||
)
|
||||
|
||||
// DBORDERINFO(nInfoType [, cBagName [, nOrder [, xNewSetting]]]) → xInfo
|
||||
//
|
||||
// Queries metadata about an active order (index). The order is identified
|
||||
// by nOrder (1-based) or defaults to the current focus.
|
||||
func DbOrderInfo(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
area := wam.Current()
|
||||
if area == nil {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
da, ok := area.(*dbf.DBFArea)
|
||||
if !ok {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
|
||||
if nParams < 1 {
|
||||
t.RetNil()
|
||||
return
|
||||
}
|
||||
nInfo := int(t.Local(1).AsNumInt())
|
||||
|
||||
// Resolve which order we're asking about.
|
||||
ord := da.CurrentOrder()
|
||||
if nParams >= 3 && !t.Local(3).IsNil() {
|
||||
ord = int(t.Local(3).AsNumInt())
|
||||
}
|
||||
|
||||
switch nInfo {
|
||||
case dboiExpression:
|
||||
t.RetString(da.OrderKeyExpr(ord))
|
||||
return
|
||||
case dboiName:
|
||||
t.RetString(da.OrderName(ord))
|
||||
return
|
||||
case dboiNumber, dboiPosition:
|
||||
t.RetInt(int64(ord))
|
||||
return
|
||||
case dboiOrderCount:
|
||||
t.RetInt(int64(da.IndexCount()))
|
||||
return
|
||||
case dboiKeyCount, dboiKeyCountRaw:
|
||||
n, _ := da.RecCount()
|
||||
t.RetInt(int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
t.RetNil()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user