Skip to content

Conversation

@sergei-pustovykh
Copy link
Contributor

@sergei-pustovykh sergei-pustovykh commented Dec 9, 2025

Support of INNER JOIN syntax

This PR introduces the standard syntax for INNER JOIN operation.

Simple case

The requests like
SELECT t1.a, t2.b FROM t1 INNER JOIN t2 ON t1.id = t2.id
are executed the same as
SELECT t1.a, t2.b FROM t1, t2 WHERE t1.id = t2.id

Base case

SELECT select-expr FROM t1 INNER JOIN t2 ON join-expr1 INNER JOIN t3 ON join-expr2 INNER JOIN t4 ON join-expr3 WHERE where-expr
works the same as
SELECT select-expr FROM t1, t2, t3, t4 WHERE where-expr AND join-expr1 AND join-expr2 AND join-expr3

@sergei-pustovykh sergei-pustovykh added enhancement New feature or request and removed enhancement New feature or request Draft labels Dec 10, 2025
@sergei-pustovykh sergei-pustovykh marked this pull request as ready for review December 15, 2025 14:57
Copy link
Contributor

@hatyo hatyo left a comment

Choose a reason for hiding this comment

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

Nice work, and congrats on your first PR. Few minor comments and we can bring it in.

return Assert.castUnchecked(ctx.tableSourceItem().accept(this), LogicalOperator.class);
public Expression visitInnerJoin(@Nonnull RelationalParser.InnerJoinContext ctx) {
getDelegate().getCurrentPlanFragment().addOperator(Assert.castUnchecked(ctx.tableSourceItem().accept(this), LogicalOperator.class));
return Assert.castUnchecked(ctx.expression().accept(this), Expression.class);
Copy link
Contributor

Choose a reason for hiding this comment

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

This assumes that the user always provides an expression, in other words, they always use the syntax on expression, however if they mistakenly use the USING syntax instead, which is permissible as per the grammar rule:

(INNER | CROSS)? JOIN tableSourceItem
      (
        ON expression
        | USING '(' uidList ')'  // <<< on OR using
      )?                                                            #innerJoin

then we get an NPE here (because ctx.expression() is null). It would be better if we catch this case and throw a proper SQLException with ErrorCode.UNSUPPORTED_QUERY.

Copy link
Contributor Author

@sergei-pustovykh sergei-pustovykh Dec 18, 2025

Choose a reason for hiding this comment

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

Added exception using is not yet supported for inner join and test case.
But it looks like a good time to implement using syntax properly and close the inner join case.

Assert.thatUnchecked(ctx.joinPart().isEmpty(), "explicit join types are not supported");
return Assert.castUnchecked(ctx.tableSourceItem().accept(this), LogicalOperator.class);
public Expression visitInnerJoin(@Nonnull RelationalParser.InnerJoinContext ctx) {
getDelegate().getCurrentPlanFragment().addOperator(Assert.castUnchecked(ctx.tableSourceItem().accept(this), LogicalOperator.class));
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to handle all the interactions with current plan fragment here? instead of visitableTableSourceBase?

i.e. when calling vistInnerJoin we add both the tableSourceItem and expression to the current plan fragment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

make sense!
Addressed

Copy link
Contributor

@hatyo hatyo left a comment

Choose a reason for hiding this comment

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

LGTM.

@sergei-pustovykh sergei-pustovykh merged commit 3e0a127 into FoundationDB:main Dec 19, 2025
8 checks passed
@sergei-pustovykh sergei-pustovykh deleted the inner_join branch December 19, 2025 15: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.

2 participants