Skip to content

[FLINK-40170][table-planner] Infer update-producing changelog mode for early-fire interval join - #28877

Draft
weiqingy wants to merge 2 commits into
apache:masterfrom
weiqingy:FLINK-36953-pr3-changelog
Draft

[FLINK-40170][table-planner] Infer update-producing changelog mode for early-fire interval join#28877
weiqingy wants to merge 2 commits into
apache:masterfrom
weiqingy:FLINK-36953-pr3-changelog

Conversation

@weiqingy

@weiqingy weiqingy commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Part of the FLIP-497 implementation stack under umbrella FLINK-36953. Landing order:

Step Sub-task Scope
PR-1a FLINK-40167 EARLY_FIRE hint surface + option validation (#28353, merged)
PR-1b FLINK-40168 Thread the hint into the interval join (#28796, merged)
PR-2 FLINK-40169 target option (#28827, in review)
PR-3 (this PR) FLINK-40170 Update-producing changelog mode + insert-only guard
PR-4 FLINK-40171 Runtime early-fire emit + retraction
PR-5 FLINK-40172 Processing-time early fire on an event-time join
PR-6 FLINK-40173 State restore coverage
PR-7 FLINK-40174 User-facing documentation

Opened as a draft because it is stacked on #28827, which is still in review. Until that merges, the commit list and diff here also carry PR-2's commit. Once #28827 merges I will rebase onto master, leaving only this PR's change, and take it out of draft.

What is the purpose of the change

With the EARLY_FIRE hint, an outer interval join emits a speculative null-padded row after the delay and corrects it when a match later arrives, so its result is no longer insert-only. This makes the planner infer that update-producing changelog mode, and reject an insert-only downstream with an error that names the hint instead of the generic "doesn't support consuming update changes" message. Inner joins and negative-window joins only ever emit inserts, so the hint stays inert for them and they remain append-only.

Runtime behavior is unchanged. The operator still ignores the hint; emission lands in PR-4.

Brief change log

  • FlinkChangelogModeInferenceProgram gets its own ModifyKindSet arm for StreamPhysicalIntervalJoin: children still consume insert-only, but the node provides INSERT and, when the hint makes it update-producing, UPDATE. It keeps its place in the UpdateKind and DeleteKind arms.
  • StreamPhysicalIntervalJoin.produceEarlyFireUpdates gates that on three conditions: the hint is set, the join is outer, and the window span is non-negative.
  • A tailored TableException when such a join feeds an insert-only downstream.
  • The compiled-plan round-trip test's sink now declares sink-insert-only=false. Its early-fire outer join produces updates under the new inference, so the previously insert-only sink no longer accepts that pipeline. This is the one existing behavior this PR changes.

Verifying this change

This change added tests and can be verified as follows:

  • EarlyFireJoinHintTest: an early-fire outer join is inferred as changelogMode=[I,UA]; an insert-only downstream fails with the tailored error; a negative-window join and an inner join both stay [I] while still carrying earlyFireDelay on the join node, so the hint is attached but inert rather than absent.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API, i.e., is any changed class annotated with @Public(Evolving): no
  • The serializers: no
  • The runtime per-record code paths (performance sensitive): no
  • Anything that affects deployment or recovery: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? no (planner inference for the FLIP-497 hint)
  • If yes, how is the feature documented? not applicable

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code (Anthropic)

weiqingy and others added 2 commits August 2, 2026 14:51
Add an optional `target` option to the EARLY_FIRE join hint. Only
`interval_join` is accepted today; any other value fails planning. An
omitted target is equivalent to `interval_join`, so existing hints keep
their meaning.

`target` scopes the hint to a single operator kind. The interval-join
rule consumes the hint only when it targets the interval join and leaves
a hint aimed at another operator kind untouched, so an untargeted hint
never silently expands its scope.
…fire interval join

With the EARLY_FIRE hint, an outer interval join speculatively emits a padded
unmatched row after the delay and corrects it when a match later arrives, so it
no longer produces insert-only changes. Teach FlinkChangelogModeInferenceProgram
to reflect this.

Split StreamPhysicalIntervalJoin into its own ModifyKindSet arm: its children
still consume insert-only, but the node provides INSERT and, when the hint makes
it update-producing, UPDATE. A new produceEarlyFireUpdates accessor gates that on
the hint being set, the join being outer, and a non-negative window span, so the
hint stays inert for inner joins and negative-window joins (which only ever emit
inserts). The interval join keeps its place in the UpdateKind and DeleteKind arms.

When such a join feeds an insert-only downstream, planning fails with a tailored
error that names the hint, rather than the generic "doesn't support consuming
update changes" message. Runtime behavior is unchanged; the operator still
ignores the hint.

The compiled-plan round-trip test's sink now declares sink-insert-only=false:
its early-fire outer join produces updates under the new inference, so the
previously insert-only sink no longer accepts the pipeline.
@flinkbot

flinkbot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

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