Yuzhao Chen created CALCITE-2638: ------------------------------------ Summary: Should not do constant reduction when dynamic function is as inputRef in project Key: CALCITE-2638 URL: https://issues.apache.org/jira/browse/CALCITE-2638 Project: Calcite Issue Type: Bug Components: core Affects Versions: 1.17.0 Reporter: Yuzhao Chen Assignee: Julian Hyde Fix For: 1.18.0
When we have a dynamic function like `current_timestamp` in the query, calcite will skip constant reduction, for example, for query1: ```sql select sal, current_timestamp as t from emp ``` The plan after rule `ReduceExpressionsRule.PROJECT_INSTANCE` is ```diff LogicalProject(SAL=[$5], T=[CURRENT_TIMESTAMP]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ``` This is as expect cause there is such code snippet in `ReducibleExprLocator#visitCall`: ```java // Even if all operands are constant, the call itself may // be non-deterministic. if (!call.getOperator().isDeterministic()) { callConstancy = Constancy.NON_CONSTANT; } else if (call.getOperator().isDynamicFunction()) { // We can reduce the call to a constant, but we can't // cache the plan if the function is dynamic. // For now, treat it same as non-deterministic. callConstancy = Constancy.NON_CONSTANT; } ``` But for query2: ```sql select sal, sal + 5, t from (select sal, current_timestamp as t from emp) ``` we will get a plan with rule `ReduceExpressionsRule.PROJECT_INSTANCE` as: ```diff + plan before LogicalProject(SAL=[$0], EXPR$1=[+($0, 5)], T=[$1]) LogicalProject(SAL=[$5], T=[CURRENT_TIMESTAMP]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + plan after LogicalProject(SAL=[$0], EXPR$1=[+($0, 5)], T=[CURRENT_TIMESTAMP]) LogicalProject(SAL=[$5], T=[CURRENT_TIMESTAMP]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ``` This is actually wrong cause `current_timestamp` is dynamic and we do not want to compute it again in the outer project. The reason we did constant reduction now is that: for query2, we will get a pulled up predicates with tool function `RexUtil.isConstant`, this function decide if the call is constant by invoking `SqlOperator#isDeterministic` which is default true here. It did not do the `isDynamicFunction()` decision just like `ReducibleExprLocator` and the reduction finally happened which handle by `RexExecutor`. Personally i think we should keep sync in reduction logic for `inputRef` and `RexCall` and i reuse the `analyzeCall` and apply a patch here. []() -- This message was sent by Atlassian JIRA (v7.6.3#76005)