@Override
  public ColumnTransformer visitFunctionExpression(
      FunctionExpression functionExpression, ColumnTransformerVisitorContext context) {
    List<Expression> expressions = functionExpression.getExpressions();
    if (!context.cache.containsKey(functionExpression)
        && !generateIdentityColumnTransformerIfPossible(functionExpression, context)) {
      if (context.hasSeen.containsKey(functionExpression)) {
        IdentityColumnTransformer identity =
            new IdentityColumnTransformer(
                TypeFactory.getType(context.getType(functionExpression)),
                context.originSize + context.commonTransformerList.size());
        ColumnTransformer columnTransformer = context.hasSeen.get(functionExpression);
        columnTransformer.addReferenceCount();
        context.commonTransformerList.add(columnTransformer);
        context.inputDataTypes.add(context.getType(functionExpression));
        context.leafList.add(identity);
        context.cache.put(functionExpression, identity);
      } else {
        if (functionExpression.isAggregationFunctionExpression()) {
          IdentityColumnTransformer identity =
              new IdentityColumnTransformer(
                  TypeFactory.getType(context.getType(functionExpression)),
                  context
                      .inputLocations
                      .get(functionExpression.getExpressionString())
                      .get(0)
                      .getValueColumnIndex());
          context.leafList.add(identity);
          context.cache.put(functionExpression, identity);
        } else if (functionExpression.isBuiltInScalarFunctionExpression()) {
          context.cache.put(
              functionExpression, getBuiltInScalarFunctionTransformer(functionExpression, context));
        } else {
          ColumnTransformer[] inputColumnTransformers =
              new ColumnTransformer[expressions.size() + 1];
          for (int i = 0; i < expressions.size(); i++) {
            inputColumnTransformers[i] = this.process(expressions.get(i), context);
          }
          // Append time column at the end of input columns for mappable UDTF
          ColumnTransformer columnTransformer =
              context.cache.computeIfAbsent(
                  new TimestampOperand(),
                  e -> {
                    TimeColumnTransformer timeColumnTransformer =
                        new TimeColumnTransformer(LongType.getInstance());
                    context.leafList.add(timeColumnTransformer);
                    return timeColumnTransformer;
                  });
          columnTransformer.addReferenceCount();
          inputColumnTransformers[expressions.size()] = columnTransformer;

          UDTFExecutor executor =
              context.udtfContext.getExecutorByFunctionExpression(functionExpression);

          // Mappable UDF does not need PointCollector, so memoryBudget and queryId is not
          // needed.
          executor.beforeStart(
              String.valueOf(0),
              0,
              expressions.stream()
                  .map(Expression::getExpressionString)
                  .collect(Collectors.toList()),
              expressions.stream().map(context::getType).collect(Collectors.toList()),
              functionExpression.getFunctionAttributes());

          context.cache.put(
              functionExpression,
              new MappableUDFColumnTransformer(
                  TypeFactory.getType(context.getType(functionExpression)),
                  inputColumnTransformers,
                  context.udtfContext.getExecutorByFunctionExpression(functionExpression)));
        }
      }
    }
    ColumnTransformer res = context.cache.get(functionExpression);
    res.addReferenceCount();
    return res;
  }
Responsible for constructing {@link ColumnTransformer} through Expression.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ColumnTransformerVisitor.java