Skip to content

Skip SQL job generation when a pipeline source or sink has no connector - #247

Merged
jogrogan merged 1 commit into
mainfrom
jogrogan/emptyConnector
Aug 8, 2026
Merged

Skip SQL job generation when a pipeline source or sink has no connector#247
jogrogan merged 1 commit into
mainfrom
jogrogan/emptyConnector

Conversation

@jogrogan

@jogrogan jogrogan commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

What

Teach the pipeline planner to skip Flink SQL job generation when a table involved in the pipeline has no connector configuration (i.e. an empty WITH () clause). Such tables are moved by a non-SQL JobTemplate (e.g. a triggered/ETL-style job) rather than a Flink SqlJob, so emitting a SqlJob for them produces SQL that is unrunnable and fails at Flink runtime.

Why

A JobTemplate with no databases filter matches every sink, so a connector-less table would still get a Flink SqlJob rendered against it — e.g. CREATE TABLE … WITH () followed by an INSERT INTO that Flink cannot execute. This affects both directions:

  • Connector-less sink (e.g. a table materialized by a downstream non-SQL job): the generated SqlJob writes into an empty-connector sink.
  • Connector-less source (the reverse case): the generated SqlJob reads from an empty-connector source.

Both should render only their non-SQL JobTemplate, never a broken SqlJob.

How

  • Add MissingConnectorException (hoptimator-api), a SQLNonTransientException signaling that a table has no connector and therefore cannot participate in a generated SQL job.
  • PipelineRel throws it while resolving connector configs when the sink (sql()) or any source (script()) has an empty config map.
  • Callers that generate SQL treat it as "skip the SQL job," not an error:
    • K8sJobDeployer — a sqlOrNull helper catches it so {{sql}}/{{flinksql}} resolve to null, which drops SQL-based JobTemplates during rendering while non-SQL templates still render.
    • LogicalTableDeployer and K8sMaterializedViewDeployer — catch it and treat the pipeline as having no SQL (null → nullable Pipeline CR field).
  • K8sPipelineDeployer stores "" instead of null for the Pipeline CR sql field.

Tests

  • PipelineRelImplementorTest — new cases asserting sql() throws MissingConnectorException when the sink or a source has no connector; existing SQL-generation tests stub a non-empty connector.
  • K8sJobDeployerTest — new cases asserting a connector-less sink skips the SQL template while a non-SQL template still renders, and that a sink with a connector still renders the SQL template.

Fixtures

  • deploy/samples/demodb.yaml: add ads-catalog-database to demodb-write-template's databases. The offline demo tier (ADS_CATALOG) previously had only a read/trigger template, so its sink had no write connector — the missing write connector is the fixture bug this surfaced. The nearline→offline logical-table integration graph now correctly renders a FlinkSessionJob for that tier.

Compatibility

No public API changes. sql()'s contract now allows throwing MissingConnectorException; all in-tree callers handle it.

A JobTemplate with no `databases` filter matches every sink, so a table
with no connector configuration (empty `WITH ()`) would still get a Flink
SqlJob rendered against it -- e.g. `CREATE TABLE ... WITH ()` plus an
`INSERT INTO` that Flink cannot execute. Such tables are moved by a
non-SQL JobTemplate rather than a SqlJob. This happens in both directions:
a connector-less sink (materialized by a downstream non-SQL job) and a
connector-less source (the reverse case).

Add MissingConnectorException (SQLNonTransientException) to signal that a
table has no connector and cannot participate in a generated SQL job.
PipelineRel throws it while resolving connector configs when the sink
(sql()) or any source (script()) has an empty config map. Callers that
generate SQL treat it as 'skip the SQL job', not an error:

  - K8sJobDeployer: a sqlOrNull helper catches it so {{sql}}/{{flinksql}}
    resolve to null, dropping SQL-based JobTemplates during rendering while
    non-SQL templates still render.
  - LogicalTableDeployer and K8sMaterializedViewDeployer: catch it and treat
    the pipeline as having no SQL.
  - K8sPipelineDeployer stores "" instead of null for the Pipeline CR sql.

Fixture: add ads-catalog-database to demodb-write-template's databases. The
offline demo tier (ADS_CATALOG) previously had only a read/trigger template,
so its sink had no write connector; the nearline->offline logical-table
graph now correctly renders a FlinkSessionJob for that tier.

Tests (per testing-best-practices.md): PipelineRelImplementorTest asserts
sql() throws when the sink or a source has no connector; K8sJobDeployerTest
asserts a connector-less sink skips the SQL template while a non-SQL template
still renders.

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

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

Code Coverage

Overall Project 84.74% -0.04% 🟢
Files changed 75.31% 🟢

File Coverage
MissingConnectorException.java 100% 🟢
K8sJobDeployer.java 100% 🟢
PipelineRel.java 96.02% 🟢
K8sMaterializedViewDeployer.java 94.9% -1.18% 🟢
K8sPipelineDeployer.java 94.37% -2.82% 🟢
LogicalTableDeployer.java 74.04% -1.08%

@ryannedolan ryannedolan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow great idea. Nice writeup as well.

@jogrogan
jogrogan merged commit d0387ae into main Aug 8, 2026
1 check passed
@jogrogan
jogrogan deleted the jogrogan/emptyConnector branch August 8, 2026 17:02
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