public static IFill[] getPreviousFill(
      int inputColumns,
      List<TSDataType> inputDataTypes,
      TimeDuration timeDurationThreshold,
      ZoneId zoneId) {
    IFillFilter filter;
    if (timeDurationThreshold == null) {
      filter = null;
    } else if (!timeDurationThreshold.containsMonth()) {
      filter = new FixedIntervalFillFilter(timeDurationThreshold.nonMonthDuration);
    } else {
      switch (TIMESTAMP_PRECISION) {
        case "ms":
          filter =
              new MonthIntervalMSFillFilter(
                  timeDurationThreshold.monthDuration,
                  timeDurationThreshold.nonMonthDuration,
                  zoneId);
          break;
        case "us":
          filter =
              new MonthIntervalUSFillFilter(
                  timeDurationThreshold.monthDuration,
                  timeDurationThreshold.nonMonthDuration,
                  zoneId);
          break;
        case "ns":
          filter =
              new MonthIntervalNSFillFilter(
                  timeDurationThreshold.monthDuration,
                  timeDurationThreshold.nonMonthDuration,
                  zoneId);
          break;
        default:
          // this case will never reach
          throw new UnsupportedOperationException(
              "not supported time_precision: " + TIMESTAMP_PRECISION);
      }
    }

    IFill[] previousFill = new IFill[inputColumns];
    for (int i = 0; i < inputColumns; i++) {
      switch (inputDataTypes.get(i)) {
        case BOOLEAN:
          previousFill[i] =
              filter == null
                  ? new BooleanPreviousFill()
                  : new BooleanPreviousFillWithTimeDuration(filter);
          break;
        case TEXT:
        case STRING:
        case BLOB:
          previousFill[i] =
              filter == null
                  ? new BinaryPreviousFill()
                  : new BinaryPreviousFillWithTimeDuration(filter);
          break;
        case INT32:
        case DATE:
          previousFill[i] =
              filter == null ? new IntPreviousFill() : new IntPreviousFillWithTimeDuration(filter);
          break;
        case INT64:
        case TIMESTAMP:
          previousFill[i] =
              filter == null
                  ? new LongPreviousFill()
                  : new LongPreviousFillWithTimeDuration(filter);
          break;
        case FLOAT:
          previousFill[i] =
              filter == null
                  ? new FloatPreviousFill()
                  : new FloatPreviousFillWithTimeDuration(filter);
          break;
        case DOUBLE:
          previousFill[i] =
              filter == null
                  ? new DoublePreviousFill()
                  : new DoublePreviousFillWithTimeDuration(filter);
          break;
        default:
          throw new IllegalArgumentException(UNKNOWN_DATATYPE + inputDataTypes.get(i));
      }
    }
    return previousFill;
  }
This Visitor is responsible for transferring PlanNode Tree to Operator Tree.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java