in iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java [211:734]
public static Type getFunctionType(String functionName, List<? extends Type> argumentTypes) {
// builtin scalar function
if (TableBuiltinScalarFunction.DIFF.getFunctionName().equalsIgnoreCase(functionName)) {
if (!isOneNumericType(argumentTypes)
&& !(argumentTypes.size() == 2
&& isNumericType(argumentTypes.get(0))
&& BOOLEAN.equals(argumentTypes.get(1)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only supports one numeric data types [INT32, INT64, FLOAT, DOUBLE] and one boolean");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.ROUND.getFunctionName().equalsIgnoreCase(functionName)) {
if (!isOneSupportedMathNumericType(argumentTypes)
&& !isTwoSupportedMathNumericType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only supports two numeric data types [INT32, INT64, FLOAT, DOUBLE]");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.REPLACE
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!isTwoCharType(argumentTypes) && !isThreeCharType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two or three arguments and they must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.SUBSTRING
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 2
&& isCharType(argumentTypes.get(0))
&& isIntegerNumber(argumentTypes.get(1)))
&& !(argumentTypes.size() == 3
&& isCharType(argumentTypes.get(0))
&& isIntegerNumber(argumentTypes.get(1))
&& isIntegerNumber(argumentTypes.get(2)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two or three arguments and first must be text or string data type, second and third must be numeric data types [INT32, INT64]");
}
return STRING;
} else if (TableBuiltinScalarFunction.LENGTH.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isCharType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be text or string data type.");
}
return INT32;
} else if (TableBuiltinScalarFunction.UPPER.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isCharType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.LOWER.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isCharType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.TRIM.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isCharType(argumentTypes.get(0)))
&& !(argumentTypes.size() == 2 && isTwoCharType(argumentTypes))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one or two arguments and they must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.LTRIM.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isCharType(argumentTypes.get(0)))
&& !(argumentTypes.size() == 2 && isTwoCharType(argumentTypes))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one or two arguments and they must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.RTRIM.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isCharType(argumentTypes.get(0)))
&& !(argumentTypes.size() == 2 && isTwoCharType(argumentTypes))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one or two arguments and they must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.REGEXP_LIKE
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!isTwoCharType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two arguments and they must be text or string data type.");
}
return BOOLEAN;
} else if (TableBuiltinScalarFunction.STRPOS.getFunctionName().equalsIgnoreCase(functionName)) {
if (!isTwoCharType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two arguments and they must be text or string data type.");
}
return INT32;
} else if (TableBuiltinScalarFunction.STARTS_WITH
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!isTwoCharType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two arguments and they must be text or string data type.");
}
return BOOLEAN;
} else if (TableBuiltinScalarFunction.ENDS_WITH
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!isTwoCharType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two arguments and they must be text or string data type.");
}
return BOOLEAN;
} else if (TableBuiltinScalarFunction.CONCAT.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() >= 2
&& argumentTypes.stream().allMatch(TableMetadataImpl::isCharType))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two or more arguments and they must be text or string data type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.STRCMP.getFunctionName().equalsIgnoreCase(functionName)) {
if (!isTwoCharType(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two arguments and they must be text or string data type.");
}
return INT32;
} else if (TableBuiltinScalarFunction.SIN.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.COS.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.TAN.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.ASIN.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.ACOS.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.ATAN.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.SINH.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.COSH.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.TANH.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.DEGREES
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.RADIANS
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.ABS.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return argumentTypes.get(0);
} else if (TableBuiltinScalarFunction.SIGN.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return argumentTypes.get(0);
} else if (TableBuiltinScalarFunction.CEIL.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.FLOOR.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.EXP.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.LN.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.LOG10.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.SQRT.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.size() == 1 && isSupportedMathNumericType(argumentTypes.get(0)))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts one argument and it must be Double, Float, Int32 or Int64 data type.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.PI.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.isEmpty())) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " accepts no argument.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.E.getFunctionName().equalsIgnoreCase(functionName)) {
if (!(argumentTypes.isEmpty())) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " accepts no argument.");
}
return DOUBLE;
} else if (TableBuiltinScalarFunction.DATE_BIN
.getFunctionName()
.equalsIgnoreCase(functionName)) {
if (!isTimestampType(argumentTypes.get(2))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " only accepts two or three arguments and the second and third must be TimeStamp data type.");
}
return TIMESTAMP;
} else if (TableBuiltinScalarFunction.FORMAT.getFunctionName().equalsIgnoreCase(functionName)) {
if (argumentTypes.size() < 2 || !isCharType(argumentTypes.get(0))) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " must have at least two arguments, and first argument pattern must be TEXT or STRING type.");
}
return STRING;
} else if (TableBuiltinScalarFunction.GREATEST.getFunctionName().equalsIgnoreCase(functionName)
|| TableBuiltinScalarFunction.LEAST.getFunctionName().equalsIgnoreCase(functionName)) {
if (argumentTypes.size() < 2 || !areAllTypesSameAndComparable(argumentTypes)) {
throw new SemanticException(
"Scalar function "
+ functionName.toLowerCase(Locale.ENGLISH)
+ " must have at least two arguments, and all type must be the same.");
}
return argumentTypes.get(0);
}
// builtin aggregation function
// check argument type
switch (functionName.toLowerCase(Locale.ENGLISH)) {
case SqlConstant.AVG:
case SqlConstant.SUM:
case SqlConstant.EXTREME:
case SqlConstant.STDDEV:
case SqlConstant.STDDEV_POP:
case SqlConstant.STDDEV_SAMP:
case SqlConstant.VARIANCE:
case SqlConstant.VAR_POP:
case SqlConstant.VAR_SAMP:
if (argumentTypes.size() != 1) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have one argument", functionName));
}
if (!isSupportedMathNumericType(argumentTypes.get(0))) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] only support numeric data types [INT32, INT64, FLOAT, DOUBLE]",
functionName));
}
break;
case SqlConstant.MIN:
case SqlConstant.MAX:
case SqlConstant.MODE:
if (argumentTypes.size() != 1) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have one argument", functionName));
}
break;
case SqlConstant.COUNT_IF:
if (argumentTypes.size() != 1 || !isBool(argumentTypes.get(0))) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have one boolean expression as argument",
functionName));
}
break;
case SqlConstant.FIRST_AGGREGATION:
case SqlConstant.LAST_AGGREGATION:
if (argumentTypes.size() != 2) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have one or two arguments", functionName));
} else if (!isTimestampType(argumentTypes.get(1))) {
throw new SemanticException(
String.format(
"Second argument of Aggregate functions [%s] should be orderable", functionName));
}
break;
case SqlConstant.FIRST_BY_AGGREGATION:
case SqlConstant.LAST_BY_AGGREGATION:
if (argumentTypes.size() != 3) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have two or three arguments",
functionName));
}
break;
case SqlConstant.MAX_BY:
case SqlConstant.MIN_BY:
if (argumentTypes.size() != 2) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have two arguments", functionName));
} else if (!argumentTypes.get(1).isOrderable()) {
throw new SemanticException(
String.format(
"Second argument of Aggregate functions [%s] should be orderable", functionName));
}
break;
case SqlConstant.APPROX_COUNT_DISTINCT:
if (argumentTypes.size() != 1 && argumentTypes.size() != 2) {
throw new SemanticException(
String.format(
"Aggregate functions [%s] should only have two arguments", functionName));
}
if (argumentTypes.size() == 2 && !isSupportedMathNumericType(argumentTypes.get(1))) {
throw new SemanticException(
String.format(
"Second argument of Aggregate functions [%s] should be numberic type and do not use expression",
functionName));
}
case SqlConstant.COUNT:
break;
default:
// ignore
}
// get return type
switch (functionName.toLowerCase(Locale.ENGLISH)) {
case SqlConstant.COUNT:
case SqlConstant.COUNT_ALL:
case SqlConstant.COUNT_IF:
case SqlConstant.APPROX_COUNT_DISTINCT:
return INT64;
case SqlConstant.FIRST_AGGREGATION:
case SqlConstant.LAST_AGGREGATION:
case SqlConstant.FIRST_BY_AGGREGATION:
case SqlConstant.LAST_BY_AGGREGATION:
case SqlConstant.EXTREME:
case SqlConstant.MODE:
case SqlConstant.MAX:
case SqlConstant.MIN:
case SqlConstant.MAX_BY:
case SqlConstant.MIN_BY:
return argumentTypes.get(0);
case SqlConstant.AVG:
case SqlConstant.SUM:
case SqlConstant.STDDEV:
case SqlConstant.STDDEV_POP:
case SqlConstant.STDDEV_SAMP:
case SqlConstant.VARIANCE:
case SqlConstant.VAR_POP:
case SqlConstant.VAR_SAMP:
return DOUBLE;
default:
// ignore
}
// User-defined scalar function
if (TableUDFUtils.isScalarFunction(functionName)) {
ScalarFunction scalarFunction = TableUDFUtils.getScalarFunction(functionName);
FunctionArguments functionArguments =
new FunctionArguments(
argumentTypes.stream()
.map(UDFDataTypeTransformer::transformReadTypeToUDFDataType)
.collect(Collectors.toList()),
Collections.emptyMap());
try {
ScalarFunctionAnalysis scalarFunctionAnalysis = scalarFunction.analyze(functionArguments);
return UDFDataTypeTransformer.transformUDFDataTypeToReadType(
scalarFunctionAnalysis.getOutputDataType());
} catch (Exception e) {
throw new SemanticException("Invalid function parameters: " + e.getMessage());
} finally {
scalarFunction.beforeDestroy();
}
} else if (TableUDFUtils.isAggregateFunction(functionName)) {
AggregateFunction aggregateFunction = TableUDFUtils.getAggregateFunction(functionName);
FunctionArguments functionArguments =
new FunctionArguments(
argumentTypes.stream()
.map(UDFDataTypeTransformer::transformReadTypeToUDFDataType)
.collect(Collectors.toList()),
Collections.emptyMap());
try {
AggregateFunctionAnalysis aggregateFunctionAnalysis =
aggregateFunction.analyze(functionArguments);
return UDFDataTypeTransformer.transformUDFDataTypeToReadType(
aggregateFunctionAnalysis.getOutputDataType());
} catch (Exception e) {
throw new SemanticException("Invalid function parameters: " + e.getMessage());
} finally {
aggregateFunction.beforeDestroy();
}
}
throw new SemanticException("Unknown function: " + functionName);
}