Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ CREATE [AGGREGATE] [ALIAS] FUNCTION function_name
>
> `Function_name`: To create the name of the function, you can include the name of the database. For example: `db1.my_func'.
>
> `arg_type`: The parameter type of the function is the same as the type defined at the time of table building. Variable-length parameters can be represented by `,...`. If it is a variable-length type, the type of the variable-length part of the parameters is the same as the last non-variable-length parameter type.
> **NOTICE**: `ALIAS FUNCTION` variable-length parameters are not supported, and there is at least one parameter.
> `arg_type`: The parameter type of the function is the same as the type defined at the time of table building. Variable-length parameters can be represented by `,...`. If it is a variable-length type, the type of the variable-length part of the parameters is the same as the last non-variable-length parameter type.
> **NOTICE**: `ALIAS FUNCTION` variable-length parameters are not supported, and there is at least one parameter. In particular, the type `ALL` refers to any data type and can only be used for `ALIAS FUNCTION`.
>
> `ret_type`: Required for creating a new function. This parameter is not required if you are aliasing an existing function.
>
Expand Down Expand Up @@ -130,8 +130,13 @@ If the `function_name` contains the database name, the custom function will be c
5. Create a custom alias function

```
-- create a custom functional alias function
CREATE ALIAS FUNCTION id_masking(INT) WITH PARAMETER(id)
AS CONCAT(LEFT(id, 3), '****', RIGHT(id, 4));

-- create a custom cast alias function
CREATE ALIAS FUNCTION decimal(ALL, INT, INT) WITH PARAMETER(col, precision, scale)
AS CAST(col AS decimal(precision, scale));
```

## keyword
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ CREATE [AGGREGATE] [ALIAS] FUNCTION function_name
>
> `function_name`: 要创建函数的名字, 可以包含数据库的名字。比如:`db1.my_func`。
>
> `arg_type`: 函数的参数类型,与建表时定义的类型一致。变长参数时可以使用`, ...`来表示,如果是变长类型,那么变长部分参数的类型与最后一个非变长参数类型一致。
> **注意**:`ALIAS FUNCTION` 不支持变长参数,且至少有一个参数。
> `arg_type`: 函数的参数类型,与建表时定义的类型一致。变长参数时可以使用`, ...`来表示,如果是变长类型,那么变长部分参数的类型与最后一个非变长参数类型一致。
> **注意**:`ALIAS FUNCTION` 不支持变长参数,且至少有一个参数。 特别地,`ALL` 类型指任一数据类型,只可以用于 `ALIAS FUNCTION`.
>
> `ret_type`: 对创建新的函数来说,是必填项。如果是给已有函数取别名则可不用填写该参数。
>
Expand Down Expand Up @@ -131,8 +131,13 @@ CREATE [AGGREGATE] [ALIAS] FUNCTION function_name
5. 创建一个自定义别名函数

```
-- 创建自定义功能别名函数
CREATE ALIAS FUNCTION id_masking(INT) WITH PARAMETER(id)
AS CONCAT(LEFT(id, 3), '****', RIGHT(id, 4));

-- 创建自定义 CAST 别名函数
CREATE ALIAS FUNCTION decimal(ALL, INT, INT) WITH PARAMETER(col, precision, scale)
AS CAST(col AS decimal(precision, scale));
```

## keyword
Expand Down
22 changes: 22 additions & 0 deletions fe/fe-core/src/main/cup/sql_parser.cup
Original file line number Diff line number Diff line change
Expand Up @@ -4352,6 +4352,11 @@ type ::=
type.setAssignedStrLenInColDefinition();
RESULT = type;
:}
| KW_VARCHAR LPAREN ident_or_text:lenStr RPAREN
{: ScalarType type = ScalarType.createVarcharType(lenStr);
type.setAssignedStrLenInColDefinition();
RESULT = type;
:}
| KW_VARCHAR
{: RESULT = ScalarType.createVarcharType(-1); :}
| KW_ARRAY LESSTHAN type:value_type GREATERTHAN
Expand All @@ -4365,6 +4370,11 @@ type ::=
type.setAssignedStrLenInColDefinition();
RESULT = type;
:}
| KW_CHAR LPAREN ident_or_text:lenStr RPAREN
{: ScalarType type = ScalarType.createCharType(lenStr);
type.setAssignedStrLenInColDefinition();
RESULT = type;
:}
| KW_CHAR
{: RESULT = ScalarType.createCharType(-1); :}
| KW_DECIMAL LPAREN INTEGER_LITERAL:precision RPAREN
Expand All @@ -4373,11 +4383,17 @@ type ::=
{: RESULT = ScalarType.createDecimalV2Type(precision.intValue(), scale.intValue()); :}
| KW_DECIMAL
{: RESULT = ScalarType.createDecimalV2Type(); :}
| KW_DECIMAL LPAREN ident_or_text:precision RPAREN
{: RESULT = ScalarType.createDecimalV2Type(precision); :}
| KW_DECIMAL LPAREN ident_or_text:precision COMMA ident_or_text:scale RPAREN
{: RESULT = ScalarType.createDecimalV2Type(precision, scale); :}
| KW_HLL
{: ScalarType type = ScalarType.createHllType();
type.setAssignedStrLenInColDefinition();
RESULT = type;
:}
| KW_ALL
{: RESULT = Type.ALL; :}
;

opt_field_length ::=
Expand Down Expand Up @@ -5180,6 +5196,8 @@ keyword ::=
{: RESULT = id; :}
| KW_CHAIN:id
{: RESULT = id; :}
| KW_CHAR:id
{: RESULT = id; :}
| KW_CHARSET:id
{: RESULT = id; :}
| KW_CHECK:id
Expand Down Expand Up @@ -5210,6 +5228,8 @@ keyword ::=
{: RESULT = id; :}
| KW_DATETIME:id
{: RESULT = id; :}
| KW_DECIMAL:id
{: RESULT = id; :}
| KW_DISTINCTPC:id
{: RESULT = id; :}
| KW_DISTINCTPCSA:id
Expand Down Expand Up @@ -5456,6 +5476,8 @@ keyword ::=
{: RESULT = id; :}
| KW_MAP:id
{: RESULT = id; :}
| KW_VARCHAR:id
{: RESULT = id; :}
;

// Identifier that contain keyword
Expand Down
126 changes: 125 additions & 1 deletion fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@

package org.apache.doris.analysis;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.doris.catalog.Catalog;
Expand Down Expand Up @@ -46,7 +50,7 @@ public class CastExpr extends Expr {
private static final Logger LOG = LogManager.getLogger(CastExpr.class);

// Only set for explicit casts. Null for implicit casts.
private final TypeDef targetTypeDef;
private TypeDef targetTypeDef;

// True if this is a "pre-analyzed" implicit cast.
private boolean isImplicit;
Expand Down Expand Up @@ -77,6 +81,11 @@ public class CastExpr extends Expr {
}
}

// only used restore from readFields.
public CastExpr() {

}

public CastExpr(Type targetType, Expr e) {
super();
Preconditions.checkArgument(targetType.isValid());
Expand Down Expand Up @@ -120,6 +129,10 @@ private static String getFnName(Type targetType) {
return "castTo" + targetType.getPrimitiveType().toString();
}

public TypeDef getTargetTypeDef() {
return targetTypeDef;
}

public static void initBuiltins(FunctionSet functionSet) {
for (Type fromType : Type.getSupportedTypes()) {
if (fromType.isNull()) {
Expand Down Expand Up @@ -206,6 +219,10 @@ public void setImplicit(boolean implicit) {
}

public void analyze() throws AnalysisException {
// do not analyze ALL cast
if (type == Type.ALL) {
return;
}
// cast was asked for in the query, check for validity of cast
Type childType = getChild(0).getType();

Expand Down Expand Up @@ -327,4 +344,111 @@ private Expr castTo(LiteralExpr value) throws AnalysisException {
}
return this;
}

@Override
public void write(DataOutput out) throws IOException {
out.writeBoolean(isImplicit);
if (targetTypeDef.getType() instanceof ScalarType) {
ScalarType scalarType = (ScalarType) targetTypeDef.getType();
scalarType.write(out);
} else {
throw new IOException("Can not write type " + targetTypeDef.getType());
}
out.writeInt(children.size());
for (Expr expr : children) {
Expr.writeTo(expr, out);
}
}

public static CastExpr read(DataInput input) throws IOException {
CastExpr castExpr = new CastExpr();
castExpr.readFields(input);
return castExpr;
}

@Override
public void readFields(DataInput in) throws IOException {
isImplicit = in.readBoolean();
ScalarType scalarType = ScalarType.read(in);
targetTypeDef = new TypeDef(scalarType);
int counter = in.readInt();
for (int i = 0; i < counter; i++) {
children.add(Expr.readIn(in));
}
}

public CastExpr rewriteExpr(List<String> parameters, List<Expr> inputParamsExprs) throws AnalysisException {
// child
Expr child = this.getChild(0);
Expr newChild = null;
if (child instanceof SlotRef) {
String columnName = ((SlotRef) child).getColumnName();
int index = parameters.indexOf(columnName);
if (index != -1) {
newChild = inputParamsExprs.get(index);
}
}
// rewrite cast expr in children
if (child instanceof CastExpr) {
newChild = ((CastExpr) child).rewriteExpr(parameters, inputParamsExprs);
}

// type def
ScalarType targetType = (ScalarType) targetTypeDef.getType();
PrimitiveType primitiveType = targetType.getPrimitiveType();
ScalarType newTargetType = null;
switch (primitiveType) {
case DECIMALV2:
// normal decimal
if (targetType.getPrecision() != 0) {
newTargetType = targetType;
break;
}
int precision = getDigital(targetType.getScalarPrecisionStr(), parameters, inputParamsExprs);
int scale = getDigital(targetType.getScalarScaleStr(), parameters, inputParamsExprs);
if (precision != -1 && scale != -1) {
newTargetType = ScalarType.createType(primitiveType, 0, precision, scale);
} else if (precision != -1 && scale == -1) {
newTargetType = ScalarType.createType(primitiveType, 0, precision, ScalarType.DEFAULT_SCALE);
}
break;
case CHAR:
case VARCHAR:
// normal char/varchar
if (targetType.getLength() != -1) {
newTargetType = targetType;
break;
}
int len = getDigital(targetType.getLenStr(), parameters, inputParamsExprs);
if (len != -1) {
newTargetType = ScalarType.createType(primitiveType, len, 0, 0);
}
// default char/varchar, which len is -1
if (len == -1 && targetType.getLength() == -1) {
newTargetType = targetType;
}
break;
default:
newTargetType = targetType;
break;
}

if (newTargetType != null && newChild != null) {
TypeDef typeDef = new TypeDef(newTargetType);
return new CastExpr(typeDef, newChild);
}

return this;
}

private int getDigital(String desc, List<String> parameters, List<Expr> inputParamsExprs) {
int index = parameters.indexOf(desc);
if (index != -1) {
Expr expr = inputParamsExprs.get(index);
if (expr.getType().isIntegerType()) {
return ((Long)((IntLiteral) expr).getRealValue()).intValue();
}
}
return -1;
}
}
9 changes: 7 additions & 2 deletions fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,8 @@ enum ExprSerCode {
MAX_LITERAL(10),
BINARY_PREDICATE(11),
FUNCTION_CALL(12),
ARRAY_LITERAL(13);
ARRAY_LITERAL(13),
CAST_EXPR(14);

private static Map<Integer, ExprSerCode> codeMap = Maps.newHashMap();

Expand Down Expand Up @@ -1715,7 +1716,9 @@ public static void writeTo(Expr expr, DataOutput output) throws IOException {
output.writeInt(ExprSerCode.FUNCTION_CALL.getCode());
} else if (expr instanceof ArrayLiteral) {
output.writeInt(ExprSerCode.ARRAY_LITERAL.getCode());
} else {
} else if (expr instanceof CastExpr){
output.writeInt(ExprSerCode.CAST_EXPR.getCode());
}else {
throw new IOException("Unknown class " + expr.getClass().getName());
}
expr.write(output);
Expand Down Expand Up @@ -1758,6 +1761,8 @@ public static Expr readIn(DataInput in) throws IOException {
return FunctionCallExpr.read(in);
case ARRAY_LITERAL:
return ArrayLiteral.read(in);
case CAST_EXPR:
return CastExpr.read(in);
default:
throw new IOException("Unknown code: " + code);
}
Expand Down
Loading