Skip to content

FiveTech_ERP: driver de datos opcional "hdbc" (RDDHDBC sobre MariaDB) - #26

Open
russimicro wants to merge 10 commits into
mainfrom
feature/hdbc-sql-driver
Open

FiveTech_ERP: driver de datos opcional "hdbc" (RDDHDBC sobre MariaDB)#26
russimicro wants to merge 10 commits into
mainfrom
feature/hdbc-sql-driver

Conversation

@russimicro

Copy link
Copy Markdown
Collaborator

Resumen

erp_db.prg ya tiene una capa de datos intercambiable (json por defecto,
dbfcdx, openads). Este PR agrega un cuarto driver, hdbc, respaldado
por RDDHDBC — un RDD de terceros (Manu Expósito) que traduce los verbos
xBase estándar a MariaDB.

Por qué encaja como RDD (y no como SQL crudo)

erp_db.prg ya habla con cada backend exclusivamente a través de verbos RDD
planos — dbUseArea / dbGoTop / dbSkip / FieldGet / dbAppend / RLock / FieldPut / dbDelete / dbCommit — nunca arma SQL a mano. RDDHDBC opera
exactamente a ese nivel (USE <tabla> VIA "HDBC"), así que el cambio es
puramente aditivo: cero cambios en erp_http.prg (su despacho if ErpDbDriver() != "json" ya es genérico) y cero cambios en
ErpDbReadRows/ErpDbApply.

Qué NO incluye este PR (importante)

Este PR no distribuye, vincula ni referencia ningún código o nombre de
API de RDDHDBC/HDBC. Es software comercial de Manu Expósito con licencia
propia — conseguirlo y usarlo es un acuerdo entre cada usuario y él, igual
que con MariaDB.

  • La rama nueva en ErpDbConfig/ErpDbOpen/ErpDbStatus solo compila
    cuando el build define HB_WITH_HDBC.
  • Solo llama a una función (ErpDbHdbcUserConnect) que cada usuario
    implementa en su propio archivo aparte
    , con su propio paquete HDBC
    licenciado — nunca parte de este repo.
  • build_win64.bat sigue el mismo contrato "compila limpio sin ello" que
    ya usa para ace64.dll de OpenADS, adaptado para una lib estática:
    requiere hdbctools.lib propia del usuario en %HBLIB% y
    HDBC_CONNECT_PRG apuntando a su conector. Sin ambos, el build es
    idéntico a hoy (verificado: erp_db.prg compila limpio con y sin
    -dHB_WITH_HDBC usando harbour.exe local).

Detalle completo del contrato, cómo activarlo y límites conocidos (no
auto-crea tablas; RLock() es por-proceso, no por-base) en
docs/hdbc-driver.md.

Verificación

harbour.exe erp_db.prg -n -w -es2 -q   → OK
harbour.exe erp_db.prg -n -w -es2 -q -dHB_WITH_HDBC   → OK (mismos symbols, sin linkear nada)

🤖 Generado con Claude Code

russimicro and others added 3 commits August 8, 2026 14:44
Extends the existing pluggable data layer (json/dbfcdx/openads in
erp_db.prg) with a fourth driver, backed by RDDHDBC — a third-party RDD
(Manu Exposito) that maps standard xBase RDD calls onto MariaDB. It fits
cleanly because erp_db.prg already talks to every backend through plain
RDD verbs (dbUseArea/dbGoTop/dbSkip/FieldGet/dbAppend/RLock/FieldPut/
dbDelete/dbCommit) — never hand-built SQL — which is exactly the level
RDDHDBC operates at; erp_http.prg's driver dispatch needs no changes.

This ships no third-party code: the new branch in ErpDbConfig/ErpDbOpen/
ErpDbStatus only compiles in when the build defines HB_WITH_HDBC, and only
calls a function (ErpDbHdbcUserConnect) that each user supplies themselves,
in their own separate .prg, using their own licensed HDBC package —
mirroring the same "compiles clean without it" contract build_win64.bat
already uses for OpenADS's ace64.dll, adapted for a statically-linked lib:
hdbctools.lib and HDBC_CONNECT_PRG are both opt-in build inputs; without
them the build is unchanged. See docs/hdbc-driver.md for the full contract,
how to enable it, and known limits (no auto-create, process-local record
locks) worth validating against your own RDDHDBC version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
well-trodden problem, not a blocker for the hdbc driver

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sql)

Replaces the vague "migration is a well-trodden path" doc note with an
actual, working generator: ErpDbHdbcSchemaSql() in erp_db.prg reuses the
same JSON-schema inference dbfcdx already relies on (ErpDbInferSchema) to
emit one "CREATE TABLE IF NOT EXISTS" per data.* dataset, plus the
_h_rowid_/deleted_at bookkeeping columns RDDHDBC tables need. It only ever
produces text — no HDBC dependency, no live connection, nothing executed
against any database — exposed at GET /api/db/schema-sql (same session
auth as the existing /api/db/status) for the user to review and run by
hand. RDDHDBC's own index-metadata table is explicitly out of scope here;
that's on RDDHDBC's own setup docs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@russimicro

Copy link
Copy Markdown
Collaborator Author

Actualización: generador de esquema propio (no un migrador externo)

El mensaje anterior de este PR mencionaba de forma vaga que "existe tooling
de migración" para provisionar el esquema de MariaDB. Eso no era preciso —
en su lugar, esta actualización aporta el generador real:

  • ErpDbHdbcSchemaSql() en erp_db.prg: reutiliza la misma inferencia de
    esquema que dbfcdx ya usa (ErpDbInferSchema) para emitir un
    CREATE TABLE IF NOT EXISTS por cada dataset data.*, agregando las
    columnas de control _h_rowid_/deleted_at que las tablas de RDDHDBC
    necesitan. Solo genera texto — cero dependencia de HDBC, cero conexión
    viva, nada se ejecuta contra ninguna base.
  • GET /api/db/schema-sql (misma autenticación de sesión que
    /api/db/status ya usa) expone ese texto para revisar y ejecutar a mano
    (curl ... > schema.sql && mysql -u ... < schema.sql).

La tabla propia de metadatos de índices de RDDHDBC queda explícitamente
fuera de alcance — eso sigue siendo de su propia documentación.

Verificado: erp_db.prg/erp_http.prg compilan limpio con y sin
-dHB_WITH_HDBC.

🤖 Generado con Claude Code

russimicro and others added 2 commits August 8, 2026 15:48
ErpDbReadRows()/ErpDbApply() require <name>.map.json to exist before the
hdbc driver can do anything; the schema generator was inferring it but
never saving it, unlike the dbfcdx path it mirrors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Small standalone page (own static file under www/, no build step) that
reads/writes meta/app.json -> "database" through the existing admin-gated
GET/POST /api/meta contract (same one the runtime form designer already
uses) and shows GET /api/db/status. Lets you pick driver (json/dbfcdx/
openads/hdbc) and its host/port/dataPath/user/password without hand-editing
JSON, and links to GET /api/db/schema-sql for the hdbc DDL preview.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@russimicro

Copy link
Copy Markdown
Collaborator Author

Actualización: UI de configuración + validación end-to-end del esquema

  • www/db-config.html (nuevo): página admin standalone que lee/escribe
    meta/app.json -> "database" vía el contrato ya existente
    GET/POST /api/meta (mismo que usa el runtime form designer, gateado por
    ErpSessIsAdmin). Permite elegir driver (json/dbfcdx/openads/hdbc)
    y host/port/dataPath/user/password sin editar JSON a mano, y muestra
    GET /api/db/status en vivo.
  • Fix: ErpDbHdbcSchemaSql() generaba el DDL pero no persistía el
    .map.json inferido — sin eso, ErpDbReadRows/ErpDbApply no podrían
    funcionar aunque el driver esté disponible. Ya corregido (mismo
    comportamiento que el path dbfcdx: ErpDbLoadMap primero, ErpDbSaveMap
    solo si no existía).
  • Validado contra una base MariaDB real (entorno local propio, no
    parte de este repo): el DDL que genera ErpDbHdbcTableSql/
    ErpDbHdbcSchemaSql — incluyendo el fix de identificadores reservados
    (`columna` con backticks; user/key/when rompían sin esto en
    algunos datasets) — crea y puebla correctamente las 45 tablas del sample
    demo a partir de meta/data/*.json. Corregí el mismo problema de
    backticks en ErpDbHdbcTableSql (Harbour) para que coincida con lo
    probado.

🤖 Generado con Claude Code

russimicro and others added 2 commits August 8, 2026 15:54
Found by actually running the generated DDL against a real MariaDB server:
several demo dataset/field names (user, key, when, ...) are MariaDB
reserved words and broke CREATE TABLE without quoting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Both found by actually building and running this against a real MariaDB
(own local RDDHDBC license, verified end-to-end: reads, add, update,
delete all round-tripped correctly against real SQL data):

1. The RDD's registered name is "RDDHDBC", not "HDBC" — dbUseArea() was
   using the wrong string. Also drops the now-pointless top-of-file
   REQUEST: there's no linkable "RDDHDBC" function symbol to request; the
   RDD's registration module gets force-linked automatically because
   ErpDbHdbcUserConnect() (required by the contract) already calls one of
   its real public functions from the same compiled unit.
2. ErpDbApply()'s "delete not persisted" re-check via Deleted() right after
   dbDelete() is an OpenADS-specific workaround for a known quirk there; it
   produced false negatives on hdbc, where deletes persist correctly
   (deleted_at set, confirmed with direct SQL) even though Deleted() on the
   just-modified record can read back .F. before the next fetch. Scoped to
   driver == "openads" only.

docs/hdbc-driver.md updated with what was actually verified.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@russimicro

Copy link
Copy Markdown
Collaborator Author

Validado end-to-end contra una MariaDB real (entorno propio, no en este repo)

Compilé este driver con mi propia licencia de RDDHDBC (fuera del repo) y lo
corrí contra una base MariaDB real. Encontré y corregí 2 bugs reales:

  1. Nombre de RDD incorrecto: el RDD se registra como "RDDHDBC", no
    "HDBC" — corregido en dbUseArea(). También quité el REQUEST del
    encabezado: no existe un símbolo de link directo para eso; basta con que
    ErpDbHdbcUserConnect() (ya exigido por el contrato) llame a cualquier
    función pública real del RDD, que fuerza el enlace del mismo módulo
    compilado que registra el RDD.
  2. Falso negativo en delete: el chequeo Deleted() post-dbDelete()
    en ErpDbApply() es un workaround específico de una peculiaridad de
    OpenADS; con hdbc reportaba error aunque el borrado sí se persistía
    (deleted_at seteado, confirmado con SQL directo). Ahora acotado a
    driver == "openads".

Resultado tras los fixes (verificado con SQL directo en paralelo):

  • GET /api/db/statushdbcAvailable:true, driver activo hdbc.
  • GET /api/dataset?key=data.products → filas reales desde MariaDB
    (UTF-8/tildes intactos), no del JSON.
  • POST /api/dataset (add/update/delete) → los tres round-trips
    correctos, confirmados con SELECT directo contra la tabla.

docs/hdbc-driver.md actualizado con el detalle de lo verificado.

🤖 Generado con Claude Code

russimicro added a commit that referenced this pull request Aug 8, 2026
Makes the driver-config page reachable from the "PC" branch: this same
portal already loads inside the exe's own embedded WebView2 via
ZWEB_FRONT=portal, so this link surfaces there too, not just in a browser.

Note: db-config.html itself ships in the companion "hdbc" driver PR
(#26), not this one — the link 404s until that lands, same as any other
cross-PR reference would.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… folder

Lets the "PC" branch reach db-config.html directly inside its own embedded
WebView2 (ZWEB_FRONT=db-config.html) instead of only being reachable from a
browser. Backward compatible: ZWEB_FRONT=web-vainilla / =portal (bundle
folders, PR #24) still resolve to <name>/index.html exactly as before —
only a value already ending in ".html" skips that suffix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@russimicro

Copy link
Copy Markdown
Collaborator Author

Alcanzable desde la rama PC también

Con el patrocinio del usuario: agregué en `Form1.prg` que `ZWEB_FRONT` acepte
un archivo suelto (`ZWEB_FRONT=db-config.html`), no solo una carpeta con
`index.html` — retrocompatible con `ZWEB_FRONT=web-vainilla`/`=portal` del
PR #24. Así la vista de escritorio (WebView2 embebido) también puede cargar
la página de configuración de driver directamente, sin depender de un
navegador aparte. Además agregué un enlace "Base de datos" en el portal
del PR #24 (`www/portal/index.html`), que ya se carga dentro del propio
exe vía `ZWEB_FRONT=portal`.

🤖 Generado con Claude Code

russimicro and others added 2 commits August 8, 2026 16:43
www/dashboard.html already had a driver select + host/port/dataPath/user/
password fields (shared with openads, same shape hdbc needs) — it just
didn't list hdbc as an option. Adds the <option> and extends the existing
openads visibility toggle to also show those fields for hdbc. The save
handler already read all these fields generically, so this is UI-only.

Heads up (documented in docs/hdbc-driver.md): dashboard.html is normally
regenerated from FWH's login.prg by sync_meta.bat, so this two-line change
needs to be mirrored in the FWH source to survive the next sync.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
confusing later error

Navigating straight to /db-config.html without a session first made the
initial GET /api/meta?key=app fail silently (message only shown, easy to
miss); clicking Guardar afterwards then failed with the unrelated-looking
"Todavia no cargo meta/app.json." Now hides the form and shows a direct
link to /login as soon as either GET call reports not authenticated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant