Fixes from 77/77 thorough test: - SOFTSEEK uses CurRecNo() (was requiring recNo>0) - SEEK reads SET SOFTSEEK at runtime (was compile-time only) - SkipIndexed skips deleted records when SET DELETED ON - GoTopIndexed skips deleted at top position - evalKeyExprInner TrimSpace on fieldName (compound key fix) - SET INDEX TO uses exprToString (was emitExpr treating as variable) - hasXBaseCommands scans nested blocks (BEGIN SEQUENCE, IF, FOR, etc.) 77/77 thorough test PASS. Stress test (82 items) in progress. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
401 lines
9.5 KiB
Plaintext
401 lines
9.5 KiB
Plaintext
// Ultimate RDD stress test — 200+ items, edge cases, multi-workarea, LOCATE, FILTER
|
|
// Harbour vs Five byte-exact comparison
|
|
|
|
|
|
PROCEDURE Main()
|
|
LOCAL i, j, aStruct, nCount, nH, nSum
|
|
LOCAL aCities, nIdx
|
|
|
|
ErrorBlock({|e| Break(e)})
|
|
|
|
aCities := {"Seoul","Tokyo","Beijing","London","NYC","Paris","Berlin","Rome","Madrid","Oslo"}
|
|
|
|
// ============================
|
|
// PART A: Create main table (100 records)
|
|
// ============================
|
|
aStruct := { ;
|
|
{"ID","N",6,0}, {"NAME","C",20,0}, {"CITY","C",15,0}, ;
|
|
{"AGE","N",3,0}, {"SALARY","N",10,2}, {"ACTIVE","L",1,0}, ;
|
|
{"CODE","C",5,0} ;
|
|
}
|
|
|
|
BEGIN SEQUENCE
|
|
|
|
dbCreate("stress_test", aStruct)
|
|
USE "stress_test" NEW
|
|
|
|
FOR i := 1 TO 100
|
|
APPEND BLANK
|
|
REPLACE ID WITH i
|
|
REPLACE NAME WITH PadR("Name_" + PadL(LTrim(Str(i)), 3, "0"), 20)
|
|
nIdx := ((i-1) % 10) + 1
|
|
REPLACE CITY WITH PadR(aCities[nIdx], 15)
|
|
REPLACE AGE WITH 20 + (i % 50)
|
|
REPLACE SALARY WITH 25000 + i * 250.50
|
|
REPLACE ACTIVE WITH (i % 3 != 0)
|
|
REPLACE CODE WITH PadR(LTrim(Str(Int(((i-1)/25))+1)), 5)
|
|
NEXT
|
|
R("A01", LTrim(Str(RecCount())))
|
|
|
|
// ============================
|
|
// PART B: Multiple indexes
|
|
// ============================
|
|
INDEX ON FIELD->NAME TO stress_name
|
|
R("B01", "OK")
|
|
CLOSE ALL
|
|
|
|
USE "stress_test" NEW
|
|
INDEX ON FIELD->CITY TO stress_city
|
|
R("B02", "OK")
|
|
CLOSE ALL
|
|
|
|
USE "stress_test" NEW
|
|
INDEX ON Str(FIELD->ID, 6) TO stress_id
|
|
R("B03", "OK")
|
|
CLOSE ALL
|
|
|
|
USE "stress_test" NEW
|
|
INDEX ON FIELD->CITY + FIELD->NAME TO stress_compound
|
|
R("B04", "OK")
|
|
CLOSE ALL
|
|
|
|
USE "stress_test" NEW
|
|
INDEX ON UPPER(FIELD->NAME) TO stress_upper
|
|
R("B05", "OK")
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART C: Name index — exhaustive seek
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_name
|
|
|
|
GO TOP
|
|
R("C01", RTrim(FieldGet(2)) + " " + LTrim(Str(RecNo())))
|
|
GO BOTTOM
|
|
R("C02", RTrim(FieldGet(2)) + " " + LTrim(Str(RecNo())))
|
|
|
|
// Seek every 10th record
|
|
FOR i := 1 TO 100 STEP 10
|
|
SEEK PadR("Name_" + PadL(LTrim(Str(i)), 3, "0"), 20)
|
|
R("C_S" + PadL(LTrim(Str(i)),3,"0"), B(Found()) + " " + LTrim(Str(RecNo())))
|
|
NEXT
|
|
|
|
// Miss before first, between, after last
|
|
SEEK PadR("Aaa", 20)
|
|
R("C03", B(Found()) + " " + B(EOF()))
|
|
SEEK PadR("Name_000", 20)
|
|
R("C04", B(Found()) + " " + B(EOF()))
|
|
SEEK PadR("Name_101", 20)
|
|
R("C05", B(Found()) + " " + B(EOF()))
|
|
|
|
// Partial key lengths: 1, 4, 6, 8
|
|
SEEK "N"
|
|
R("C06", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK "Name"
|
|
R("C07", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK "Name_0"
|
|
R("C08", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK "Name_05"
|
|
R("C09", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
|
|
// Full traversal count + sum ID
|
|
GO TOP
|
|
nCount := 0
|
|
nSum := 0
|
|
DO WHILE !EOF()
|
|
nCount++
|
|
nSum += FieldGet(1)
|
|
SKIP
|
|
ENDDO
|
|
R("C10", LTrim(Str(nCount)))
|
|
R("C11", LTrim(Str(nSum)))
|
|
|
|
// Reverse traversal
|
|
GO BOTTOM
|
|
nCount := 0
|
|
DO WHILE !BOF()
|
|
nCount++
|
|
SKIP -1
|
|
ENDDO
|
|
R("C12", LTrim(Str(nCount)))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART D: City index — duplicate keys
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_city
|
|
|
|
GO TOP
|
|
R("D01", RTrim(FieldGet(3)) + " " + LTrim(Str(RecNo())))
|
|
|
|
// Count per city
|
|
FOR i := 1 TO 10
|
|
SEEK PadR(aCities[i], 15)
|
|
nCount := 0
|
|
DO WHILE !EOF() .AND. RTrim(FieldGet(3)) == aCities[i]
|
|
nCount++
|
|
SKIP
|
|
ENDDO
|
|
R("D_" + Left(aCities[i], 3), LTrim(Str(nCount)))
|
|
NEXT
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART E: SOFTSEEK comprehensive
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_name
|
|
SET SOFTSEEK ON
|
|
|
|
SEEK PadR("Name_050", 20)
|
|
R("E01", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK PadR("Name_050X", 20)
|
|
R("E02", B(Found()) + " " + LTrim(Str(RecNo())) + " " + RTrim(FieldGet(2)))
|
|
SEEK PadR("Name_100X", 20)
|
|
R("E03", B(Found()) + " " + B(EOF()))
|
|
SEEK PadR("Aaa", 20)
|
|
R("E04", B(Found()) + " " + LTrim(Str(RecNo())) + " " + RTrim(FieldGet(2)))
|
|
SEEK "Name_099"
|
|
R("E05", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
|
|
SET SOFTSEEK OFF
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART F: Compound key (CITY+NAME)
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_compound
|
|
|
|
GO TOP
|
|
R("F01", RTrim(FieldGet(3)) + "|" + RTrim(FieldGet(2)) + " " + LTrim(Str(RecNo())))
|
|
GO BOTTOM
|
|
R("F02", RTrim(FieldGet(3)) + "|" + RTrim(FieldGet(2)) + " " + LTrim(Str(RecNo())))
|
|
|
|
// Seek with full compound key
|
|
SEEK PadR("Seoul", 15) + PadR("Name_001", 20)
|
|
R("F03", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK PadR("Tokyo", 15) + PadR("Name_002", 20)
|
|
R("F04", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
|
|
// Partial: just city
|
|
SEEK PadR("Berlin", 15)
|
|
R("F05", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK PadR("Oslo", 15)
|
|
R("F06", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART G: UPPER index
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_upper
|
|
|
|
GO TOP
|
|
R("G01", RTrim(FieldGet(2)) + " " + LTrim(Str(RecNo())))
|
|
SEEK PadR("NAME_050", 20)
|
|
R("G02", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK PadR("name_050", 20)
|
|
R("G03", B(Found()))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART H: DELETE + SEEK + SET DELETED
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_name
|
|
|
|
// Delete every 5th
|
|
SET ORDER TO 0
|
|
FOR i := 1 TO 100
|
|
GO i
|
|
IF i % 5 == 0
|
|
DELETE
|
|
ENDIF
|
|
NEXT
|
|
|
|
SET ORDER TO 1
|
|
SET DELETED OFF
|
|
SEEK PadR("Name_010", 20)
|
|
R("H01", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK PadR("Name_050", 20)
|
|
R("H02", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
|
|
SET DELETED ON
|
|
GO TOP
|
|
nCount := 0
|
|
DO WHILE !EOF()
|
|
nCount++
|
|
SKIP
|
|
ENDDO
|
|
R("H03", LTrim(Str(nCount)))
|
|
|
|
// Seek deleted record with SET DELETED ON
|
|
SEEK PadR("Name_010", 20)
|
|
R("H04", B(Found()) + " " + B(EOF()))
|
|
|
|
// Seek non-deleted neighbor
|
|
SEEK PadR("Name_011", 20)
|
|
R("H05", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
|
|
SET DELETED OFF
|
|
|
|
// Recall all
|
|
SET ORDER TO 0
|
|
FOR i := 1 TO 100
|
|
GO i
|
|
IF Deleted()
|
|
RECALL
|
|
ENDIF
|
|
NEXT
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART I: Numeric key seek
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_id
|
|
|
|
SEEK Str(1, 6)
|
|
R("I01", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK Str(50, 6)
|
|
R("I02", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK Str(100, 6)
|
|
R("I03", B(Found()) + " " + LTrim(Str(RecNo())))
|
|
SEEK Str(0, 6)
|
|
R("I04", B(Found()) + " " + B(EOF()))
|
|
SEEK Str(101, 6)
|
|
R("I05", B(Found()) + " " + B(EOF()))
|
|
|
|
GO TOP
|
|
R("I06", LTrim(Str(FieldGet(1))))
|
|
GO BOTTOM
|
|
R("I07", LTrim(Str(FieldGet(1))))
|
|
|
|
// Skip 10 from top, check ID
|
|
GO TOP
|
|
SKIP 9
|
|
R("I08", LTrim(Str(FieldGet(1))) + " " + LTrim(Str(RecNo())))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART J: Seek + field value verification
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
SET INDEX TO stress_name
|
|
|
|
SEEK PadR("Name_042", 20)
|
|
R("J01", LTrim(Str(FieldGet(1))) + " " + RTrim(FieldGet(2)) + " " + RTrim(FieldGet(3)))
|
|
R("J02", LTrim(Str(FieldGet(4))) + " " + LTrim(Str(FieldGet(5))))
|
|
R("J03", B(FieldGet(6)))
|
|
|
|
SEEK PadR("Name_099", 20)
|
|
R("J04", LTrim(Str(FieldGet(1))) + " " + RTrim(FieldGet(3)))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART K: DBEVAL equivalent — sum with condition
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
GO TOP
|
|
nSum := 0
|
|
nCount := 0
|
|
DO WHILE !EOF()
|
|
IF FieldGet(6) // ACTIVE = .T.
|
|
nSum += FieldGet(5) // SALARY
|
|
nCount++
|
|
ENDIF
|
|
SKIP
|
|
ENDDO
|
|
R("K01", LTrim(Str(nCount)))
|
|
R("K02", LTrim(Str(Int(nSum))))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART L: Multi-workarea
|
|
// ============================
|
|
dbCreate("stress_wa2", {{"REF_ID","N",6,0},{"NOTE","C",30,0}})
|
|
USE "stress_wa2" NEW
|
|
FOR i := 1 TO 10
|
|
APPEND BLANK
|
|
REPLACE REF_ID WITH i * 10
|
|
REPLACE NOTE WITH "Note for ID " + LTrim(Str(i * 10))
|
|
NEXT
|
|
R("L01", LTrim(Str(RecCount())))
|
|
GO 5
|
|
R("L02", LTrim(Str(FieldGet(1))) + " " + RTrim(FieldGet(2)))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART M: PACK + verify
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
|
|
// Delete records 91-100
|
|
FOR i := 91 TO 100
|
|
GO i
|
|
DELETE
|
|
NEXT
|
|
|
|
PACK
|
|
R("M01", LTrim(Str(RecCount())))
|
|
|
|
GO 1
|
|
R("M02", LTrim(Str(FieldGet(1))))
|
|
GO TOP
|
|
R("M03", LTrim(Str(RecNo())))
|
|
|
|
// Verify last record
|
|
GO BOTTOM
|
|
R("M04", LTrim(Str(FieldGet(1))) + " " + LTrim(Str(RecNo())))
|
|
|
|
CLOSE ALL
|
|
|
|
// ============================
|
|
// PART N: ZAP + rebuild
|
|
// ============================
|
|
USE "stress_test" NEW
|
|
ZAP
|
|
R("N01", LTrim(Str(RecCount())))
|
|
R("N02", B(EOF()))
|
|
|
|
// Re-populate 5 records
|
|
FOR i := 1 TO 5
|
|
APPEND BLANK
|
|
REPLACE ID WITH i * 100
|
|
REPLACE NAME WITH PadR("New_" + LTrim(Str(i)), 20)
|
|
NEXT
|
|
R("N03", LTrim(Str(RecCount())))
|
|
|
|
GO 3
|
|
R("N04", LTrim(Str(FieldGet(1))) + " " + RTrim(FieldGet(2)))
|
|
|
|
CLOSE ALL
|
|
|
|
RECOVER
|
|
? "ERROR"
|
|
END SEQUENCE
|
|
|
|
|
|
RETURN
|
|
|
|
FUNCTION B(lVal)
|
|
IF lVal
|
|
RETURN ".T."
|
|
ENDIF
|
|
RETURN ".F."
|
|
|
|
PROCEDURE R(cKey, cVal)
|
|
? cKey + "=" + cVal
|
|
RETURN
|