diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 index 35fe7f26a2..b6f1ae30e5 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 @@ -123,6 +123,7 @@ CAST: 'CAST'; CATALOG: 'CATALOG'; CATALOGS: 'CATALOGS'; CHANGE: 'CHANGE'; +CHAR: 'CHAR'; CHECK: 'CHECK'; CLEAR: 'CLEAR'; CLUSTER: 'CLUSTER'; @@ -139,6 +140,7 @@ COMPACTIONS: 'COMPACTIONS'; COMPUTE: 'COMPUTE'; CONCATENATE: 'CONCATENATE'; CONSTRAINT: 'CONSTRAINT'; +CONVERT: 'CONVERT'; COST: 'COST'; CREATE: 'CREATE'; CROSS: 'CROSS'; diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 891c3a01b8..7dc1554ce1 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -404,8 +404,18 @@ primaryExpression | interval #intervalLiteral | ASTERISK #star | qualifiedName DOT ASTERISK #star - | functionIdentifier LEFT_PAREN ((DISTINCT|ALL)? arguments+=expression - (COMMA arguments+=expression)* (ORDER BY sortItem (COMMA sortItem)*)?)? RIGHT_PAREN + | CHAR LEFT_PAREN + arguments+=expression (COMMA arguments+=expression)* + (USING charSet=identifierOrText)? + RIGHT_PAREN #charFunction + | CONVERT LEFT_PAREN argument=expression USING charSet=identifierOrText RIGHT_PAREN #convertCharSet + | CONVERT LEFT_PAREN argument=expression COMMA type=dataType RIGHT_PAREN #convertType + | functionIdentifier + LEFT_PAREN ( + (DISTINCT|ALL)? + arguments+=expression (COMMA arguments+=expression)* + (ORDER BY sortItem (COMMA sortItem)*)? + )? RIGHT_PAREN (OVER windowSpec)? #functionCall | value=primaryExpression LEFT_BRACKET index=valueExpression RIGHT_BRACKET #elementAt | value=primaryExpression LEFT_BRACKET begin=valueExpression @@ -584,6 +594,7 @@ nonReserved | CATALOG | CATALOGS | CHANGE + | CHAR | CHECK | CLEAR | CLUSTER @@ -600,6 +611,7 @@ nonReserved | COMPUTE | CONCATENATE | CONSTRAINT + | CONVERT | COST | CREATE | CUBE @@ -835,4 +847,4 @@ nonReserved | HDFS | BROKER //--DEFAULT-NON-RESERVED-END - ; + ; \ No newline at end of file diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java index 8267b4f952..3dd3044404 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java @@ -82,6 +82,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXorCoun import org.apache.doris.nereids.trees.expressions.functions.scalar.Cardinality; import org.apache.doris.nereids.trees.expressions.functions.scalar.Cbrt; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Char; import org.apache.doris.nereids.trees.expressions.functions.scalar.CharacterLength; import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce; import org.apache.doris.nereids.trees.expressions.functions.scalar.Concat; @@ -428,6 +429,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(Cardinality.class, "array_size", "cardinality", "size"), scalar(Cbrt.class, "cbrt"), scalar(Ceil.class, "ceil", "ceiling"), + scalar(Char.class, "char"), scalar(CharacterLength.class, "char_length", "character_length"), scalar(Coalesce.class, "coalesce"), scalar(Concat.class, "concat"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index c7e7a19361..a0c6c09925 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -194,6 +194,8 @@ import org.apache.doris.nereids.trees.expressions.functions.agg.Count; import org.apache.doris.nereids.trees.expressions.functions.agg.GroupConcat; import org.apache.doris.nereids.trees.expressions.functions.scalar.Array; import org.apache.doris.nereids.trees.expressions.functions.scalar.ArraySlice; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Char; +import org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTo; import org.apache.doris.nereids.trees.expressions.functions.scalar.CreateMap; import org.apache.doris.nereids.trees.expressions.functions.scalar.CreateStruct; import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd; @@ -1185,6 +1187,38 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor { return new EncryptKeyRef(new StringLiteral(db), new StringLiteral(key)); } + @Override + public Expression visitCharFunction(DorisParser.CharFunctionContext ctx) { + String charSet = ctx.charSet == null ? "utf8" : ctx.charSet.getText(); + List arguments = ImmutableList.builder() + .add(new StringLiteral(charSet)) + .addAll(visit(ctx.arguments, Expression.class)) + .build(); + return new Char(arguments); + } + + @Override + public Expression visitConvertCharSet(DorisParser.ConvertCharSetContext ctx) { + return new ConvertTo(getExpression(ctx.argument), new StringLiteral(ctx.charSet.getText())); + } + + @Override + public Expression visitConvertType(DorisParser.ConvertTypeContext ctx) { + DataType dataType = ((DataType) typedVisit(ctx.type)).conversion(); + Expression cast = ParserUtils.withOrigin(ctx, () -> + new Cast(getExpression(ctx.argument), dataType)); + if (dataType.isStringLikeType() && ((CharacterType) dataType).getLen() >= 0) { + List args = ImmutableList.of( + cast, + new TinyIntLiteral((byte) 1), + Literal.of(((CharacterType) dataType).getLen()) + ); + return new UnboundFunction("substr", args); + } else { + return cast; + } + } + @Override public Expression visitFunctionCall(DorisParser.FunctionCallContext ctx) { return ParserUtils.withOrigin(ctx, () -> { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Char.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Char.java new file mode 100644 index 0000000000..77b311835f --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Char.java @@ -0,0 +1,65 @@ +// 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.functions.scalar; + +import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable; +import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.IntegerType; +import org.apache.doris.nereids.types.StringType; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction 'char'. + */ +public class Char extends ScalarFunction + implements ExplicitlyCastableSignature, AlwaysNullable { + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(StringType.INSTANCE).varArgs(StringType.INSTANCE, IntegerType.INSTANCE)); + + public Char(List varArgs) { + super("char", varArgs); + } + + public Char(Expression... varArgs) { + super("char", varArgs); + } + + /** + * withChildren. + */ + @Override + public Char withChildren(List children) { + return new Char(children); + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitChar(this, context); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java index 0f37d870b9..a303a17736 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java @@ -86,6 +86,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXorCoun import org.apache.doris.nereids.trees.expressions.functions.scalar.Cardinality; import org.apache.doris.nereids.trees.expressions.functions.scalar.Cbrt; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Char; import org.apache.doris.nereids.trees.expressions.functions.scalar.CharacterLength; import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce; import org.apache.doris.nereids.trees.expressions.functions.scalar.Concat; @@ -633,6 +634,10 @@ public interface ScalarFunctionVisitor { return visitScalarFunction(concat, context); } + default R visitChar(Char charFunc, C context) { + return visitScalarFunction(charFunc, context); + } + default R visitConcatWs(ConcatWs concatWs, C context) { return visitScalarFunction(concatWs, context); } diff --git a/regression-test/data/nereids_function_p0/scalar_function/C.out b/regression-test/data/nereids_function_p0/scalar_function/C.out index 7f60e9d43f..17aae49730 100644 --- a/regression-test/data/nereids_function_p0/scalar_function/C.out +++ b/regression-test/data/nereids_function_p0/scalar_function/C.out @@ -1101,3 +1101,9 @@ varchar13 0.4535961214255773 0.3623577544766736 +-- !char -- +Doris Doris + +-- !convert -- +1 1 + diff --git a/regression-test/suites/nereids_function_p0/scalar_function/C.groovy b/regression-test/suites/nereids_function_p0/scalar_function/C.groovy index 47ff0b9b5d..df896d9f29 100644 --- a/regression-test/suites/nereids_function_p0/scalar_function/C.groovy +++ b/regression-test/suites/nereids_function_p0/scalar_function/C.groovy @@ -99,4 +99,8 @@ suite("nereids_scalar_fn_C") { qt_sql_cos_Double_notnull "select cos(kdbl) from fn_test_not_nullable order by kdbl" sql "select current_user() from fn_test" sql "select current_user() from fn_test_not_nullable" + + qt_char "select char(68, 111, 114, 105, 115), char(68, 111, 114, 105, 115 using utf8);" + qt_convert "select convert(1 using gbk), convert(1, string);" + }