Summary
The SQL backends (SQLite, PostgreSQL, MariaDB/MySQL, MSSQL, Firebird, ODBC) expose read + navigation + SEEK through the ACE ABI, so a Harbour app using rddads works with the standard xBase navigational commands (dbGoTop/dbSkip/dbSeek, FieldGet) — much like SQLRDD. However, the write surface is not yet wired into the navigational ABI for any SQL backend, and record/file locking (rLock()/fLock()) is not emulated on any SQL backend.
This issue tracks closing that gap so the SQL backends become full read/write through the xBase API (SQLRDD-equivalent).
Current state (verified)
| Capability |
SQLite |
PostgreSQL |
MariaDB |
MSSQL |
Firebird |
ODBC |
| Read + navigation |
✅ |
✅ |
✅ |
✅ |
✅ |
✅ |
dbSeek (by column/index) |
✅ |
✅ |
✅ |
✅ |
✅ |
✅ |
Write (dbAppend/REPLACE/dbDelete) via ABI |
❌ |
❌ |
❌ |
❌ |
❌* |
❌* |
rLock() / fLock() |
❌ |
❌ |
❌ |
❌ |
❌ |
❌ |
Details:
AdsAppendRecord / AdsSetString / AdsDeleteRecord (in src/abi/ace_exports.cpp) only route through the remote/wire connection (tcp://) or the native local DBF table. There is no get_firebird_table / get_odbc_table / get_maria_table / get_postgres_table branch in any write function (read functions do use those getters, 18–20× each).
- (*)
FirebirdConnection::append_blank/set_field/delete_record (staged INSERT/UPDATE/DELETE) and the ODBC connection write methods exist and are unit-tested at the connection layer (tests/unit/firebird_connection_test.cpp), but are only called by those tests — never by the ABI.
- MariaDB / PostgreSQL / MSSQL connections have no write methods (
AdsAppendRecord on MSSQL explicitly returns "write not available in v1"). docs/OPENADS_PLUS.md marks PostgreSQL Write as "Planned".
- No SQL backend defines
lock_record / lock_table.
Proposed plan (cheap → expensive)
- Wire Firebird write into the navigational ABI —
AdsAppendRecord, AdsSetString/SetDouble/SetLong/... (REPLACE), AdsWriteRecord (commit row), AdsDeleteRecord, mirroring how Firebird read is already wired (get_firebird_table). The engine already exists + is unit-tested, so this is the lowest-risk first win. ABI-level test (live-FB gated, skips without OPENADS_TEST_FB_URI).
- Wire ODBC write the same way — strategic, since ODBC is a universal gateway (write to MariaDB/PostgreSQL/etc. via
odbc://DSN even before native write lands).
- Native write for MariaDB / PostgreSQL / MSSQL — implement
append_blank/set_field/delete_record on each connection (staged INSERT/UPDATE/DELETE keyed by PK), following the Firebird pattern, then wire into the ABI.
- Emulate
rLock() / fLock() — map to the SQL engine's locking/transaction semantics (e.g. SELECT ... FOR UPDATE / row versioning), the main remaining SQLRDD-parity gap.
Notes
- Changes to
src/abi/ace_exports.cpp are coordinated upstream (Antonio) — delivered as additive, source-clean PRs from the fork, not merged directly.
- Backend-side write methods (
src/sql_backend/*) are additive and self-contained.
Summary
The SQL backends (SQLite, PostgreSQL, MariaDB/MySQL, MSSQL, Firebird, ODBC) expose read + navigation + SEEK through the ACE ABI, so a Harbour app using
rddadsworks with the standard xBase navigational commands (dbGoTop/dbSkip/dbSeek,FieldGet) — much like SQLRDD. However, the write surface is not yet wired into the navigational ABI for any SQL backend, and record/file locking (rLock()/fLock()) is not emulated on any SQL backend.This issue tracks closing that gap so the SQL backends become full read/write through the xBase API (SQLRDD-equivalent).
Current state (verified)
dbSeek(by column/index)dbAppend/REPLACE/dbDelete) via ABIrLock()/fLock()Details:
AdsAppendRecord/AdsSetString/AdsDeleteRecord(insrc/abi/ace_exports.cpp) only route through the remote/wire connection (tcp://) or the native local DBF table. There is noget_firebird_table/get_odbc_table/get_maria_table/get_postgres_tablebranch in any write function (read functions do use those getters, 18–20× each).FirebirdConnection::append_blank/set_field/delete_record(staged INSERT/UPDATE/DELETE) and the ODBC connection write methods exist and are unit-tested at the connection layer (tests/unit/firebird_connection_test.cpp), but are only called by those tests — never by the ABI.AdsAppendRecordon MSSQL explicitly returns"write not available in v1").docs/OPENADS_PLUS.mdmarks PostgreSQL Write as "Planned".lock_record/lock_table.Proposed plan (cheap → expensive)
AdsAppendRecord,AdsSetString/SetDouble/SetLong/...(REPLACE),AdsWriteRecord(commit row),AdsDeleteRecord, mirroring how Firebird read is already wired (get_firebird_table). The engine already exists + is unit-tested, so this is the lowest-risk first win. ABI-level test (live-FB gated, skips withoutOPENADS_TEST_FB_URI).odbc://DSNeven before native write lands).append_blank/set_field/delete_recordon each connection (staged INSERT/UPDATE/DELETE keyed by PK), following the Firebird pattern, then wire into the ABI.rLock()/fLock()— map to the SQL engine's locking/transaction semantics (e.g.SELECT ... FOR UPDATE/ row versioning), the main remaining SQLRDD-parity gap.Notes
src/abi/ace_exports.cppare coordinated upstream (Antonio) — delivered as additive, source-clean PRs from the fork, not merged directly.src/sql_backend/*) are additive and self-contained.