Skip to content

Releases: FiveTechSoft/OpenADS

v1.5.2

27 Jun 23:30

Choose a tag to compare

v1.5.1

27 Jun 16:21

Choose a tag to compare

Full Changelog: v1.5.0...v1.5.1

v1.5.0

27 Jun 02:35

Choose a tag to compare

v1.5.0 — x86 fix, CDX/AOF correctness, complete API docs

Bug Fixes (credits: Jonsson / RusSoft Ltda.)

  • CDX tag order: list_tags() sorts by creation order, not alphabetical
  • CDX expression-index key size: fixed truncation causing rows out of order on large tables
  • AdsSetAOF: returns AE_INVALID_EXPRESSION for non-optimisable filters (fixes silent SET FILTER disable)
  • x86 calling convention: __stdcall (WINAPI) on Win32 fixes stack corruption
  • Conditional FOR on logical fields: treat as numeric 0/1 (PR #121)
  • INDEX ON corruption: prevent source table index corruption (PR #118)
  • ODBC driver x86: C4100/C2733 fixes

New Features

  • Server-side aggregation (COUNT/SUM/AVG/MIN/MAX)
  • FetchWhere V2 with cached forward scan
  • ODBC driver with scrollable cursors, typed access, app-lock emulation
  • Native write path for PostgreSQL/MariaDB/Firebird
  • SQL push-down for SET FILTER/AOF
  • Complete API docs: all 364 ACE functions in Portuguese

Testing

  • x64: 872/872 passed
  • x86: 874/874 passed
  • New tests: CDX tag order, expression-index scale, multi-tag navigation

Full changelog: v1.4.0...v1.5.0

What's Changed

  • feat(serverd): read settings from an openads.ini via --config by @Admnwk in #88
  • feat(serverd): interactive --setup wizard (writes openads.ini, optional service) by @Admnwk in #89
  • docs: client onboarding kit — Studio launcher, quick start, migration guide by @Admnwk in #90
  • build: install() rules + CPack for reproducible packages by @Admnwk in #91
  • packaging: Windows GUI installer (Inno Setup) by @Admnwk in #94
  • fix(cdx): rewrite stored key expression when re-creating a tag (re-filter on another column) by @Admnwk in #93
  • cookbook(orm): fast-queries DBF example (index-ordered nav + AOF) + vendored ORM refresh by @Admnwk in #95
  • packaging(installer): make openads-setup.iss compile (brace comment + deprecated arch) by @Admnwk in #96
  • fix(abi): give server_type_mask C++ linkage (fixes clang -Werror CI break) by @Admnwk in #99
  • fix(abi): serialize native AdsCreateIndex61 (concurrent-create heap corruption) + daily-ops soak harness by @Admnwk in #97
  • fix(abi): AdsGetRecordCount on a conditional ORDER handle counts FOR matches (#87) by @Admnwk in #100
  • feat: route non-AOF SET FILTER bulk scans through server-side FetchWhere (Tier-2) by @Admnwk in #101
  • feat: FetchWhere V2 — serve forward filter scan from cache (no goto per match) by @Admnwk in #102
  • feat: push Clipper SET FILTER/AOF down to SQL backends (SQLite) by @Admnwk in #107
  • feat(abi,odbc): system.primarykeys catalog + ODBC SQLPrimaryKeys by @Admnwk in #106
  • feat: expand xBase->SQL push-down coverage ($ contains, LEFT) by @Admnwk in #108
  • SQL backends: native write (dbAppend/REPLACE/dbDelete) + rLock()/fLock() for FB/PG/MariaDB/ODBC (#103 slices 1-4, supersedes #104) by @Admnwk in #109
  • abi(firebird): wire backend write (dbAppend/REPLACE/dbDelete) into the navigational ABI (#103 slice 1) by @Admnwk in #104
  • feat: extend SET FILTER/AOF push-down to PostgreSQL by @Admnwk in #110
  • feat(odbc): typed SQLGetData, scrollable cursor, positional parameters by @Admnwk in #105
  • fix(adi): create non-structural .adi bag on the correct ADT table by @Admnwk in #112
  • Tier-3: server-side aggregation push-down (AdsAggregate COUNT/SUM/AVG/MIN/MAX) by @Admnwk in #113
  • fix(adi): reopen a non-structural .adi bag on the correct ADT table by @Admnwk in #114
  • ODBC driver: Driver-Manager / ADO conformance (descriptor handles, SQLBindCol, BIT, ODBC_VER) by @Admnwk in #117
  • fix(index): prevent INDEX ON from corrupting source table indexes by @Admnwk in #118
  • fix(aggregate): validate Tier-3 spec field names (reject unknown/empty, close SQL-injection surface) by @Admnwk in #116
  • ODBC: emulate rLock()/fLock() via SQL Server sp_getapplock (completes #109) by @Admnwk in #111
  • fix(abi): AdsGetField crash on SQL backends when reading by field ordinal (ADSFIELD) by @Admnwk in #115
  • fix: unbreak build (AE_PARSE_ERROR) + ODBC driver x86 (C4100/C2733) by @Admnwk in #119
  • ci: add msvc-x86 (32-bit) build leg by @Admnwk in #120
  • fix(index): conditional FOR ignored a logical-field condition by @Admnwk in #121

Full Changelog: v1.4.0...v1.5.0

v1.4.0 — ADS dialect, CDX engine, wire FetchWhere, enterprise pool, SQL backends

26 Jun 03:17

Choose a tag to compare

1.4.0

ADS Dialect Compatibility (Harbour/FiveWin ERP)

  • N-way comma join (3+ tables) with left-deep hash-join on composite keys + filter pushdown.
  • <alias>.* wildcard projection, UPPER(col) in WHERE (case-insensitive map), FROM t AS a base-table alias, [file.dat] free-table brackets, WHERE 1 = 1 constant folding, ODBC temporal literals ({d ...}/{ts ...}/{t ...}).

CDX Index Engine

  • Bulk-load builder (build_bulk) — bottom-up B+tree, ~10× faster CREATE INDEX.
  • O(1) browse-position cache for AdsGetRelKeyPos/AdsGetKeyNum.
  • Conditional (FOR) index predicates — persist in the sub-tag header + apply at insert; full reopen round-trip.
  • Read-only flush-skip, FOR-clause hardening, NTX empty-rooted-leaf PACK/reindex (5004), composite key width no longer pinned to the 254-byte probe (follow-up to #68).
  • CDX index direction fix (v1.3.0): Harbour rddads / X# put compound vs descending option bits on swapped positions; descending now decoded only when both 0x02 and 0x08 are set, so Harbour/FiveWin indexes no longer build reversed.

Wire Protocol

  • Server-side filtered scan (FetchWhere, opcode 0xA4) — client sends a Clipper-style FOR predicate, server returns only matching rows.

Enterprise Server

  • Sharded-reactor connection pool (WorkerPool) behind OPENADS_SERVER_POOL (default OFF), FrameReader non-blocking partial-frame buffering, Session extracted from server.cpp.
  • EnterpriseConfig env tunables; session reaping + max-sessions cap; deadlock-free stop().

SQL Backends

  • PostgreSQL column metadata (IS_NULLABLE/COLUMN_DEFAULT) via information schema.
  • stmt_map serialisation (concurrency), SQLite busy-timeout + WAL, CREATE TABLE honours statement table type.

ABI

  • Connection/handle introspection: real AdsGetConnectionType (remote/local), AdsGetHandleType (by handle kind), AdsGetIndexCondition/AdsGetIndexFilename.

ADT / Build / Tooling

  • ADT companion-stream count fix; data_dict.cpp strict-warning cleanups; xBase++ smoke test; FiveWin ORM cookbook; concurrency tests.

Full CI green (msvc-x64, ninja-clang, ninja-clang/TLS, macos, PHP). Verified locally + over the wire against a live openads_serverd.

What's Changed

  • fix(abi): serialise stmt_map() so concurrent SQL statements don't corrupt it by @Admnwk in #82
  • cookbook(orm): build the track against hb_orm2 + a FiveWin grid fed by the ORM by @Admnwk in #70
  • test(cdx): empty-table bare CHAR key width + doc sync v1.2.2 by @Admnwk in #71
  • feat(serverd): bound session threads (reaping + optional max-sessions cap) for 24x7 servers by @Admnwk in #73
  • fix(cdx): don't pin composite index keys to the 254-byte probe width (follow-up to #68) by @Admnwk in #69
  • fix(adt): write the ADT header companion-type count instead of a flat 1 by @Admnwk in #75
  • feat(wire): server-side filtered scan (FetchWhere) for non-AOF predicates by @Admnwk in #80
  • fix(ntx): handle empty-but-rooted leaf on insert (PACK/reindex 5004) by @Admnwk in #83
  • fix(cdx): persist and apply conditional (FOR) index predicates by @Admnwk in #76
  • feat(pg): expose column nullable/default via AdsDDGetFieldProperty by @Admnwk in #84
  • feat(serverd): sharded-reactor connection pool behind OPENADS_SERVER_POOL (default off) by @Admnwk in #74

Full Changelog: v1.3.0...v1.4.0

v1.3.0 — CDX index direction fix for Harbour rddads / FiveWin

25 Jun 12:56

Choose a tag to compare

1.3.0

  • CDX index direction fix for Harbour rddads (FiveWin). AdsCreateIndex61 decoded descending = ulOptions & ADS_DESCENDING (0x08). Instrumenting the two RDD clients showed they place the compound/descending option bits on swapped positions: X#'s ADSRDD sends 0x02 for an ascending tag and 0x0A for descending, while Harbour's rddads sends 0x08 for ascending and 0x0A for descending. So a plain Harbour INDEX ON f TAG t (0x08) was read as descending and every Harbour/FiveWin index was built reversed — AdsGotoTop landed on the last key and Skip walked backward, so a TBrowse/tDatabase grid showed its rows upside-down (Seek still worked, which masked it). Direction is now decoded as descending only when both 0x02 and 0x08 are set (0x0A); a lone 0x02 or 0x08 is that client's compound marker and is ascending. The SQL CREATE INDEX path emits 0x0A for a descending tag so it round-trips through the same decode. Pinned by abi_cdx_index_direction_test and examples/fivewin/tdata_index_test.prg.
  • Build fix: drop a dead trim() in data_dict.cpp. An unreferenced static function tripped -WX C4505 on a clean MSVC build.

Includes everything from 1.2.x (CDX char key width, empty-leaf walk, leaf recno bits + prefix seek, MSSQL/NTX/ABI fixes).

Full Changelog: v1.2.3...v1.3.0

v1.2.3 — CDX char key width fix + clang build fix

24 Jun 22:54

Choose a tag to compare

1.2.3

  • CDX character index key width fix (PR #68). AdsCreateIndex61 derived a character tag's fixed key width from the trimmed value of the first record. When the first row was short (e.g. "ANA") and later rows shared a longer prefix ("ANABELA CARDOSO", "ANABELA FERREIRA"), every later key was truncated to the first row's width and collapsed onto the same stored key, so distinct values became indistinguishable and a seek landed on the wrong record — both inside the index and for native FoxPro/Clipper readers of the bag. The key width now comes from the declared field length for a bare character field, falling back to the untrimmed first-record width for a composite expression, keeping the 32-char default only for an empty table. Numeric CDX/NTX key widths are unchanged. Pinned by abi_cdx_char_keylen_test.
  • Build fix: <cstdint> in sqlite_uri_test. std::uint8_t was used without including <cstdint>; clang/libc++ does not pull it in transitively, so the ninja-clang -Werror CI job failed while MSVC and AppleClang stayed green. Added the explicit include.
  • Full unit suite 739/739, 0 regression.

What's Changed

  • fix(cdx): size a character index key from the field width, not the trimmed first record by @Admnwk in #68

Full Changelog: v1.2.2...v1.2.3

v1.2.2 — CDX/MSSQL/NTX/ABI fixes

24 Jun 20:09

Choose a tag to compare

Fixes

  • CDX empty-leaf walk (PR #63) — forward/backward index walks skip empty leaves left by \erase(). Fixes REINDEX/bulk-delete ADSCDX/5000.
  • CDX leaf recno bits + prefix seek (PR #62) — recno field sized from record count (not key length); partial seeks match on search-key length.
  • MSSQL backward SKIP (PR #65) — off-by-one: skip onto row 0 reads it, not BOF.
  • ABI typed getters for SQL backends (PR #66) — AdsGetDouble/Long/LongLong/String dispatch through backend ops vtable for PostgreSQL.
  • NTX numeric key format (PR #67) — native DBFNTX form (zero-padded + complemented negatives).

Tests

738/738 unit tests passing (was 726). New edge-case tests:

  • \�bi_ntx_numeric_edge_test.cpp\ — -0.0 normalisation, width/dec clamping, byte-complement, custom key
  • \cdx_empty_tree_test.cpp\ — empty tree, all-erased tree, exact prefix, descending prefix

Docs

  • Project history page (EN/ES/PT)
  • Changelog + whatsnew updated for v1.2.2

What's Changed

  • fix(ntx): store numeric index keys in the native DBFNTX form by @Admnwk in #67
  • fix(mssql): backward SKIP onto the first row reads row 0, not BOF by @Admnwk in #65
  • fix(abi): route typed getters + AdsGetIndexHandle through the per-backend ops vtable (PostgreSQL) by @Admnwk in #66
  • fix(cdx): skip empty leaves on forward index walks (fixes REINDEX/bulk-delete ADSCDX/5000) by @Admnwk in #63
  • fix(cdx): size leaf recno bits from record count; partial-key (prefix) seek by @Admnwk in #62

Full Changelog: v1.2.1...v1.2.2

v1.2.1

24 Jun 06:49

Choose a tag to compare

v1.2.1 — 2026-06-24

  • Added unit tests: adm_memo, codepage, maria_uri, postgres_uri, proc, sqlite_uri (706/706 tests pass)
  • Remote benchmark docs: iMac WiFi (784K rec/s) and charleskwon.com SSH tunnel (676K rec/s)
  • Removed sensitive credentials from tracking
  • ORM examples synced to v1.1.0-alpha

What's Changed

  • docs(cookbook): portable boolean type + honest seek-vs-scan narrative in all-backends bench by @Admnwk in #49
  • examples: self-contained ORM example over the ACE ABI by @Admnwk in #52
  • perf(cdx): 64 KB read-ahead block cache for the record read path by @Admnwk in #51
  • fix(engine): PACK rebuilds indexes; SOFT seek lands on next-greater key by @Admnwk in #40
  • feat(adt): M6 ADI index keys for Date/Time/Timestamp/Money/Logical by @Admnwk in #45
  • fix(abi): correct named-parameter substitution in AdsExecuteSQL (:p1/:p10 collision + 4096-byte truncation) by @Admnwk in #42
  • feat(sql): accept SAP ADS dialect ({static} hint, [bracket] tables, table alias, UPPER()/LOWER() in WHERE, WHERE 1=1, comma-join) by @Admnwk in #48
  • build: gate SQLite backend sources on OPENADS_WITH_SQLITE (fix OFF build) by @Admnwk in #43
  • feat: SQLCipher-compatible encrypted databases via the SQLite backend by @Admnwk in #19
  • fix(cdx,tx): multi-tag CDX allocator, branch erase, and safe transaction flush by @Admnwk in #25
  • feat(contrib): harbour-orm — ActiveRecord ORM for Harbour over the ACE ABI by @Admnwk in #29
  • fix(abi): reject INDEX expression naming an unknown column by @Admnwk in #56
  • fix(adi): correct multi-level char-key index build (runaway + truncated child page) by @Admnwk in #59
  • feat(sql-backend): native Firebird backend behind the backend-ops registry (stacked on #31) by @Admnwk in #54
  • fix(cdx): multi-tag OrdNumber, duplicate binding, and unbounded .cdx growth by @Admnwk in #55
  • fix: conform DBF/CDX/ADT writer to on-disk format so native engines open it by @Admnwk in #60
  • examples: standalone ACE self-test (Harbour host, no RDD) by @Admnwk in #61
  • feat: ODBC-backed table driver (read + write) behind the ACE ABI (builds on #18) by @Admnwk in #24
  • feat(ado): FiveWin ADO bridge class for OpenADS (TDataBase:SqlQuery via AdsExecuteSQLDirect) by @Admnwk in #26
  • test(bench): OpenADS Plus benchmark harness (NAV + exhaustive stress + ADS/OpenADS A/B) by @Admnwk in #27
  • examples(orm): sync to v1.1.0-alpha — events, soft-deletes, N:N + nested eager, withCount, ES + roadmap by @Admnwk in #64

Full Changelog: v1.1.0...v1.2.1

v1.2.0 — Deferred-Flush Bulk Insert + MSSQL Backend

24 Jun 05:22

Choose a tag to compare

v1.2.0 (2026-06-24)

Deferred-Flush Bulk-Insert Mode (528× speedup)

New \AdsSetDeferredFlush(hTable, 1)\ API puts the table into deferred-flush mode: \AdsWriteRecord\ writes the record to OS cache but skips the per-record \FlushFileBuffers\ call. Data is flushed only when \AdsFlushFileBuffers\ is called explicitly.

Benchmark: 500K records + CDX index

  • Before: ~2.7 hours (50 rec/s)
  • After: 26 seconds (26,381 rec/s)

MSSQL Native TDS 7.4 Backend

Native SQL Server connectivity via the TDS 7.4 wire protocol with optional mbedTLS encryption. URI: \mssql://user:pass@host:port/database. Enable: \OPENADS_WITH_MSSQL=ON.

Test Results

649/649 unit tests pass. 0 failures.

What's Changed

  • docs(cookbook): portable boolean type + honest seek-vs-scan narrative in all-backends bench by @Admnwk in #49
  • examples: self-contained ORM example over the ACE ABI by @Admnwk in #52
  • perf(cdx): 64 KB read-ahead block cache for the record read path by @Admnwk in #51
  • fix(engine): PACK rebuilds indexes; SOFT seek lands on next-greater key by @Admnwk in #40
  • feat(adt): M6 ADI index keys for Date/Time/Timestamp/Money/Logical by @Admnwk in #45
  • fix(abi): correct named-parameter substitution in AdsExecuteSQL (:p1/:p10 collision + 4096-byte truncation) by @Admnwk in #42
  • feat(sql): accept SAP ADS dialect ({static} hint, [bracket] tables, table alias, UPPER()/LOWER() in WHERE, WHERE 1=1, comma-join) by @Admnwk in #48
  • build: gate SQLite backend sources on OPENADS_WITH_SQLITE (fix OFF build) by @Admnwk in #43
  • feat: SQLCipher-compatible encrypted databases via the SQLite backend by @Admnwk in #19
  • fix(cdx,tx): multi-tag CDX allocator, branch erase, and safe transaction flush by @Admnwk in #25
  • feat(contrib): harbour-orm — ActiveRecord ORM for Harbour over the ACE ABI by @Admnwk in #29
  • fix(abi): reject INDEX expression naming an unknown column by @Admnwk in #56
  • fix(adi): correct multi-level char-key index build (runaway + truncated child page) by @Admnwk in #59
  • feat(sql-backend): native Firebird backend behind the backend-ops registry (stacked on #31) by @Admnwk in #54
  • fix(cdx): multi-tag OrdNumber, duplicate binding, and unbounded .cdx growth by @Admnwk in #55
  • fix: conform DBF/CDX/ADT writer to on-disk format so native engines open it by @Admnwk in #60
  • examples: standalone ACE self-test (Harbour host, no RDD) by @Admnwk in #61
  • feat: ODBC-backed table driver (read + write) behind the ACE ABI (builds on #18) by @Admnwk in #24

Full Changelog: v1.1.0...v1.2.0

v1.1.0

23 Jun 09:42

Choose a tag to compare

What's Changed

  • feat: SQLite + PostgreSQL + MariaDB + ODBC behind a pluggable backend-ops registry by @Admnwk in #31
  • feat: SQL passthrough — run SQL directly against the SQLite backend (builds on #18) by @Admnwk in #21
  • feat: PostgreSQL table driver behind the ACE ABI (builds on #18) by @Admnwk in #22
  • fix(abi): AdsSetDouble/AdsSetLogical honor remote tables (tcp:// navigational writes) by @Admnwk in #28

Full Changelog: v1.0.4...v1.1.0