- 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>
104 lines
3.1 KiB
Plaintext
104 lines
3.1 KiB
Plaintext
// Five Example: Dual SQLite — NO #pragma BEGINDUMP
|
|
//
|
|
// Two databases open simultaneously — transfer data between them.
|
|
// All Go calls via IMPORT — zero boilerplate.
|
|
|
|
IMPORT "database/sql"
|
|
IMPORT _ "modernc.org/sqlite"
|
|
|
|
PROCEDURE Main()
|
|
LOCAL dbSource, dbTarget, aSrc, aTgt
|
|
LOCAL aRows, i, nCount
|
|
|
|
? "=== Dual SQLite Demo ==="
|
|
?
|
|
|
|
dbSource := sql.Open("sqlite", "source.db")
|
|
dbTarget := sql.Open("sqlite", "target.db")
|
|
|
|
// Setup source
|
|
dbSource:Exec("DROP TABLE IF EXISTS products")
|
|
dbSource:Exec("CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price REAL, stock INTEGER)")
|
|
dbSource:Exec("INSERT INTO products VALUES (1, 'Keyboard', 89.99, 150)")
|
|
dbSource:Exec("INSERT INTO products VALUES (2, 'Mouse', 29.99, 300)")
|
|
dbSource:Exec("INSERT INTO products VALUES (3, 'Monitor', 499.99, 45)")
|
|
dbSource:Exec("INSERT INTO products VALUES (4, 'Headset', 79.99, 200)")
|
|
dbSource:Exec("INSERT INTO products VALUES (5, 'Webcam', 59.99, 120)")
|
|
? "Source: 5 products created"
|
|
|
|
// Setup target
|
|
dbTarget:Exec("DROP TABLE IF EXISTS inventory")
|
|
dbTarget:Exec("CREATE TABLE inventory (product_id INTEGER, name TEXT, price REAL, status TEXT)")
|
|
? "Target: inventory table ready"
|
|
?
|
|
|
|
// Source -> Target transfer (stock > 100)
|
|
aRows := SqlScan(dbSource, "SELECT * FROM products WHERE stock > 100")
|
|
? "Transferring", Len(aRows), "products with stock > 100..."
|
|
|
|
nCount := 0
|
|
FOR i := 1 TO Len(aRows)
|
|
dbTarget:Exec("INSERT INTO inventory VALUES (" + ;
|
|
Str(aRows[i]["id"]) + ", " + ;
|
|
"'" + aRows[i]["name"] + "', " + ;
|
|
Str(aRows[i]["price"]) + ", " + ;
|
|
"'" + IIF(aRows[i]["stock"] > 200, "high", "normal") + "')")
|
|
nCount++
|
|
NEXT
|
|
? Str(nCount, 3), "records transferred"
|
|
?
|
|
|
|
// Verify target
|
|
? "=== Target Inventory ==="
|
|
aRows := SqlScan(dbTarget, "SELECT * FROM inventory ORDER BY price DESC")
|
|
? PadR("ID", 4), PadR("Name", 15), PadR("Price", 10), "Status"
|
|
? Replicate("-", 45)
|
|
FOR i := 1 TO Len(aRows)
|
|
? PadR(aRows[i]["product_id"], 4), ;
|
|
PadR(aRows[i]["name"], 15), ;
|
|
PadR(Str(aRows[i]["price"], 8, 2), 10), ;
|
|
aRows[i]["status"]
|
|
NEXT
|
|
?
|
|
|
|
// Cross-database summary
|
|
? "=== Cross-DB Summary ==="
|
|
aSrc := SqlScan(dbSource, "SELECT COUNT(*) as cnt, SUM(price) as total FROM products")
|
|
aTgt := SqlScan(dbTarget, "SELECT COUNT(*) as cnt, SUM(price) as total FROM inventory")
|
|
? "Source:", aSrc[1]["cnt"], "products, total", aSrc[1]["total"]
|
|
? "Target:", aTgt[1]["cnt"], "items, total", aTgt[1]["total"]
|
|
|
|
dbSource:Close()
|
|
dbTarget:Close()
|
|
?
|
|
? "Both databases closed. Done."
|
|
|
|
RETURN
|
|
|
|
// SqlScan — pure PRG function using Go's sql.Rows directly
|
|
// No #pragma BEGINDUMP needed!
|
|
FUNCTION SqlScan(db, cSQL)
|
|
LOCAL rows, cols, aResult, aRow, i, nCols
|
|
|
|
aResult := {}
|
|
rows := db:Query(cSQL)
|
|
|
|
IF rows == NIL
|
|
RETURN aResult
|
|
ENDIF
|
|
|
|
cols := rows:Columns()
|
|
nCols := Len(cols)
|
|
|
|
DO WHILE rows:Next()
|
|
aRow := {=>}
|
|
FOR i := 1 TO nCols
|
|
aRow[cols[i]] := rows:Column(i)
|
|
NEXT
|
|
AAdd(aResult, aRow)
|
|
ENDDO
|
|
|
|
rows:Close()
|
|
|
|
RETURN aResult
|