[ 
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.

[]()

 

  was:
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.

[]()

 


> 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.
> []()
>  



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to