Skip to content

Fix !specify first-call failure for lazily-discovered sink schemas - #246

Merged
jogrogan merged 1 commit into
mainfrom
jogrogan/specifyMutable
Aug 7, 2026
Merged

Fix !specify first-call failure for lazily-discovered sink schemas#246
jogrogan merged 1 commit into
mainfrom
jogrogan/specifyMutable

Conversation

@jogrogan

@jogrogan jogrogan commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Problem

CREATE OR REPLACE MATERIALIZED VIEW ... AS SELECT ... via !specify (dry-run)
failed with Table <name> not found in schema <schema> on the first
invocation, then succeeded on an identical second call. This made specifying
a pipeline into a lazily-discovered sink non-deterministic.

Root cause

DdlMode.SPECIFY.mutable() returned false, so processCreateMaterializedView /
processCreateTable navigated the schema via context.getRootSchema() — a
per-statement snapshot of the root — and registered the temporary sink view
there. But sink resolution (HoptimatorDriver.rowType) reads the live
connection root (connection.calciteConnection().getRootSchema()).

For sinks whose sub-schema is implicit/lazy (not pre-enumerated), the snapshot
and live roots resolve to different CalciteSchema wrappers with different table
maps on a cold cache, so the view added to the snapshot was invisible to the
live-root read. The failed first call warmed Calcite's schema caches enough that
the two roots aligned on the second.

Fix

  • All DDL modes now navigate/register against the live (mutable) root schema,
    so the temporary view is resolvable by sink resolution on the first call.
  • That made DdlMode.mutable() always true (dead), so it's removed and
    replaced with a single-purpose dryRun() flag (true for SPECIFY,
    false for CREATE/UPDATE) that drives rollback: SPECIFY restores the
    temporary view and any deployer side effects; CREATE/UPDATE keep their
    mutations on success.

This keeps !specify side-effect-free while fixing first-call resolution.

Testing

  • HoptimatorDdlUtilsTest passes; the ...MutableReturns... tests are replaced
    with ...DryRun... equivalents (SPECIFY.dryRun() == true,
    CREATE/UPDATE.dryRun() == false).

CREATE OR REPLACE MATERIALIZED VIEW via !specify (dry-run) failed with
"Table <name> not found in schema <schema>" on the first invocation and
only succeeded on an identical second call, for sinks whose schema is
discovered lazily (e.g. OpenHouse namespaces).

Root cause: DdlMode.SPECIFY navigated the schema via context.getRootSchema(),
a per-statement snapshot, and registered the temporary sink view there. But
sink resolution (HoptimatorDriver.rowType) reads the live connection root.
On a cold cache the snapshot and live roots resolve to different CalciteSchema
wrappers, so the temp view was invisible to the read. The failed first call
warmed Calcite's caches enough to align the two roots on the second call.

Fix: all DDL modes now register against the live (mutable) root schema, so the
temporary view is resolvable on the first call. Since that made DdlMode.mutable()
always true, it is removed and replaced with a single-purpose dryRun() flag that
drives dry-run rollback: SPECIFY restores the temporary view and any deployer
side effects; CREATE/UPDATE keep their mutations on success. This keeps !specify
side-effect-free while fixing first-call resolution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Coverage

Overall Project 84.75% 🟢
Files changed 100% 🟢

File Coverage
HoptimatorDdlUtils.java 87.2% 🟢

@jogrogan
jogrogan merged commit e63d9ee into main Aug 7, 2026
1 check passed
@jogrogan
jogrogan deleted the jogrogan/specifyMutable branch August 7, 2026 19:30
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.

2 participants