Files
five/examples/go_dual_db.prg
Charles KWON OhJun 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

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