public static Type getFunctionType()

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);
  }