[
https://issues.apache.org/jira/browse/CALCITE-2638?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Yuzhao Chen updated CALCITE-2638:
---------------------------------
Description:
When we have a dynamic function like
{code:java}
current_timestamp
{code}
in the query, calcite will skip constant reduction, for example, for query1:
{code:java}
select sal, current_timestamp as t from emp{code}
The plan after rule `ReduceExpressionsRule.PROJECT_INSTANCE` is
{code:java}
LogicalProject(SAL=[$5], T=[CURRENT_TIMESTAMP])
LogicalTableScan(table=[[CATALOG, SALES, EMP]]){code}
This is as expect cause there is such code snippet in
`ReducibleExprLocator#visitCall`:
{code: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;
}{code}
But for query2:
{code:java}
select sal, sal + 5, t from (select sal, current_timestamp as t from emp) {code}
we will get a plan with rule `ReduceExpressionsRule.PROJECT_INSTANCE` as:
{code:java}
+ 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]])
{code}
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 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.
[pull-request](https://github.com/apache/calcite/pull/892)
was:
When we have a dynamic function like
{code:java}
current_timestamp
{code}
in the query, calcite will skip constant reduction, for example, for query1:
{code:java}
select sal, current_timestamp as t from emp{code}
The plan after rule `ReduceExpressionsRule.PROJECT_INSTANCE` is
{code:java}
LogicalProject(SAL=[$5], T=[CURRENT_TIMESTAMP])
LogicalTableScan(table=[[CATALOG, SALES, EMP]]){code}
This is as expect cause there is such code snippet in
`ReducibleExprLocator#visitCall`:
{code: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;
}{code}
But for query2:
{code:java}
select sal, sal + 5, t from (select sal, current_timestamp as t from emp){code}
we will get a plan with rule `ReduceExpressionsRule.PROJECT_INSTANCE` as:
{code:java}
+ 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]])
{code}
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 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.
[]()
> 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
> Priority: Major
> Fix For: 1.18.0
>
>
> When we have a dynamic function like
> {code:java}
> current_timestamp
> {code}
> in the query, calcite will skip constant reduction, for example, for query1:
> {code:java}
> select sal, current_timestamp as t from emp{code}
> The plan after rule `ReduceExpressionsRule.PROJECT_INSTANCE` is
> {code:java}
> LogicalProject(SAL=[$5], T=[CURRENT_TIMESTAMP])
> LogicalTableScan(table=[[CATALOG, SALES, EMP]]){code}
> This is as expect cause there is such code snippet in
> `ReducibleExprLocator#visitCall`:
> {code: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;
> }{code}
> But for query2:
> {code:java}
> select sal, sal + 5, t from (select sal, current_timestamp as t from emp)
> {code}
> we will get a plan with rule `ReduceExpressionsRule.PROJECT_INSTANCE` as:
> {code:java}
> + 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]])
> {code}
> 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 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.
> [pull-request](https://github.com/apache/calcite/pull/892)
>
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)