Skip to content

fix(meerkat-core): qualify lookup columns to stop ambiguous CSV export (ISS-301213)#280

Open
jayachandranramadoss-devrev wants to merge 1 commit into
mainfrom
iss/301213-qualify-lookup-alias
Open

fix(meerkat-core): qualify lookup columns to stop ambiguous CSV export (ISS-301213)#280
jayachandranramadoss-devrev wants to merge 1 commit into
mainfrom
iss/301213-qualify-lookup-alias

Conversation

@jayachandranramadoss-devrev

Copy link
Copy Markdown
Contributor

Summary

  • Fixes CSV export Binder Error: Ambiguous reference to column name when resolution joins multiple lookup tables that share a raw column name (e.g. deprecated_created_by_agent_id on both dim_devu and dim_group — Razorpay Incident dashboard, TKT-65015).
  • Root cause: each lookup is joined as SELECT <named cols>, * FROM (<lookupSql>). The trailing bare * re-exposes every raw column of the lookup, so a name shared across two lookups appears twice in the intermediate join relation and DuckDB's binder rejects the export.
  • Approach (qualify): rewrite each lookup table's SQL to project its declared dimensions (plus the join column) under a globally-unique table-qualified alias <config>__<column>. The bare * then only ever surfaces uniquely-named columns, so the ambiguity cannot occur.

Why not PR #272's narrowing

PR #272 narrows each lookup to only the join + resolution columns (drops the rest). This PR instead renames every declared column to a unique qualified alias — it keeps all declared lookup columns available and also disambiguates shared declared column names, not just undeclared passthrough ones.

Changes

  • generate-resolution-schemas.ts: add buildQualifiedLookupSql (projects <wrapAlias>."<col>" AS "<config>__<col>"), and resolutionJoinColumnAlias helper; resolution dimension .sql now references the qualified alias.
  • resolution.ts: join ON clause references the qualified join-column alias.
  • Test expectations updated: resolution.spec.ts (core + node), generate-resolution-schemas.spec.ts, resolution-step.spec.ts.
  • New resolution-shared-column-ambiguity.spec.ts regression test.

DevRev

work-item: ISS-301213

Test plan

  • New regression test: each shared lookup column projected under a distinct qualified alias; export COPYs to CSV with resolved values + row count intact.
  • meerkat-core: 549 passed. meerkat-node: 906 passed. meerkat-browser: 2 passed.
  • Joins, array/UNNEST joins, filters, SQL-overrides all unaffected.
  • Verified self-contained: no other site references lookup columns by raw name; devrev-web consumes export SQL opaquely and CSV headers (outer projection) are byte-identical, so user-facing output is unchanged.

🤖 Generated with Claude Code

…t (ISS-301213)

CSV export from dashboard widgets failed with `Binder Error: Ambiguous
reference to column name` when a base query joined multiple lookup tables
that share a raw column name (e.g. `deprecated_created_by_agent_id` on both
`dim_devu` and `dim_group`, seen on the Razorpay Incident dashboard /
TKT-65015).

Each resolution lookup is joined as `SELECT <named cols>, * FROM (<lookupSql>)`.
The trailing bare `*` re-exposed every raw column of the lookup, so a column
name shared across two lookups appeared twice in the intermediate join
relation and the binder rejected the export.

Fix: rewrite each lookup table's SQL so it projects its declared dimensions
(plus the join column) under a globally-unique table-qualified alias
`<config>__<column>`. The bare `*` then only ever surfaces uniquely-named
columns, so the ambiguity cannot occur. The resolution dimension `.sql` and
the join ON clause are updated to reference the same qualified aliases.

This is an alternative to the post-hoc narrowing approach in PR #272: it
keeps every declared lookup column available (renamed) rather than dropping
unreferenced ones, and disambiguates even shared *declared* column names.

Test plan:
- New regression test asserts each lookup column is projected under a
  distinct qualified alias and the export COPYs with resolved values intact.
- meerkat-core: 549 passed. meerkat-node: 906 passed. meerkat-browser: 2 passed.
@github-actions

Copy link
Copy Markdown

⚠️ Heads-up: This repository will be blocked from any work other than patching.

File meerkat-core/src/resolution/generators/tests/generate-resolution-schemas.spec.ts is not allowed to be modified in this patch.
The following vulnerability issues are past SLA:

Note that there is significant latency in updating this list. Please reach out on #antifragile if you are in a hurry or have an emergency.

@jayachandranramadoss-devrev

Copy link
Copy Markdown
Contributor Author

Why this fix lives in meerkat, not devrev-web

A reasonable question: the lookup table SQL is built in devrev-web (createResolutionSchemasdataSourceToMeerkatSchema), so could we fix the ambiguity there alone — e.g. by aliasing each resolution column as table.column?

No — a devrev-web-only rename breaks the join. The column references are generated inside meerkat, by raw column name:

  • join ON clause → <lookup>.<joinColumn> (e.g. dim_devu.id)
  • resolved dimension → <lookup>.<column> (e.g. dim_devu.fullname)

If devrev-web renamed the lookup's projected columns to qualified aliases ("dim_devu.id", "dim_devu.fullname"), the bare id / fullname would no longer exist as output names, and meerkat's references would point at non-existent columns. The projected alias and the name meerkat looks up must be the same string, so you cannot make it simultaneously unique and still match meerkat's raw-name references — from devrev-web alone.

This fix avoids that wall by changing both ends in the same repo: the lookup projects ... AS "<config>__<column>" and the join/reference code (resolution.ts, generate-resolution-schemas.ts) is updated to reference the same qualified alias. That coordination is only possible inside meerkat.

The only devrev-web-only change that would work without a meerkat release is narrowing (dropping unused passthrough columns like deprecated_created_by_agent_id), not renaming. That is exactly the approach in the now-closed #272, and it has a residual hole: every lookup still projects its id join column by raw name, so two lookups can still collide on id (or any other shared declared column). The qualify approach here renames every column uniquely and has no such hole.

Rollout note

Production currently ships @devrev/meerkat-core@0.0.130. For this fix to reach users (TKT-65015 / Razorpay): merge → publish meerkat → bump the @devrev/meerkat-* deps in devrev-web. No devrev-web code changes are required to adopt it — the export SQL shape changes only inside lookup subqueries, and user-facing CSV headers (the outer projection) are byte-identical.

@jayachandranramadoss-devrev jayachandranramadoss-devrev enabled auto-merge (squash) June 15, 2026 16:27
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