Summary
docs/en/migrating-from-ads.md positions OpenADS as a drop-in replacement for SAP ACE ("move without rewriting"), but does not warn users that CDX files written by OpenADS are unreadable by SAP ACE. Applications that migrate to OpenADS, then attempt to switch back to ace64.dll from SAP (rollback, side-by-side testing, or mixed environment), get error 7017 Corrupt .ADI, .CDX, or .IDX index on every table that OpenADS has written to.
This is not a bug in the write path — it is intentional per src/drivers/cdx/cdx_index.cpp:1686:
// Harbour index signature "RCHB" (big-endian) at offset 20, as the
// native writer emits for the structure tag (TagBlock == 0).
file_hdr[20] = 0x52; file_hdr[21] = 0x43;
OpenADS emulates Harbour's native DBFCDX writer format, not the ACE CDX format. Both share the .cdx extension but are not binary-compatible headers. That's a defensible engineering choice, but users hitting rollback need to be told upfront.
Reproduction
- Start with SAP-built
DRUKAR.cdx (single-tag CDX, ~3 KB) — SAP opens it fine.
- Point application at OpenADS
ace64.dll, open the table and let OpenADS write to it (any index rebuild or record append that touches the CDX).
- Restore SAP
ace64.dll and re-open the same table → error 7017 Corrupt .CDX.
Header diff (offset 0x00-0x1F, 3 KB DRUKAR.cdx):
| Offset |
SAP |
OpenADS |
Meaning |
0x04-07 |
00 00 00 00 |
FF FF FF FF |
free-page pointer |
0x08-0B |
00 00 00 01 (BE) |
01 00 00 00 (LE) |
version/count word |
0x0F |
00 |
01 |
flag byte |
0x10-13 |
zeros |
00 04 00 02 |
reserved area, populated |
0x14-17 |
zeros |
52 43 48 42 = RCHB |
Harbour-writer magic |
0x614-1B |
zeros |
DRUKAR\0 extra copy |
extra tag-name string |
SAP's parser trips on the non-zero header/RCHB bytes and returns 7017.
What the docs currently say (and don't say)
docs/en/migrating-from-ads.md — pitches OpenADS as ADS-compatible, "move without rewriting", but has no section on rollback or on binary CDX format differences.
docs/en/known-issues.md — no mention of CDX header layout, 7017, or RCHB. The one CDX-adjacent note is about the ADS_DESCENDING flag value (0x08 vs 0x02), which is API-level, not file-format.
docs/en/rddads-compat.md — no mention.
docs/en/ordinal-compat.md — covers the DLL-level ordinal issue but not the on-disk format.
A user following the migration guide has no way to discover the one-way nature of the transition until an outage forces a rollback.
Proposed fix (docs only)
Add a short section to migrating-from-ads.md (or a dedicated docs/en/rollback.md linked from it), roughly:
Rollback to SAP ACE is not automatic
OpenADS writes CDX files in Harbour's DBFCDX-compatible format (magic RCHB at offset 0x14 in each CDX header). SAP ACE does not recognize this format and will return error 7017 "Corrupt .ADI, .CDX, or .IDX index" on any table whose CDX has been touched by OpenADS.
If you may need to run against SAP ACE again later (rollback, mixed environment, side-by-side benchmark), either:
- Keep the original SAP-built CDX files backed up outside the working directory before pointing the app at OpenADS, or
- After rolling back, run a global
DELETE FILE *.cdx + rebuild-all-tags pass under SAP.
This does not apply in reverse: OpenADS reads SAP-built CDX files without modification, as long as no write happens.
Optionally: mention it near the top of migrating-from-ads.md as a callout, since it's the kind of thing that surprises people at the worst moment (production incident, needing to revert).
Not a feature request
I understand the format choice is deliberate and rewriting the whole write path in ACE-binary shape isn't in scope for this ticket. Just the documentation gap.
Related: #128 (perf regression on INDEX ON — separate concern). Both surfaced during a real-world evaluation on a 5.6 GB, 609-table Harbour/rddads app; happy to share more repro details from that environment on request.
Summary
docs/en/migrating-from-ads.mdpositions OpenADS as a drop-in replacement for SAP ACE ("move without rewriting"), but does not warn users that CDX files written by OpenADS are unreadable by SAP ACE. Applications that migrate to OpenADS, then attempt to switch back toace64.dllfrom SAP (rollback, side-by-side testing, or mixed environment), get error 7017Corrupt .ADI, .CDX, or .IDX indexon every table that OpenADS has written to.This is not a bug in the write path — it is intentional per
src/drivers/cdx/cdx_index.cpp:1686:OpenADS emulates Harbour's native DBFCDX writer format, not the ACE CDX format. Both share the
.cdxextension but are not binary-compatible headers. That's a defensible engineering choice, but users hitting rollback need to be told upfront.Reproduction
DRUKAR.cdx(single-tag CDX, ~3 KB) — SAP opens it fine.ace64.dll, open the table and let OpenADS write to it (any index rebuild or record append that touches the CDX).ace64.dlland re-open the same table → error 7017Corrupt .CDX.Header diff (offset 0x00-0x1F, 3 KB
DRUKAR.cdx):0x04-0700 00 00 00FF FF FF FF0x08-0B00 00 00 01(BE)01 00 00 00(LE)0x0F00010x10-1300 04 00 020x14-1752 43 48 42=RCHB0x614-1BDRUKAR\0extra copySAP's parser trips on the non-zero header/
RCHBbytes and returns 7017.What the docs currently say (and don't say)
docs/en/migrating-from-ads.md— pitches OpenADS as ADS-compatible, "move without rewriting", but has no section on rollback or on binary CDX format differences.docs/en/known-issues.md— no mention of CDX header layout, 7017, orRCHB. The one CDX-adjacent note is about theADS_DESCENDINGflag value (0x08 vs 0x02), which is API-level, not file-format.docs/en/rddads-compat.md— no mention.docs/en/ordinal-compat.md— covers the DLL-level ordinal issue but not the on-disk format.A user following the migration guide has no way to discover the one-way nature of the transition until an outage forces a rollback.
Proposed fix (docs only)
Add a short section to
migrating-from-ads.md(or a dedicateddocs/en/rollback.mdlinked from it), roughly:Optionally: mention it near the top of
migrating-from-ads.mdas a callout, since it's the kind of thing that surprises people at the worst moment (production incident, needing to revert).Not a feature request
I understand the format choice is deliberate and rewriting the whole write path in ACE-binary shape isn't in scope for this ticket. Just the documentation gap.
Related: #128 (perf regression on
INDEX ON— separate concern). Both surfaced during a real-world evaluation on a 5.6 GB, 609-table Harbour/rddadsapp; happy to share more repro details from that environment on request.