[Fix](Nereids) fold constant result is wrong on functions relative to timezone (#19863)
This commit is contained in:
@ -328,10 +328,6 @@ public class FoldConstantRuleOnFE extends AbstractExpressionRewriteRule {
|
||||
@Override
|
||||
public Expression visitBoundFunction(BoundFunction boundFunction, ExpressionRewriteContext context) {
|
||||
boundFunction = rewriteChildren(boundFunction, context);
|
||||
//functions, like current_date, do not have arg
|
||||
if (boundFunction.getArguments().isEmpty()) {
|
||||
return boundFunction;
|
||||
}
|
||||
Optional<Expression> checkedExpr = preProcess(boundFunction);
|
||||
if (checkedExpr.isPresent()) {
|
||||
return checkedExpr.get();
|
||||
|
||||
@ -20,6 +20,7 @@ package org.apache.doris.nereids.trees.expressions;
|
||||
import org.apache.doris.nereids.analyzer.Unbound;
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.nereids.trees.AbstractTreeNode;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.Literal;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
|
||||
@ -139,6 +140,10 @@ public abstract class Expression extends AbstractTreeNode<Expression> implements
|
||||
*/
|
||||
public boolean isConstant() {
|
||||
if (this instanceof LeafExpression) {
|
||||
if (this instanceof BoundFunction) {
|
||||
BoundFunction function = ((BoundFunction) this);
|
||||
return function instanceof Foldable;
|
||||
}
|
||||
return this instanceof Literal;
|
||||
} else {
|
||||
return children().stream().allMatch(Expression::isConstant);
|
||||
|
||||
@ -137,11 +137,11 @@ public enum ExpressionEvaluator {
|
||||
ImmutableMultimap.Builder<String, FunctionInvoker> mapBuilder =
|
||||
new ImmutableMultimap.Builder<String, FunctionInvoker>();
|
||||
List<Class> classes = ImmutableList.of(
|
||||
DateTimeAcquire.class,
|
||||
DateTimeExtractAndTransform.class,
|
||||
ExecutableFunctions.class,
|
||||
DateLiteral.class,
|
||||
DateTimeArithmetic.class,
|
||||
DateTimeAcquire.class,
|
||||
NumericArithmetic.class
|
||||
);
|
||||
for (Class cls : classes) {
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
/**
|
||||
* specifically for bound function can be folded to constant.
|
||||
*/
|
||||
public interface Foldable {
|
||||
}
|
||||
@ -23,9 +23,10 @@ import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
|
||||
import org.apache.doris.nereids.util.DateUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.TimeZone;
|
||||
import java.time.ZoneId;
|
||||
|
||||
/**
|
||||
* executable functions:
|
||||
@ -37,12 +38,12 @@ public class DateTimeAcquire {
|
||||
*/
|
||||
@ExecFunction(name = "now", argTypes = {}, returnType = "DATETIME")
|
||||
public static Expression now() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
@ExecFunction(name = "now", argTypes = {"INT"}, returnType = "DATETIMEV2")
|
||||
public static Expression now(IntegerLiteral precision) {
|
||||
return DateTimeV2Literal.fromJavaDateType(LocalDateTime.now(),
|
||||
return DateTimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()),
|
||||
precision.getValue());
|
||||
}
|
||||
|
||||
@ -51,12 +52,12 @@ public class DateTimeAcquire {
|
||||
*/
|
||||
@ExecFunction(name = "current_timestamp", argTypes = {}, returnType = "DATETIME")
|
||||
public static Expression currentTimestamp() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
@ExecFunction(name = "current_timestamp", argTypes = {"INT"}, returnType = "DATETIMEV2")
|
||||
public static Expression currentTimestamp(IntegerLiteral precision) {
|
||||
return DateTimeV2Literal.fromJavaDateType(LocalDateTime.now(), precision.getValue());
|
||||
return DateTimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()), precision.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,12 +65,12 @@ public class DateTimeAcquire {
|
||||
*/
|
||||
@ExecFunction(name = "localtime", argTypes = {}, returnType = "DATETIME")
|
||||
public static Expression localTime() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(TimeZone.getDefault().toZoneId()));
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
@ExecFunction(name = "localtimestamp", argTypes = {}, returnType = "DATETIME")
|
||||
public static Expression localTimestamp() {
|
||||
return DateTimeV2Literal.fromJavaDateType(LocalDateTime.now(TimeZone.getDefault().toZoneId()));
|
||||
return DateTimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,12 +78,12 @@ public class DateTimeAcquire {
|
||||
*/
|
||||
@ExecFunction(name = "curdate", argTypes = {}, returnType = "DATE")
|
||||
public static Expression curDate() {
|
||||
return DateLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
return DateLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
@ExecFunction(name = "current_date", argTypes = {}, returnType = "DATE")
|
||||
public static Expression currentDate() {
|
||||
return DateLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
return DateLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,11 +91,27 @@ public class DateTimeAcquire {
|
||||
*/
|
||||
@ExecFunction(name = "curtime", argTypes = {}, returnType = "DATETIME")
|
||||
public static Expression curTime() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
@ExecFunction(name = "current_time", argTypes = {}, returnType = "DATETIME")
|
||||
public static Expression currentTime() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
|
||||
}
|
||||
|
||||
/**
|
||||
* date transformation function: unix_timestamp
|
||||
*/
|
||||
@ExecFunction(name = "unix_timestamp", argTypes = {}, returnType = "INT")
|
||||
public static Expression unixTimestamp() {
|
||||
return new IntegerLiteral((int) (System.currentTimeMillis() / 1000L));
|
||||
}
|
||||
|
||||
/**
|
||||
* date transformation function: utc_timestamp
|
||||
*/
|
||||
@ExecFunction(name = "utc_timestamp", argTypes = {}, returnType = "INT")
|
||||
public static Expression utcTimestamp() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(ZoneId.of("UTC+0")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,20 +448,12 @@ public class DateTimeExtractAndTransform {
|
||||
.plusSeconds(second.getValue())
|
||||
.atZone(ZoneId.of("UTC+0"))
|
||||
.toOffsetDateTime()
|
||||
.atZoneSameInstant(ZoneId.systemDefault());
|
||||
.atZoneSameInstant(DateUtils.getTimeZone());
|
||||
return dateFormat(new DateTimeLiteral(dateTime.getYear(), dateTime.getMonthValue(),
|
||||
dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond()),
|
||||
format);
|
||||
}
|
||||
|
||||
/**
|
||||
* date transformation function: unix_timestamp
|
||||
*/
|
||||
@ExecFunction(name = "unix_timestamp", argTypes = {}, returnType = "INT")
|
||||
public static Expression unixTimestamp() {
|
||||
return new IntegerLiteral(getTimestamp(LocalDateTime.now()));
|
||||
}
|
||||
|
||||
/**
|
||||
* date transformation function: unix_timestamp
|
||||
*/
|
||||
@ -509,18 +501,9 @@ public class DateTimeExtractAndTransform {
|
||||
}
|
||||
return ((int) Duration.between(
|
||||
specialLowerBound,
|
||||
dateTime
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toOffsetDateTime().atZoneSameInstant(ZoneId.of("UTC+0"))
|
||||
.toLocalDateTime()).getSeconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* date transformation function: utc_timestamp
|
||||
*/
|
||||
@ExecFunction(name = "utc_timestamp", argTypes = {}, returnType = "INT")
|
||||
public static Expression utcTimestamp() {
|
||||
return DateTimeLiteral.fromJavaDateType(LocalDateTime.now());
|
||||
dateTime.atZone(DateUtils.getTimeZone())
|
||||
.toOffsetDateTime().atZoneSameInstant(ZoneId.of("UTC+0"))
|
||||
.toLocalDateTime()).getSeconds());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.apache.doris.nereids.trees.expressions.functions.scalar;
|
||||
|
||||
import org.apache.doris.catalog.FunctionSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.Foldable;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.Nondeterministic;
|
||||
@ -33,7 +34,7 @@ import java.util.List;
|
||||
* ScalarFunction 'current_date'. This class is generated by GenerateFunction.
|
||||
*/
|
||||
public class CurrentDate extends ScalarFunction
|
||||
implements LeafExpression, ExplicitlyCastableSignature, Nondeterministic, AlwaysNotNullable {
|
||||
implements LeafExpression, ExplicitlyCastableSignature, Nondeterministic, AlwaysNotNullable, Foldable {
|
||||
|
||||
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
|
||||
FunctionSignature.ret(DateType.INSTANCE).args()
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.apache.doris.nereids.trees.expressions.functions.scalar;
|
||||
|
||||
import org.apache.doris.catalog.FunctionSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.Foldable;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.Nondeterministic;
|
||||
@ -33,7 +34,7 @@ import java.util.List;
|
||||
* ScalarFunction 'current_time'. This class is generated by GenerateFunction.
|
||||
*/
|
||||
public class CurrentTime extends ScalarFunction
|
||||
implements LeafExpression, ExplicitlyCastableSignature, Nondeterministic, AlwaysNotNullable {
|
||||
implements LeafExpression, ExplicitlyCastableSignature, Nondeterministic, AlwaysNotNullable, Foldable {
|
||||
|
||||
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
|
||||
FunctionSignature.ret(TimeType.INSTANCE).args()
|
||||
|
||||
@ -18,8 +18,10 @@
|
||||
package org.apache.doris.nereids.util;
|
||||
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.TextStyle;
|
||||
@ -163,4 +165,11 @@ public class DateUtils {
|
||||
public static int getOrDefault(final TemporalAccessor accessor, final ChronoField field) {
|
||||
return accessor.isSupported(field) ? accessor.get(field) : /*default value*/ 0;
|
||||
}
|
||||
|
||||
public static ZoneId getTimeZone() {
|
||||
if (ConnectContext.get() == null || ConnectContext.get().getSessionVariable() == null) {
|
||||
return ZoneId.systemDefault();
|
||||
}
|
||||
return ZoneId.of(ConnectContext.get().getSessionVariable().getTimeZone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
suite("test_date_acquire") {
|
||||
sql 'set enable_nereids_planner=true'
|
||||
sql 'set enable_fallback_to_original_planner=false'
|
||||
|
||||
String res = sql 'explain select now(), now(3), curdate(), current_date(), curtime(), current_time(), current_timestamp(), current_timestamp(3)'
|
||||
res = res.split('VUNION')[1]
|
||||
assertFalse(res.contains("()") || res.contains("(3)"))
|
||||
|
||||
sql "set enable_fold_constant_by_be=true"
|
||||
|
||||
test {
|
||||
sql "select from_unixtime(1553152255), unix_timestamp('2007-11-30 10:30%3A19', '%Y-%m-%d %H:%i%%3A%s')"
|
||||
result([['2019-03-21 15:10:55', 1196389819]])
|
||||
}
|
||||
|
||||
sql "set time_zone='+00:00'"
|
||||
|
||||
test {
|
||||
sql "select from_unixtime(1553152255), unix_timestamp('2007-11-30 10:30%3A19', '%Y-%m-%d %H:%i%%3A%s')"
|
||||
result([['2019-03-21 07:10:55', 1196418619]])
|
||||
}
|
||||
|
||||
sql "set time_zone='+04:00'"
|
||||
|
||||
test {
|
||||
sql "select from_unixtime(1553152255), unix_timestamp('2007-11-30 10:30%3A19', '%Y-%m-%d %H:%i%%3A%s')"
|
||||
result([['2019-03-21 11:10:55', 1196404219]])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user