[ 
https://issues.apache.org/jira/browse/CALCITE-7616?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Mihai Budiu resolved CALCITE-7616.
----------------------------------
    Fix Version/s: 1.43.0
       Resolution: Fixed

Fixed in 
[https://github.com/apache/calcite/commit/7424c0ae3fe4641925460935522fbc8b4600b8fe]

Thank you for the contribution [~leishp] 

> ProjectToLogicalProjectAndWindowRule should only match logical Project nodes
> ----------------------------------------------------------------------------
>
>                 Key: CALCITE-7616
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7616
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.42.0
>            Reporter: leishp
>            Assignee: leishp
>            Priority: Major
>              Labels: pull-request-available
>             Fix For: 1.43.0
>
>
> When a JDBC schema's dialect supports window functions (e.g. MySQL, 
> PostgreSQL), a query with CTE and RANK() throws AssertionError during 
> VolcanoPlanner optimization:
> {code:java}
> AssertionError: Relational expression
>   LogicalWindow.JDBC.TEST.[]
>   has calling-convention JDBC.TEST but does not implement the required 
> interface
>   'interface org.apache.calcite.adapter.jdbc.JdbcRel' of that convention
> {code}
> h3. Reproduction
>   A JDBC schema whose dialect reports {{supportsWindowFunctions() = true}} 
> (e.g. MySQL), and a window query:
>   {code:sql}
>   SELECT empno, RANK() OVER (ORDER BY sal DESC) AS rnk
>   FROM emp
> {code}
> h3. Root cause
> {{ProjectToLogicalProjectAndWindowRule}} passes the parent {{{}Project{}}}'s 
> traitSet directly to {{LogicalWindow.create()}} via {{{}CalcRelSplitter{}}}. 
> When the parent is a {{JdbcProject}} (JDBC convention), the generated 
> {{LogicalWindow}} inherits the JDBC convention but does not implement the 
> {{JdbcRel}} interface, causing an AssertionError in 
> {{{}VolcanoPlanner.registerImpl{}}}.
> {code:java}
> // ProjectToWindowRule.java:161 — passes project.getTraitSet() directly
> final LogicalCalc calc =
>     new LogicalCalc(project.getCluster(), project.getTraitSet(),  // JDBC 
> convention leaks in
>         project.getHints(), input, program);
> {code}
> This is related to CALCITE-3352 (wrong collation on generated Window) — both 
> bugs share the same root cause: {{ProjectToWindowRule}} blindly propagates 
> the parent's traitSet to the generated {{{}LogicalWindow{}}}. Danny Chen 
> commented on CALCITE-3352:
> {quote}We should limit this rule to only match logical nodes because it is a 
> plan rewrite.
> {quote}
> h3. Fix
> Narrow the rule's operand from {{Project.class}} to {{LogicalProject.class}}, 
> so it no longer matches non-logical projects such as {{JdbcProject}}. This 
> rule is a *logical plan rewrite* (it
> emits a {{LogicalWindow}} of Convention.NONE), so it must only apply to 
> logical nodes — exactly as Danny Chen advised on CALCITE-3352. With the 
> operand narrowed, the windowed expression stays
> in {{JdbcProject}} and is pushed down to the database by {{JdbcProjectRule}} 
> when the dialect supports window functions.
> {code:java}
>   // ProjectToWindowRule.java — ProjectToLogicalProjectAndWindowRuleConfig
>   .withOperandSupplier(b ->
>       b.operand(LogicalProject.class)   // was Project.class
>           .predicate(Project::containsOver)
>           .anyInputs())
> {code}
> h3. Impact
>  - When dialect supports window functions: window function is pushed down to 
> database via {{{}JdbcProject{}}}. Correct behavior.
>  - When dialect does NOT support window functions: 
> {{ProjectToLogicalProjectAndWindowRule}} fires on {{LogicalProject(NONE)}} as 
> before. No change.
>  - No existing tests broken (verified {{RelOptRulesTest}} 902/902 passed).
> h3. Scope
> This is a targeted fix for the convention issue only. The collation issue 
> (CALCITE-3352) is tracked separately.
> h3. Test
>   Added {{JdbcAdapterTest#testWindowFunctionJdbcConvention}} plus a nested 
> {{WindowSupportingJdbcSchemaFactory}}, in the *existing* {{JdbcAdapterTest}} 
> (not a new top-level class, to avoid
>   changing the Gradle test-class execution order). It runs against an 
> in-memory HSQLDB with a MySQL dialect override ({{supportsWindowFunctions() = 
> true}}) and asserts the planner no longer
>   throws the "calling-convention" AssertionError.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to