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

Mihai Budiu resolved CALCITE-7191.
----------------------------------
    Fix Version/s: 1.41.0
         Assignee: Mihai Budiu
       Resolution: Fixed

Fixed in 
https://github.com/apache/calcite/commit/8fb5696cd5e5033d4fa2b8e8dd602562669ebfa0
Thank you to [~gnirmal] for providing the report, the fix, the test cases, and 
the review
Thank you to [~dongsl] and [~asolimando] for the reviews


> Hypergraph creation with incorrect hyperedges
> ---------------------------------------------
>
>                 Key: CALCITE-7191
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7191
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.41.0
>            Reporter: Nirmal Govindaraj
>            Assignee: Mihai Budiu
>            Priority: Major
>              Labels: pull-request-available
>             Fix For: 1.41.0
>
>
> This is about the JOIN_TO_HYPERGRAPH rule introduced in CALCITE-6846
> When I tested the following query in RelOptRulesTest.java I encountered an 
> assertion error in the planAfter stage where HYPER_GRAPH_OPTIMIZE gets 
> executed 
>  
> {code:java}
> HepProgram program = new 
> HepProgramBuilder().addMatchOrder(HepMatchOrder.BOTTOM_UP)
>     .addRuleInstance(CoreRules.JOIN_PROJECT_RIGHT_TRANSPOSE)
>     .addRuleInstance(CoreRules.JOIN_PROJECT_LEFT_TRANSPOSE)
>     .addRuleInstance(CoreRules.PROJECT_MERGE)
>     .addRuleInstance(CoreRules.PROJECT_REMOVE)
>     .addRuleInstance(CoreRules.JOIN_TO_HYPER_GRAPH)
>     .build();
> String innerJoinSql = "select a.ename, bc.name from bonus a inner join 
> (select b.empno, b.ename, c.name from emp b inner join dept c on b.deptno = 
> c.deptno) bc on a.ename = bc.ename";
> sql(innerJoinSql).withPre(program)
>     .withRule(CoreRules.HYPER_GRAPH_OPTIMIZE, CoreRules.PROJECT_MERGE)
>     .check();{code}
> {code:java}
> java.lang.AssertionError      at 
> org.apache.calcite.rel.rules.HyperGraph$1.visitNodeAndFieldIndex(HyperGraph.java:437)
>         at 
> org.apache.calcite.rel.rules.HyperGraph$1.visitNodeAndFieldIndex(HyperGraph.java:432)
>         at 
> org.apache.calcite.rex.RexNodeAndFieldIndex.accept(RexNodeAndFieldIndex.java:78)
>      at org.apache.calcite.rex.RexShuttle.visitList(RexShuttle.java:167)     
> at org.apache.calcite.rex.RexShuttle.visitCall(RexShuttle.java:119)     at 
> org.apache.calcite.rex.RexShuttle.visitCall(RexShuttle.java:38)      at 
> org.apache.calcite.rex.RexCall.accept(RexCall.java:208)      at 
> org.apache.calcite.rel.rules.HyperGraph.extractJoinCond(HyperGraph.java:443) 
> {code}
> On debugging further I noticed that the edges were not correct in the 
> hypergraph it created
> {code:java}
> HyperGraph(edges=[{0}——[INNER, =(node(0)_field(0), 
> node(1)_field(1))]——{1},{1}——[INNER, =(node(0)_field(7), 
> node(2)_field(0))]——{2}])
>   LogicalTableScan(table=[[CATALOG, SALES, BONUS]]) -- nodeIndex 0
>   LogicalTableScan(table=[[CATALOG, SALES, EMP]]) -- nodeIndex 1
>   LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) -- nodeIndex 2
>  {code}
> The second edge should be from EMP table so node(1)_field(7), 
> node(2)_field(0). On debugging the JOIN_TO_HYPERGRAPH rule I found that the 
> issue was in the adjustNodeBit method of HyperEdge.java. Essentially what 
> happens is that when we reach the BONUS inner join we have a Hypergraph on 
> EMP and DEPT on the right side of the tree so the node indices of the 
> hyperedges need to be shifted by 1
> {code:java}
> public HyperEdge adjustNodeBit(int nodeOffset) {
>   RexShuttle shiftNodeIndexShuttle = new RexShuttle() {
>     @Override public RexNode visitNodeAndFieldIndex(RexNodeAndFieldIndex 
> nodeAndFieldIndex) {
>       return new RexNodeAndFieldIndex(
>           nodeAndFieldIndex.getNodeIndex() << nodeOffset,
>           nodeAndFieldIndex.getFieldIndex(),
>           nodeAndFieldIndex.getName(),
>           nodeAndFieldIndex.getType());
>     }
>   };
>   RexNode shiftedCondition = condition.accept(shiftNodeIndexShuttle);
>   List<ConflictRule> shiftedConflictRules = new ArrayList<>();
>   for (ConflictRule conflictRule : conflictRules) {
>     shiftedConflictRules.add(conflictRule.shift(nodeOffset));
>   }
>   return new HyperEdge(
>       tes.shift(nodeOffset),
>       shiftedConflictRules,
>       leftNodeUsedInPredicate << nodeOffset,
>       rightNodeUsedInPredicate << nodeOffset,
>       initialLeftNodeBits << nodeOffset,
>       initialRightNodeBits << nodeOffset,
>       joinType,
>       shiftedCondition);
> } {code}
> But in the code it does a leftshift by 1 instead 
> (nodeAndFieldIndex.getNodeIndex() << nodeOffset in shiftNodeIndexShuttle). So 
> the hyperedge between EMP and DEPT which was originally between node 0 and 
> node 1 turns into node 0 and node 2
>  
> Changing the code to nodeAndFieldIndex.getNodeIndex() + nodeOffset in 
> shiftNodeIndexShuttle fixes the issue
>  
>  
>  



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

Reply via email to