You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Join.validate() in sql/src/main/scala/app/softnetwork/elastic/sql/query/From.scala
unconditionally rejects any join whose joined table has no explicit alias,
even when the join condition correctly qualifies columns by the table name
itself. Standard SQL does not require an alias on joined tables — the bare
table name is a valid qualifier.
Repro
-- Fails: "JOIN JOIN customers ON orders.customer_id = customers.id requires an alias"SELECT*FROM orders
LEFT JOIN customers ONorders.customer_id=customers.id;
-- Works: alias `c` is purely decorativeSELECT*FROM orders
LEFT JOIN customers c ONorders.customer_id=c.id;
The first form is accepted by PostgreSQL, MySQL, DuckDB, ClickHouse, SQL
Server, and the SQL-2003 standard. The bare table name customers is a
valid qualifier in ON / WHERE / SELECT.
Root cause
overridedefvalidate():Either[String, Unit] =for {
_ <- source.validate()
_ <- alias match {
caseSome(a) if a.alias.nonEmpty =>Right(())
case _ =>Left(s"JOIN $this requires an alias")
}
_ <-thismatch {
case j if joinType.isDefined && on.isEmpty && joinType.get !=CrossJoin=>Left(s"JOIN $j requires an ON clause")
case j if alias.isEmpty =>Left(s"JOIN $j requires an alias")
case _ =>Right(())
}
} yield ()
Two separate code paths reject the missing alias (lines 170–173 and
lines 177–178). Neither path is conditional on whether the ON/WHERE
clause actually depends on an alias.
Impact
Direct queries hand-written by users fail with a confusing "requires an
alias" error that the SQL standard does not impose.
Round-trip SQL from any external generator (BI tools, ORMs, DuckDB
rewrites, JDBC drivers) that emits alias-less joins breaks at parse
time.
Discovered while writing the ParserSpec coverage for Parser: accept the OUTER keyword in LEFT/RIGHT/FULL OUTER JOIN #94 (optional
OUTER keyword): the natural test SQL LEFT JOIN customers ON ...
failed not because of the OUTER work, but because the alias was
missing.
Proposed fix
Two options, ranked by safety:
Drop the alias requirement entirely. Alias was always optional in
SQL; the table name itself is a valid qualifier. Internally, anywhere tableAlias is used as a key, fall back to the table name when no
alias was given (some codepaths already do this — e.g. the MV graph
builder's tableAliases.getOrElse(tableName, tableName)).
Reject only when the ON / WHERE / SELECT actually references
an undefined alias. Keeps the safety net, but only fires when a
qualifier in the query cannot be resolved against either an alias or
a table name. More conservative but more complex.
Option 1 mirrors how every mainstream SQL engine behaves and aligns with
how the MV graph builder already treats missing aliases.
Acceptance criteria
SELECT * FROM orders LEFT JOIN customers ON orders.customer_id = customers.id
parses and validates.
Existing tests using explicit aliases continue to pass — the alias
stays optional.
Where downstream code keys off tableAlias, the table name is
used as a fallback.
New ParserSpec cases for alias-less INNER / LEFT / RIGHT / FULL JOIN.
Summary
Join.validate()insql/src/main/scala/app/softnetwork/elastic/sql/query/From.scalaunconditionally rejects any join whose joined table has no explicit alias,
even when the join condition correctly qualifies columns by the table name
itself. Standard SQL does not require an alias on joined tables — the bare
table name is a valid qualifier.
Repro
The first form is accepted by PostgreSQL, MySQL, DuckDB, ClickHouse, SQL
Server, and the SQL-2003 standard. The bare table name
customersis avalid qualifier in
ON/WHERE/SELECT.Root cause
Two separate code paths reject the missing alias (lines 170–173 and
lines 177–178). Neither path is conditional on whether the
ON/WHEREclause actually depends on an alias.
Impact
alias" error that the SQL standard does not impose.
rewrites, JDBC drivers) that emits alias-less joins breaks at parse
time.
OUTER keyword): the natural test SQL
LEFT JOIN customers ON ...failed not because of the OUTER work, but because the alias was
missing.
Proposed fix
Two options, ranked by safety:
Drop the alias requirement entirely. Alias was always optional in
SQL; the table name itself is a valid qualifier. Internally, anywhere
tableAliasis used as a key, fall back to the table name when noalias was given (some codepaths already do this — e.g. the MV graph
builder's
tableAliases.getOrElse(tableName, tableName)).Reject only when the
ON/WHERE/SELECTactually referencesan undefined alias. Keeps the safety net, but only fires when a
qualifier in the query cannot be resolved against either an alias or
a table name. More conservative but more complex.
Option 1 mirrors how every mainstream SQL engine behaves and aligns with
how the MV graph builder already treats missing aliases.
Acceptance criteria
SELECT * FROM orders LEFT JOIN customers ON orders.customer_id = customers.idparses and validates.
stays optional.
tableAlias, the table name isused as a fallback.
Related
missing aliases by falling back to table name.