16 Commits

Author SHA1 Message Date
0e80b93d0a docs(pgserver): Phase 7 — bootstrap example + CI gate documentation
Wraps the v1.0 PG-wire deliverable with the two pieces operators
actually look for: a runnable example PRG and an updated CI gate
list in CLAUDE.md.

* examples/pgserver_demo.prg — full bootstrap PRG demonstrating
  every HB_FUNC composed in the order a production deployment
  needs:
    PG_TLS_SELF_SIGNED → PG_ADD_ROLE × N → PG_ALLOW_IP × N →
    PG_SERVER_START( ":5432", "md5" )
  Comments cover the SHARED-DBF integration point and the SPAWN
  idiom for non-blocking server startup. Builds cleanly under
  the examples_build sweep (now 66/72; was 65/71).

* CLAUDE.md — the "어떤 파일이든 수정한 후" mandatory test list
  goes from 3 gates → 6:
    1. go test ./...
    2. FiveSql2 SQL:1999 43/43
    3. Harbour compat 56/56
    4. std.ch 17/17 (added)
    5. FRB 7/7 (added)
    6. pgserver integration 6/6 (added — psql required)
  Aligns the rule-of-thumb with reality. The five suites already
  ran on every audit-era commit; pgserver/run.sh is new in
  Phases 3-6 and now joins them.

This completes the v1.0 PostgreSQL-wire frontend. End-to-end
checklist:

  Phase 1: per-session state isolation         [93cf5c8]
  Phase 2: SimpleQuery wire MVP                [d98f5e1 7083297]
  Phase 3: DML + transactions                  [a556764]
  Phase 4: Extended Protocol (Parse/Bind/Exec) [8472928]
  Phase 5: password + MD5 auth                 [90eafcf]
  Phase 6: TLS + IP allowlist                  [3b2dd36]
  Phase 7: example + docs                      [this commit]

Open follow-ups (Phase 7.x):
  - hbrdd workarea per-thread isolation (audit Top-Risk #2):
    ≥3 concurrent connections doing in-flight INSERT/SELECT in
    their own transactions can race at the workarea layer. Fix
    is a separate workstream against hbrtl/database.go +
    hbrdd/dbf/. Documented limitation in tests/pgserver/run.sh.
  - SCRAM-SHA-256 auth (Phase 5.1).
  - pg_catalog shim for BI-tool introspection (Phase 1.1+ of the
    original audit plan).
  - Binary parameter format for NUMERIC/TIMESTAMP (Phase 4.1).

All gates green:
  go test ./...               ✓
  FiveSql2 SQL:1999 43/43     ✓
  Harbour compat 56/56        ✓
  std.ch 17/17                ✓
  FRB 7/7                     ✓
  examples 66/72              ✓ (+1 from new pgserver_demo)
  pgserver integration 6/6    ✓

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 15:20:44 +09:00
486e466592 feat: FiveSql2 43/43, @byref, mutable closure, RTL 479, DateTime fix
Major changes since last commit:
- FiveSql2 SQL:1999 engine (10,458 LOC) — 43/43 ALL PASS
- 21 compiler/runtime bugs fixed (short-circuit AND/OR, FOR LOOP, etc.)
- @byref pass-by-reference via RefCell pattern
- Mutable closure capture (EnsureLocalRef + RefCell sharing)
- RTL: 400 → 479 functions (+79: file, string, datetime, hash, UTF-8)
- DateTime/Timestamp fully working (hb_DateTime, hb_Hour/Min/Sec, display)
- Reserved word guard (39 keywords blocked from function calls)
- AEval arg order fix (element before index)
- Closure capture redecl fix (unique _cap_ names per block)
- Hash/string indexing in ArrayPush/ArrayPop
- Harbour compat test suite: 51/51
- 4 docs: Porting Report, Implementation Plan, Optimization Plan, Commercialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:35:37 +09:00
1b41384675 fix: CDX mmap + internal node format (BE key-first) — 50K works
CDX internal node format fix:
- Was: [child LE][recNo LE][key] (NTX-style)
- Now: [key][recNo BE][child BE] (correct CDX format)
- Fixes GoTop/Seek/Scan for large CDX files (50K+ records)

CDX mmap:
- syscall.Mmap on OpenIndex for zero-copy reads
- idx.readAt() helper: mmap slice or file fallback
- All ReadAt calls in Tag navigation replaced
- Close: munmap

CDX 50K benchmark (all counts correct):
  SEEK NAME 50K: 362ms (f=50000)
  SCAN 50K: 276ms (c=50000)
  SCOPE 35K: 238ms (c=35000)
  SEEK ID 50K: 320ms (f=50000)

CDX is slower than NTX due to bit-packed leaf decompression per page.
Cross-read test: 18/18 still PASS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:32:06 +09:00
7fec4ce150 perf: 50K benchmark — Harbour vs Five on ext4
50K records benchmark on native ext4 (home directory):
- APPEND 50K: Five 140ms / Harbour 61ms (2.3x)
- INDEX 50K:  Five 31ms / Harbour 6ms (5.2x)
- SEEK 50K:   Five 142ms / Harbour 23ms (6.2x)
- SCAN 50K:   Five 35ms / Harbour 5ms (7x)
- PACK 50K:   Five 19ms / Harbour 16ms (1.2x)

All within acceptable Go vs C overhead (2-7x).
PACK nearly identical. APPEND close (2.3x).

Known issue: 3-level NTX bulk build has separator duplication
at interior→root level (count=50083 vs 50000).
Does not affect correctness for <= 2-level trees (100 records OK).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:36:12 +09:00
1d3f897daf bench: RDD performance benchmark — Harbour vs Five comparison
10,000 records, 3 indexes, 12 benchmarks:
- APPEND: Five 72s vs Harbour 16ms (flush-per-record — optimization needed)
- INDEX: Five 30-36ms vs Harbour 1-2ms (per-key insert vs bulk)
- SEEK: Five 35ms vs Harbour 5ms (7x — acceptable)
- SCAN: Five 8-11ms vs Harbour 1-4ms (3-9x — acceptable)
- PACK: Five 4ms = Harbour 4ms (identical!)

B6 correctness: Five found=10000 (all), Harbour found=1 (hash collision)
All counts match: 10000 records, 8000 after SET DELETED, 8000 after PACK

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 08:38:19 +09:00
cc46ad2832 fix: SOFTSEEK, SET DELETED+INDEX, compound key, SET INDEX TO + stress test
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>
2026-04-06 15:11:17 +09:00
b7028791d6 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>
2026-04-06 14:08:51 +09:00
c04c9aeaa8 feat: INDEX ON with UDF support — user functions in key expressions
Core change:
- dbf.KeyEvalFunc: global callback set by gengo before OrderCreate
- evalKeyExprInner default case: calls KeyEvalFunc for unknown functions
- Final fallback: any unresolvable expression → KeyEvalFunc → MacroEval
- valueToKeyBytes: converts MacroEval result to index key bytes
- gengo: sets dbf.KeyEvalFunc = t.MacroEval before OrderCreate, clears after

Examples that now work:
  INDEX ON MyFunc(FIELD->NAME) TO idx    // UDF in key expression
  INDEX ON CityKey(FIELD->CITY, NAME) TO idx  // multi-param UDF
  INDEX ON Left(MyFunc(NAME), 15) TO idx // nested built-in + UDF

Also fixed:
- SET ORDER TO n: int→string via hbrt.NtoS (was empty string)
- CDX compound leaf decoder: proper bit-packed tag name extraction
- CDX compound recNo = direct byte offset (not page number)

All existing tests pass, NTX 47/47 + CDX 20/20 Harbour compat maintained.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 13:36:21 +09:00
7e2a159b88 feat: CDX support + ORDSCOPE + cross-read Harbour compatibility
CDX Integration:
- IndexEngine interface: common for NTX Index and CDX Tag
- OrderListAdd: auto-detects .cdx/.ntx extension, opens CDX tags
- decodeCompoundLeaf: proper bit-packed tag directory decoding
  (was stub falling through to scanCompoundLeaves with wrong names)
- CDX Tag: added KeyLen(), KeyExpr(), ForExpr(), IsDescending(), Close()
- CDX compound recNo = direct byte offset (not page number)

ORDSCOPE:
- SetScope/ClearScope/SetScopeTop/SetScopeBottom on DBFArea
- GoTopIndexed: seeks to scopeTop, validates within scopeBottom
- GoBottomIndexed: seeks to scopeBottom boundary
- SkipIndexed: stops at scope boundaries (top and bottom)
- OrdScope RTL function registered (nScope: 0=TOP, 1=BOTTOM)
- scopeKeyFromValue: converts Value to padded key bytes

Index Order Management:
- OrderListFocus: handles numeric order ("2" → order 2)
- SET ORDER TO n: gengo emits hbrt.NtoS for int-to-string conversion
- IndexOrd/OrdCount/OrdName/OrdKey: real implementations (were stubs)
- OrderCount/CurrentOrder/OrderName/OrderKeyExpr accessors on DBFArea
- ClearScope on order switch (prevents stale scope)

Cross-read test: Harbour-created CDX → Five reads, 20/20 items match:
  NAME/CITY/ID seek, ORDSCOPE count, GoTop/GoBottom all identical

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 12:21:26 +09:00
441d6c184f test: cross-read Harbour NTX from Five — 100% binary compatible
Five reads DBF + NTX files created by Harbour:
- NAME index: exact/partial seek, GoTop/Bottom, Skip, SoftSeek
- CITY index: duplicate key seek with correct RecNo order
- ID index: numeric key (Str(ID,6)) seek

17/17 items match Harbour output exactly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:55:55 +09:00
6e78d12cc2 fix: 3 RDD compat bugs — FIELD->, AsNumInt Double, PACK/ZAP with index
Bug 1: FIELD->NAME in INDEX ON expression
- evalKeyExprInner: strip FIELD->/alias-> prefix before field lookup
- exprToString: handle AliasExpr (FIELD->NAME → "FIELD->NAME")

Bug 2: AsNumInt() on Double returned IEEE 754 raw bits
- Value.AsNumInt(): check tDouble and convert via Float64frombits
- Fixed array index crash when index is result of % modulo

Bug 3: PACK/ZAP crash with open indexes
- OrderListRebuild: fully implemented (was TODO stub)
  Saves index info, closes all, sets idxState=nil, recreates
- OrderCreate: set current=-1 during key evaluation (natural GoTo)
- PACK/ZAP: save/restore idxState, rebuild after operation
- Register __DBPACK, __DBZAP, DBRECALL symbol aliases

Harbour vs Five: 45/47 match (96%), 2 diffs are duplicate-key sort order

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 04:41:19 +09:00
53370e7cbc test: Harbour vs Five RDD compatibility test (91% match)
47 test items comparing Harbour and Five output:
- T01-T28: 100% match (CRUD, navigation, SET DELETED)
- T29-T39: 100% match (SEEK exact/partial/softseek)
- T40-T41: Found matches, RecNo differs (duplicate key sort stability)
- T42-T43: 100% match
- T44-T47: Five crashes (PACK with open index)

Known issues found:
- FIELD->NAME syntax not supported in INDEX ON expression
- Modulo % returns Double causing array index hang (Int() workaround)
- PACK crashes when NTX index is open

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 19:42:50 +09:00
21fd9dc65c feat: SET DELETED filtering, SEEK/LOCATE/CONTINUE, SET command codegen
- skipFilter: skip deleted records in GoTop/GoBottom/Skip when SET DELETED ON
- hbrdd.IsSetDeleted callback: avoids circular import hbrdd→hbrtl
- Parser: capture ON/OFF for boolean SET commands (DELETED, EXACT, SOFTSEEK, etc.)
- Parser: capture TO expr for SET DATE/DECIMALS/EPOCH
- Gengo: emit proper t.Do() calls for 11 SET toggles + 3 value SETs
- stmtSet: was stub (skipToEOL), now calls parseSet()
- RTL: register 11 SET toggle functions (SETDELETED, SETEXACT, etc.)
- RTL: DBLOCATE/DBCONTINUE for sequential search
- RTL: DBSETFILTER/DBCLEARFILTER/DBFILTER
- PadL/PadR: support 3rd param fill character
- Area interface: added SetFound, SetLocate, LocateBlock, filter methods
- MemRDD: implements new Area interface methods
- Comprehensive PRG test: test_search.prg (7 test suites all pass)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:33:59 +09:00
c0f175883c docs: Add math section to syntax reference + improve example comments
- five-syntax-en/ko: Add Math comparison table (Harbour RTL vs Go math)
- go_math_compare.prg: Detailed English comments explaining each section
- Example lists updated with go_math_compare.prg

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:31:44 +09:00
0828d17159 feat: Harbour RTL vs Go math comparison example + analyzer IMPORT fix
- examples/go_math_compare.prg: Side-by-side comparison of
  Harbour RTL (Abs, Sqrt, Round, Int, Max, Min, Log, Exp, Mod)
  vs Go math package (Sin, Cos, Pow, Pi, Floor, Ceil, Hypot, ...)
- Combined usage: normal distribution, compound interest, distance
- Analyzer: recognize IMPORT package names as valid identifiers
- Analyzer: add math RTL functions (ABS, SQRT, etc.) to known list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 10:35:40 +09:00
59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00