Skip to content

Implement the PartiQL “AT” construct for unnesting with ordinality#4112

Merged
RobertBrunel merged 2 commits into
FoundationDB:mainfrom
RobertBrunel:partiql-at
May 15, 2026
Merged

Implement the PartiQL “AT” construct for unnesting with ordinality#4112
RobertBrunel merged 2 commits into
FoundationDB:mainfrom
RobertBrunel:partiql-at

Conversation

@RobertBrunel
Copy link
Copy Markdown
Contributor

@RobertBrunel RobertBrunel commented Apr 24, 2026

This change adds support for the PartiQL AT clause in array unnesting queries. For example, SELECT … FROM T1, T1.array1 AS element AT pos produces a pos field carrying the 1-based ordinal position of each array element. The ordinal has type INTEGER (not BIGINT), aligned with the array subscript operator.

Without AT, the EXPLODE plan operation produces just the array elements as before. When AT is present, it instead produces a struct {element, ordinal} (with anonymous field names) as a DynamicMessage. Downstream FLATMAP and FILTER nodes bind these fields through normal FieldValue accessors (no special-case unwrapping is needed).

Summary of changes:

  1. Parser: Add the optional AT <atAlias> syntax to the atomTableItem rule. Only tableSourceItem can have an AT; other FROM item types reject it with SQLSTATE 42809.
  2. AST transformation: In QueryVisitor#visitAtomTableItem(), extract the AT alias and pass it to LogicalOperator#generateAccess().
  3. Logical plan: In LogicalOperator#generateCorrelatedFieldAccess(), construct an ExplodeExpression with the WITH ORDINALITY flag and build appropriate output attributes for the element/ordinal pair.
  4. Relational expressions: Extend ExplodeExpression as appropriate to incorporate the new withOrdinality field and the element/ordinal result type.
  5. Physical plan nodes: Extend RecordQueryExplodePlan similarly with a withOrdinality boolean, including the proto representation. executePlan() builds DynamicMessage structs with 1-based ordinals when ordinality is requested.
  6. Planner rules: ImplementExplodeRule passes withOrdinality through to the plan.
  7. EXPLAIN output: In ExplainPlanVisitor, add the WITH ORDINALITY keywords to the EXPLODE node to indicate that it produces the element/ordinal pair.

Testing:

  • Integration tests in array-join-at.yamsql.
  • Unit tests for EXPLODE changes in ExplodePlanTest.

Resolves #4117.

@RobertBrunel RobertBrunel requested a review from normen662 April 24, 2026 17:36
@RobertBrunel RobertBrunel self-assigned this Apr 24, 2026
@RobertBrunel RobertBrunel added the enhancement New feature or request label Apr 24, 2026
@RobertBrunel RobertBrunel force-pushed the partiql-at branch 5 times, most recently from 03a0ac3 to d1f39b3 Compare April 27, 2026 16:02
@RobertBrunel RobertBrunel marked this pull request as ready for review April 27, 2026 16:03
@RobertBrunel RobertBrunel requested a review from hatyo April 27, 2026 17:05
@RobertBrunel RobertBrunel force-pushed the partiql-at branch 2 times, most recently from 425709c to a0ab96e Compare May 5, 2026 18:04
This change adds support for the PartiQL `AT` clause in array unnesting queries. For example, `SELECT … FROM T1, T1.array1 AS element AT pos` produces a `pos` field carrying the 1-based ordinal position of each array element. The ordinal has type `INTEGER` (not `BIGINT`), aligned with the array subscript operator.

Without `A`T, the `EXPLODE` plan operation produces just the array elements as before. When `AT` is present, it instead produces a struct {element, ordinal} (with anonymous field names) as a `DynamicMessage`. Downstream `FLATMAP` and `FILTER` nodes bind these fields through normal `FieldValue` accessors (no special-case unwrapping is needed).

Summary of changes:

1. Parser: Add the optional `AT <atAlias>` syntax to the `atomTableItem` rule. Only `tableSourceItem` can have an `AT`; other `FROM` item types reject it with SQLSTATE 42809.
2. AST transformation: In `QueryVisitor#visitAtomTableItem()`, extract the `AT` alias and pass it to `LogicalOperator#generateAccess()`.
3. Logical plan: In `LogicalOperator#generateCorrelatedFieldAccess()`, construct an `ExplodeExpression` with the `WITH ORDINALITY` flag and build appropriate output attributes for the element/ordinal pair.
4. Relational expressions: Extend `ExplodeExpression` as appropriate to incorporate the new `withOrdinality` field and the element/ordinal result type.
5. Physical plan nodes: Extend `RecordQueryExplodePlan` similarly with a `withOrdinality` boolean, including the proto representation. `executePlan()` builds `DynamicMessage` structs with 1-based ordinals when ordinality is requested.
6. Planner rules: `ImplementExplodeRule` passes `withOrdinality` through to the plan.
7. EXPLAIN output: In `ExplainPlanVisitor`, add the `WITH ORDINALITY` keywords to the EXPLODE node to indicate that it produces the element/ordinal pair.

Testing:
* Integration tests in `array-join-at.yamsql`.
* Unit tests for `EXPLODE` changes in `ExplodePlanTest`.

Resolves FoundationDB#4117.
@github-actions
Copy link
Copy Markdown

📊 Metrics Diff Analysis Report

Summary

  • New queries: 15
  • Dropped queries: 0
  • Plan changed + metrics changed: 0
  • Plan unchanged + metrics changed: 0
ℹ️ About this analysis

This automated analysis compares query planner metrics between the base branch and this PR. It categorizes changes into:

  • New queries: Queries added in this PR
  • Dropped queries: Queries removed in this PR. These should be reviewed to ensure we are not losing coverage.
  • Plan changed + metrics changed: The query plan has changed along with planner metrics.
  • Metrics only changed: Same plan but different metrics

The last category in particular may indicate planner regressions that should be investigated.

New Queries

Count of new queries by file:

  • yaml-tests/src/test/resources/array-join-at.metrics.yaml: 15

@RobertBrunel RobertBrunel dismissed normen662’s stale review May 15, 2026 13:09

Addressed the requested changes.

@RobertBrunel RobertBrunel merged commit 3474171 into FoundationDB:main May 15, 2026
14 checks passed
@RobertBrunel RobertBrunel deleted the partiql-at branch May 15, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for unnesting with ordinality

3 participants