OpenADS Release Notes
Complete history of releases with categorized improvements.
Unreleased (main, 2026-09-29)
Bug Fixes
-
xBase writes to MariaDB/MySQL: numeric and logical setters now reach the staging buffer -
AdsSetDouble,AdsSetLong,AdsSetLongLongandAdsSetLogicalhad no MariaDB branch and fell through to the native-DBF table lookup, failing with5000 unknown tableonmariadb://tables. They now stage throughMariaConnection::set_field, likeAdsSetStringalready did: doubles are formatted with"%.17g"and logicals as"1"/"0", which MariaDB coerces into both numeric andCHAR(1)columns. Append and REPLACE of character/date fields already worked; this completes the xBase write path. Covered by a new live test (numeric/logical INSERT and UPDATE round-trip). -
Record locks are idempotent per handle, and lock introspection reports the caller’s own state (Pritpal Bedi) - locking the same record twice on one handle used to stack: a repeated
AdsLockRecordbumped an internal count and the record stayed locked until every lock was undone. A repeated lock is now a no-op and a singleAdsUnlockRecordreleases it, matching ADS.AdsIsRecordLockedandDBRI_LOCKEDnow answer whether the calling handle holds the lock instead of any connection’s, and remote clients get real cross-connection introspection: the server answers theIsRecordLockedwire query against the engine table lock and the session’s record locks. The lock suite was reworked (116 tests), including a new test that observes a lock through a real second connection.
Unreleased (main, 2026-09-25)
New Features
- Inter-process
.ntxindex lock, Harbour DBFNTX-compatible — the NTX driver now locks the.ntxfile itself at byte 1,000,000,000, the same scheme Harbour’s DBFNTX uses, so OpenADS, Harbour and xHarbour/Clipper applications can share NTX indexes across processes safely: reads take a shared lock, writes an exclusive one held untilflush(), and a version counter lets other processes notice the change and reload the index. Before this, only DBF record locks were aligned across processes and concurrent writers could corrupt an.ntx. Covered by new inter-process unit tests, including a two-process concurrent writer test.
v1.8.98 — 2026-08-21
Bug Fixes
openads_serverdignoresremote_only_accessfrom its own ini (Pritpal Bedi) — the client guard fired inside the daemon too: the session ABI twin’s legitimate local opens were logged as LOCALACCESS noise, and deny mode would have broken them. The daemon now force-disables the guard unless the env var is set explicitly.
v1.8.97 — 2026-08-21
Bug Fixes
openads.iniclient keys: dash style + exe-dir lookup (Pritpal Bedi) — keys in the serverd dash style (remote-only-access, likehttp-port/legacy-paths) were not recognized, and anopenads.ininext to the application .exe was not found. Keys are now normalized (-=_, case-insensitive) and the search order is$OPENADS_INI→ DLL dir → app exe dir → cwd.
v1.8.96 — 2026-08-21
New Features
remote_only_access = logaudit mode (Pritpal Bedi) — deny mode (1) raises the RTE wherever the first local open happens, and an app whose error handler itself opens tables via ADSCDX dies from Harbour error-handler recursion (“recursive call” error). The newlog(or2) mode writes aLOCALACCESS="OPEN|CREATE" ASKED="..." VIA=LOCALline to the audit console /log_fileand lets the access proceed, so the full inventory of legacy local paths is collected in one run before switching to deny mode.
v1.8.95 — 2026-08-20
New Features
- Client settings in
openads.ini(Pritpal Bedi) — everyOPENADS_*client setting now also reads fromopenads.ini(env var wins):remote_only_access,resolve_verbose,log,log_file,trace,wire_trace,arc_trace,tls_insecure,adi_v2,adt_cdx_index. The client DLL looks for the file next to itself, then in the app working directory;OPENADS_INIpoints at an explicit path. The file is re-read when it changes. Seeopenads.ini.sample.
v1.8.94 — 2026-08-20
New Features
OPENADS_REMOTE_ONLY_ACCESS=1client guard (Pritpal Bedi) — remote-only deployments can now forbid legacy local-path access through ACE. With the env var set on the client process, a localAdsOpenTable/AdsCreateTablefails withAE_ACCESS_DENIED(rddads raises a Harbour runtime error) instead of silently reading/writing a.dbfnext to the app. Remote and SQL-backend connections are unaffected, as is local I/O through another RDD. See Migrating from ADS.
v1.8.93 — 2026-08-19
New Features
OAds_Mutex*Harbour wrappers — the server-side distributed mutex service (v1.8.92, remote connections only) is now callable from Harbour PRG code without RDDADS viacontrib/oads_hb/oads_hb.c:OAds_MutexCreate( [hConn], cName ),OAds_MutexLock( [hConn], cName, nTimeoutMs ),OAds_MutexTryLock( [hConn], cName ),OAds_MutexUnlock( [hConn], cName ),OAds_MutexDestroy( [hConn], cName ). OmittinghConnuses the default connection set withOAds_SetConnection()(Pritpal Bedi).
Documentation
- API reference — new section 26 “Distributed Mutex (server-side,
remote only)” with the Harbour signatures;
last_updatedtimestamp added to the front matter.
v1.8.89 — 2026-08-17
New Features
- Process-wide audit sequence — each
RESOLVEDline is nowCONN ENTRY SEQ TIMESTAMP ….ENTRYstill restarts per connection;SEQis a single incrementing number for the process so two connections no longer look like a repeated counter (Pritpal Bedi).
v1.8.88 — 2026-08-17
Bug Fixes
oads_hb.cincludes"ace.h"— Harbour drop-in glue now uses the same header ascontrib/rddads, so it compiles in a consumer project without editing the file each time (Pritpal Bedi).
Packaging
- Windows ZIP names — only
openads-<ver>-windows-x64.zip/windows-x86.zip. The parallel*-win-*.zipslim kit is no longer published (it was a differentace64.dlland confused downloads).
v1.8.87 — 2026-08-17
New Features
- Resolve audit trail — every table-path resolve is a fixed-width
line (
CONN6 ENTRY8 TIMESTAMP RESOLVED=... asked=... via=local|remote). Console default is onlyRESOLVED. SetOPENADS_RESOLVE_VERBOSE=1for detail lines;OPENADS_LOG_FILEstores onlyRESOLVED(Pritpal Bedi).
Bug Fixes
- Remote is safe storage — a remote-server connection no longer
opens a leftover host-absolute path.
--legacy-pathsremounts under--data; otherwise the open fails with the normal RDD error (Pritpal Bedi).
v1.8.79 — 2026-08-15
New Features
-
Connection switching + optional hConn for OAds_F* —
OAds_SetConnection( hConn )sets the thread-local default connection;OAds_GetConnection()retrieves it. AllOAds_F*Harbour functions (OAds_FOpen,OAds_FCreate,OAds_CheckExistence,OAds_DeleteFile,OAds_RenameFile,OAds_GetFileSize,OAds_GetFileDate,OAds_GetFileTime,OAds_DirMake,OAds_DirRemove,OAds_DirExist,OAds_Directory,OAds_FExist) now accept hConn as optional. When omitted, the thread-local default is used. Backward compatible — existing code passing hConn continues to work.Use case: single-connection apps set the default once; multi-connection apps switch via
OAds_SetConnection(hConn)before each call — handy for transparent backup across two endpoints.
Bug Fixes
- macOS build —
arc2_stamp()now useslocaltime_ron POSIX (was Windows-onlylocaltime_s); trace log uses/tmp/ace_calls.logon POSIX.AE_NO_MATCHING_FILE(5059) added to the error enum.
v1.8.78 — 2026-08-15
New Features
- Multi-port server — A single
openads_serverdinstance can now listen on multiple TCP ports, each with its own data directory. Configure additional ports with[port:NNNN]sections inopenads.ini, each specifying adatapath. Matches LetoDB’sPort=/DataPath=capability: one process, one config file, multiple logical servers.
Bug Fixes
- CDX index corruption on record update (macOS) —
sync_all_indexes_()silently discarded the B-tree erase result when updating a record, so the old index entry stayed in the tree and the new entry was inserted on top — creating duplicate/stale keys that corrupted B-tree separators. The erase error is now propagated so the caller can abort before inserting. For fresh appends, the blank-key snapshot (fields not yet set) is tolerated because those keys were never inserted. (Commitdf9c2cc.)
Tests
abi_alternating_append_test: 4 cases — alternating local/remote appends maintain all CDX tag keys.abi_adt_scope_validation_test: M5 stress append + index order + memo round-trip.- Full unit suite: 524/524 on Windows, same on macOS.
v1.8.77 — 2026-08-14
Bug Fixes
- Remote
ordListClear()+ordListAdd()left the workarea without an order — The client-side remoteAdsCloseAllIndexesclosed the indexes on the server but never invalidated the cached tag/handle map in the ACE client DLL. The nextAdsOpenIndex/SET ORDER TOreused dead server wire-ids (SetOrder5000 on run 2) or found no order at all (ADSCDX/301 “Workarea not indexed” ondbSeekon run 1). The client cache is now dropped on close-all. (Reported by Pritpal Bedi — Harbour 32-bitTestIndexes().) OrdCount()stale afterOrdCreate()without reopen — The remote create path never registered the new tag in the client’s index handle list, soAdsGetNumIndexes/AdsGetIndexHandlelagged until close+reopen. After a successfulcreate_indexthe client now refreshes the whole bag from the server (ADS semantics: creating a tag opens every tag in the bag), in bag order. (Reported by Pritpal Bedi.)- x86
openads_serverdcrashed at startup —dll_probe_acecalledAdsGetVersionthrough a mismatched calling convention whenever anace32.dll/openace32.dllsat next to the exe. The probe now identifies OpenADS builds via the OpenADS-onlyoads_*exports before calling anything, and calls__cdecl. (Reported by Pritpal Bedi: “Server does not launch”.) - x86 undecorated exports restored to the
__cdeclimplementations (v1.8.74 behavior) — The stdcall rework had aliased the plainAdsXxxexport names to the__stdcallwrappers, so__cdeclcallers (FWH apps such asB_BIG.exe,GetProcAddressprobes, Xbase++) crashed withACCESS_VIOLATIONon the first ACE call (ADS_GETFUNCTABLE). The plain names now target the__cdeclimplementations again;_AdsXxx@Nremains on the__stdcallwrappers. (Reported by Pritpal Bedi.) - Release CI unblocked — C4100 in
AdsFindNextTable/AdsFindClose(MSVC/WX), UUID buffer worst-case%llxsizing (clang-Wformat-truncation), and sign-conversion casts insession.cpptransaction dispatch (clang-Wsign-conversion).
Tests
abi_remote_index_reopen_test: 2 cases — remoteordListClear+ordListAddleaves a usable order (created bag and auto-opened bag variants).- Fixed iterator-of-two-temporaries UB in
abi_server_fs_test/abi_remote_index_reopen_test(flakyvector too long). - Import libraries under
dist/import-libsregenerated from the current DLLs.
v1.8.75 — 2026-08-13
New Features
- ADS-compatible replication (Phase 1) — One-way async replication between OpenADS servers via publications, articles, and subscriptions. The DataDict now supports
Publication,Article, andSubscriptionobject types with full CRUD and round-trip persistence. A durable CRC-32C queue (ReplQueue) captures INSERT/UPDATE/DELETE mutations through best-effort capture hooks, andrepl_apply_once()drains the queue to apply changes to a local target table. 35 unit tests (464 assertions). - M12.33 remote FindTables —
AdsOpenTableand the serverOpenTabledispatcher now striptcp://host:port/URI prefixes that legacy Delphi TAdsTable components embed in table names.
Tests
repl_queue_test: 10 cases — append, read_from, CRC corruption, empty filerepl_catalog_test: 8 cases — DD round-trip, table_is_published, cascade, rejectsabi_repl_capture_test: 1 case — capture hooks fire on INSERT/UPDATE/DELETErepl_apply_test: 23 cases — subscription resolution, INSERT/UPDATE/DELETE apply, mixed batches, idempotency, last_lsn persistence, error paths
v1.8.74 — 2026-08-12
Bug Fixes
- INDEX ON bag remounted through table’s connection —
AdsCreateIndex61/AdsCreateIndex/AdsOpenIndexnow remount the index bag through the table’s connection the same way as the.dbf. FixesINDEX ONwriting.z01next to the app while the.dbfremounted under--legacy-paths. - Explicit local Connection handle no longer hijacked — An explicit local
Connectionhandle is no longer hijacked by “any liveRemoteConnection” (in-process server ABI twin + mixed local/remote apps).
Tests
AdsCreateIndex61 remounts client-absolute .z01 under legacy_pathsremote INDEX ON remounts client-absolute .z01 under legacy-paths jail
v1.8.73 — 2026-08-12
Bug Fixes
--legacy-pathsnow remounts every client-absolute path under--data— Previously, host files that already existed outside--datacould still be opened. Every client-absolute open/create now remounts under--datafirst; the host-absolute OPEN/CREATE exceptions apply only in strict mode.
Documentation
- Documented the
--data/ URI /--legacy-pathscontract (forward slashes recommended) incookbook/docs/local-and-remote.mdandconnection-strings.md.
Tests
session_connection_test: host-absolute file outside the jail must not win whenlegacy_pathsis on.abi_mt_create_vs_dbfcdx_test: Harbour helpers are Windows-only so clang-Werror(Linux/macOS) does not fail on unused stubs.
v1.8.72 — 2026-08-11
Performance
- ADSCDX multi-thread create ~30x faster than Harbour DBFCDX — Measured on 40 tables / 4 threads, 10 rows + 3-tag CDX each:
- Harbour DBFCDX: ~4 s (baseline)
- OpenADS ADSCDX: ~0.13 s (~30x faster)
- Harbour ADSCDX (rddads): ~0.15 s (~27x faster)
- No per-op FlushFileBuffers — Default is page-write only; set
OPENADS_FSYNC=1to restore the old power-fail-safe path. - AdsCreateIndex61 no longer holds state().mu across bulk build — Only index_bindings_mu around map mutations, so multi-thread INDEX ON scales.
- CDX write-lock wait uses a condition variable — Not 100 us poll; always releases the batch join on flush error paths.
Tests
abi_mt_create_vs_dbfcdx_test.cpp— every ADSCDX speed run paired with a Harbour DBFCDX baseline.- Build harness:
tests/unit/build_mt_create_bench.bat.
v1.8.68 — 2026-08-09
Bug Fixes
- clang
-Werrorbuild breaks in new test files — Two unused-code warnings (lambda capture, helper functions) failed macOS/Linux CI builds. No product code changes beyond the warning fixes; supersedes v1.8.67 on POSIX.
v1.8.67 — 2026-08-09
Bug Fixes
- CDX B+tree Harbour-exact (key, recno) ordering — Insert descent now compares full (key, recno) pairs. Separators are refreshed on every max-pair change, on insert and on erase.
- Two multithreading defects fixed — CDX write-lock batch now has an owner thread; remote
AdsOpenIndexhandle array overflow fixed. - DBF headers now byte-identical with Harbour DBFCDX — Header length
32 + 32*n + 2with 2-byte terminator. Production-index flag set when CDX bag shares table’s basename.
Tests
cdx_dup_key_split_test: independent raw-page decoder asserting parent-separator == child-max.abi_alternating_append_test: two local connections and a remote server + local client alternating duplicate-key bursts.
v1.8.66 — 2026-08-08
Bug Fixes
- Multi-tag CDX bags: creation and binding — Legacy
AdsCreateIndexno longer truncates the bag when adding a second tag.AdsOpenIndexnow binds all tags regardless of handle array size. - DBF record-count race under concurrent mixed writers —
refresh_record_count_now takes the max of header and size-derived counts.
v1.8.65 — 2026-08-07
Bug Fixes (POSIX)
- SIGPIPE guard —
sock_send()withMSG_NOSIGNALon Linux;SO_NOSIGPIPEon macOS. - ADT byte-lock offset wrap — Offsets ≥ 2^63 folded into positive range.
- CDX write-lock registry per-file mutex — Each
.cdxpath serialises on its own entry mutex.
v1.8.64 — 2026-08-07
Bug Fixes
- Harbour DBFCDX interop: shared-index visibility — Peer CDX updates now detected via file-header version counter.
- Physical write guard (GoHot) — Shared-mode writes require RLock / FLock / exclusive.
- Index corruption under mixed ADS/DBFCDX writers — Lock offsets aligned with Harbour DBFCDX VFP scheme.
v1.8.63 — 2026-08-07
Bug Fixes
- Remote
keynostale after APPEND/WRITE/DELETE/RECALL —keyno_validand prefetch/BOF-EOF flags now cleared.
v1.8.62 — 2026-08-07
Performance
- Server-side
GetKeyNumvia CDX O(1) cache — New wire opcodesGetKeyNum/GetKeyNumAck(0x03/0x04). - Same-record
GotoRecordpreserves keyno —TXBrowse:Refresh()after remote APPEND stays O(1).
v1.8.61 — 2026-08-07
Bug Fixes
- CDX tag-header update counter endianness — Now big-endian to match Harbour DBFCDX.
v1.8.60 — 2026-08-06
Bug Fixes
- CDX page allocator tail reset after recreate — Prevents ~10x sparse-file bloat.
v1.8.59 — 2026-08-05
Performance
- Legacy ADI
CREATE INDEXbottom-up bulk pack — Index ~49% smaller (73,216 → 37,376 bytes for 10,000 keys).
v1.8.58 — 2026-08-05
Documentation
- Error log vs transaction journal paths — Documented
ads_err.dbflocation and relocation options.
v1.8.57 — 2026-08-05
New Features
- ADI v2 tags — Compound/computed/FOR on ADT tables.
AdsGetKeyCountmemoise — Performance improvement.- ADT read-ahead — Prefetch optimization.
- PACK truncate — Efficient table compaction.
v1.8.56 — 2026-08-05
Bug Fixes
- CDX numeric leaves type-dependent trail byte — NUL for FoxNumeric, matching DBFCDX density.
v1.8.55 — 2026-08-04
New Features
- SAP date display format —
AdsGetFieldformatted vsAdsGetStringraw. - Join/union/aggregate temps are ADT — Temporary tables use ADT format.
v1.8.54 — 2026-08-04
Bug Fixes
- Connect no longer fails when data root is not writable — e.g.
--data "C:\".
v1.8.53 — 2026-08-03
Bug Fixes
legacy_pathsremote create/reindex — Fixed un-flagged ABI twin usage.- Drive-letter routing for whole-filesystem servers —
--data "C:\;D:\;E:\".
v1.8.52 — 2026-08-03
New Features
legacy_pathsserver mode — Zero-change ERP ports with absolute path remapping.
v1.8.51 — 2026-08-02
Bug Fixes
- x86
ace32.dllexports cdecl aliases — For MinGW rddads compatibility.
v1.8.50 — 2026-08-01
Bug Fixes
- Empty AOF visible-set returns Limbo —
AdsSeekLastpositions correctly. - AOF index selection — Fixed.
- ADI keycount fix — Fixed.
v1.8.49 — 2026-08-01
Bug Fixes
- Write coalescing broke rollback/CDX/AFTER triggers — Fixed.
- Remote ADT numeric round-trip encoding — Fixed.
v1.8.48 — 2026-08-01
Bug Fixes
- 32-bit toolchain:
ace.h__stdcallon MSVC x86 — All in-tree tools link against exported stdcall names.
v1.8.47 — 2026-08-01
Bug Fixes
- Remote
AtBOF/AtEOFanswered from wrong cursor — Fixed. - Row trailer at BOF fixed phantom duplicate row — Fixed.
v1.8.46 — 2026-08-01
Bug Fixes
DbSetOrder(0)restores natural order — Fixed.- ace32.dll exports stdcall
@Nnames — Fixed. - ADSHANDLE 32-bit — Fixed.
v1.8.45 — 2026-07-31
Bug Fixes
- Remote
KeyNo/RelKeyPosclamps to scope-aware key count — Eliminates phantom rows in xBrowse.
For the full commit-by-commit history see the CHANGELOG.