[Enhancement](function) support unix_timestamp with float (#26827)

---------

Co-authored-by: YangWithU <plzw8@outlook.com>
This commit is contained in:
zclllyybb
2023-11-27 09:58:53 +08:00
committed by GitHub
parent 3791de3cfa
commit baadc14e60
19 changed files with 505 additions and 111 deletions

View File

@ -30,6 +30,7 @@ import org.apache.doris.catalog.Function;
import org.apache.doris.catalog.FunctionSet;
import org.apache.doris.catalog.FunctionUtil;
import org.apache.doris.catalog.MapType;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.catalog.ScalarFunction;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.catalog.StructField;
@ -1681,6 +1682,27 @@ public class FunctionCallExpr extends Expr {
children.set(1, new StringLiteral("%Y-%m-%d %H:%i:%s"));
}
}
if (fnName.getFunction().equalsIgnoreCase("unix_timestamp") && children.size() == 1) {
if (getChild(0).type.isDatetimeV2()) {
ScalarType type = (ScalarType) getChild(0).type;
Preconditions.checkArgument(type.getScalarScale() <= 6,
"DatetimeV2's scale shouldn't exceed 6 but meet " + type.getScalarScale());
fn.setReturnType(
ScalarType.createDecimalType(PrimitiveType.DECIMAL64, 10 + type.getScalarScale(),
type.getScalarScale()));
} else if (getChild(0).type.isStringType()) {
// use DATETIME to make scale adaptive
ScalarType type = ((ScalarType) (((StringLiteral) getChild(0))
.uncheckedCastTo(ScalarType.DATETIME).type));
if (type.isDatetimeV2()) {
int scale = ((ScalarType) (((StringLiteral) getChild(0))
.uncheckedCastTo(ScalarType.DATETIME).type)).getScalarScale();
fn.setReturnType(
ScalarType.createDecimalType(PrimitiveType.DECIMAL64, 10 + scale, scale));
}
}
}
}
if (fnName.getFunction().equalsIgnoreCase("convert_to")) {
if (children.size() < 2 || !getChild(1).isConstant()) {

View File

@ -25,14 +25,17 @@ 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.DateV2Literal;
import org.apache.doris.nereids.trees.expressions.literal.DecimalV3Literal;
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.VarcharType;
import org.apache.doris.nereids.util.DateUtils;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -494,9 +497,19 @@ public class DateTimeExtractAndTransform {
return new IntegerLiteral(getTimestamp(date.toJavaDateType()));
}
@ExecFunction(name = "unix_timestamp", argTypes = {"DATETIMEV2"}, returnType = "INT")
/**
* date transformation function: unix_timestamp
*/
@ExecFunction(name = "unix_timestamp", argTypes = { "DATETIMEV2" }, returnType = "DECIMALV3")
public static Expression unixTimestamp(DateTimeV2Literal date) {
return new IntegerLiteral(getTimestamp(date.toJavaDateType()));
if (date.getMicroSecond() == 0) {
return new DecimalV3Literal(DecimalV3Type.createDecimalV3TypeLooseCheck(10, 0),
new BigDecimal(getTimestamp(date.toJavaDateType()).toString()));
}
int scale = date.getDataType().getScale();
String val = getTimestamp(date.toJavaDateType()).toString() + "." + date.getMicrosecondString();
return new DecimalV3Literal(DecimalV3Type.createDecimalV3TypeLooseCheck(10 + scale, scale),
new BigDecimal(val));
}
/**

View File

@ -21,12 +21,13 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Nondeterministic;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DateTimeType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateType;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.VarcharType;
@ -40,16 +41,19 @@ import java.util.List;
* ScalarFunction 'unix_timestamp'. This class is generated by GenerateFunction.
*/
public class UnixTimestamp extends ScalarFunction
implements ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args, Nondeterministic {
implements ExplicitlyCastableSignature, Nondeterministic {
// we got changes when computeSignature
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(IntegerType.INSTANCE).args(),
FunctionSignature.ret(IntegerType.INSTANCE).args(DateTimeV2Type.SYSTEM_DEFAULT),
FunctionSignature.ret(DecimalV3Type.createDecimalV3Type(16, 6)).args(DateTimeV2Type.SYSTEM_DEFAULT),
FunctionSignature.ret(IntegerType.INSTANCE).args(DateV2Type.INSTANCE),
FunctionSignature.ret(IntegerType.INSTANCE).args(DateTimeType.INSTANCE),
FunctionSignature.ret(IntegerType.INSTANCE).args(DateType.INSTANCE),
FunctionSignature.ret(IntegerType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT, VarcharType.SYSTEM_DEFAULT),
FunctionSignature.ret(IntegerType.INSTANCE).args(StringType.INSTANCE, StringType.INSTANCE)
FunctionSignature.ret(DecimalV3Type.createDecimalV3Type(16, 6)).args(VarcharType.SYSTEM_DEFAULT,
VarcharType.SYSTEM_DEFAULT),
FunctionSignature.ret(DecimalV3Type.createDecimalV3Type(16, 6)).args(StringType.INSTANCE,
StringType.INSTANCE)
);
/**
@ -74,14 +78,41 @@ public class UnixTimestamp extends ScalarFunction
}
/**
* custom compute nullable.
* [['unix_timestamp'], 'INT', [], 'ALWAYS_NOT_NULLABLE'],
* [['unix_timestamp'], 'INT', ['DATETIME'], 'DEPEND_ON_ARGUMENT'],
* [['unix_timestamp'], 'INT', ['DATE'], 'DEPEND_ON_ARGUMENT'],
* [['unix_timestamp'], 'DECIMAL64', ['DATETIMEV2'], 'DEPEND_ON_ARGUMENT'],
* [['unix_timestamp'], 'INT', ['DATEV2'], 'DEPEND_ON_ARGUMENT'],
* [['unix_timestamp'], 'INT', ['VARCHAR', 'VARCHAR'], 'ALWAYS_NULLABLE'],
* [['unix_timestamp'], 'INT', ['STRING', 'STRING'], 'ALWAYS_NULLABLE'],
*/
@Override
public boolean nullable() {
if (arity() == 0) {
return false;
}
return PropagateNullableOnDateLikeV2Args.super.nullable();
if (arity() == 1) {
return child(0).nullable();
}
if (arity() == 2 && child(0).getDataType().isStringLikeType() && child(1).getDataType().isStringLikeType()) {
return true;
}
return child(0).nullable() || child(1).nullable();
}
@Override
public FunctionSignature computeSignature(FunctionSignature signature) {
if (arity() != 1) {
return signature;
}
DataType argType0 = getArgumentType(0);
if (argType0.isDateTimeV2Type()) {
int scale = ((DateTimeV2Type) argType0).getScale();
return signature.withReturnType(DecimalV3Type.createDecimalV3Type(10 + scale, scale));
} else if (argType0.isStringLikeType()) {
return signature.withReturnType(DecimalV3Type.createDecimalV3Type(16, 6));
}
return signature;
}
/**

View File

@ -106,6 +106,14 @@ public class DateTimeV2Literal extends DateTimeLiteral {
(int) (microSecond / Math.pow(10, DateTimeV2Type.MAX_SCALE - getDataType().getScale())));
}
public String getMicrosecondString() {
if (microSecond == 0) {
return "0";
}
return String.format("%0" + getDataType().getScale() + "d",
(int) (microSecond / Math.pow(10, DateTimeV2Type.MAX_SCALE - getDataType().getScale())));
}
@Override
public Expression plusYears(long years) {
return fromJavaDateType(

View File

@ -468,6 +468,11 @@ public class TypeCoercionUtils {
return promoted;
}
}
// adapt scale when from string to datetimev2 with float
if (type.isStringLikeType() && dataType.isDateTimeV2Type()) {
return recordTypeCoercionForSubQuery(input,
DateTimeV2Type.forTypeFromString(((Literal) input).getStringValue()));
}
}
return recordTypeCoercionForSubQuery(input, dataType);
}