Anton Kovalevsky created CALCITE-6804:
-----------------------------------------
Summary: Anti-join with WHERE NOT EXISTS syntax has corrupted
condition
Key: CALCITE-6804
URL: https://issues.apache.org/jira/browse/CALCITE-6804
Project: Calcite
Issue Type: Bug
Reporter: Anton Kovalevsky
Queries like:
{code:sql}
SELECT * FROM
(
SELECT field1 FROM table1 JOIN table2 ON table1.field1 = table2.field2
) selected
WHERE NOT EXISTS (select 1 from table3 where table3.field3 = selected.field1)
{code}
are being converted into
{code:sql}
SELECT * FROM
(
SELECT field1 FROM table1 JOIN table2 ON table1.field1 = table2.field2
) selected
WHERE NOT EXISTS (select 1 from table3 where table3.field3 =
table2.<random_field>)
{code}
Example I added to RelToSqlConverterTest
{code:java}
@Test void testAntiJoinWithWhereNotExists() {
final String sql = "SELECT * FROM (select * from (select
e1.\"product_id\"\n"
+ "FROM \"foodmart\".\"product\" e1 LEFT JOIN \"foodmart\".\"product\"
e3 on e1.\"product_id\" = e3.\"product_id\") s where true) selected where not
exists\n"
+ "(select 1 from \"foodmart\".\"product\" e2 where e2.\"product_id\" =
selected.\"product_id\")";
final String expected = "SELECT *\n" +
"FROM (SELECT \"product\".\"product_id\"\n" +
"FROM \"foodmart\".\"product\"\n" +
"LEFT JOIN \"foodmart\".\"product\" AS \"product0\" ON
\"product\".\"product_id\" = \"product0\".\"product_id\"" +
") AS \"t\"\n" +
"WHERE EXISTS (SELECT *\nFROM \"foodmart\".\"product\"\nWHERE
\"product_id\" = \"t\".\"product_class_id\")"
;
sql(sql).ok(expected);
}
{code}
{code:java}
Expected: is "SELECT ...) AS \"t\"\nWHERE EXISTS (... WHERE \"product_id\" =
\"t\".\"product_id\")"
but: was "SELECT ...) AS \"t\"\nWHERE EXISTS (... WHERE \"product_id\" =
\"product1\".\"product_class_id\")"
{code}
*product1* is generated alias for a query from one of sub-queries, and
*product_class_id* is a field from that misused table scan.
My high level understanding is that query with WHERE NOT EXISTS syntax is
considered as LogicalFilter and appropriate pieces of code (like
*AliasReplacementShuttle* and {*}visitAntiOrSemiJoin{*}) are not invoked.
And visit of Filter node builds alias context inappropriately.
Directions I am trying:
- Duplicate antiJoin visit under the scope of filter visit.
- Explicit rule to convert Filter to Join manually. Feels artificial because
it planner should be triggered, it requires a convention.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)