@Override
  public Operator visitSeriesScan(SeriesScanNode node, LocalExecutionPlanContext context) {
    NonAlignedFullPath seriesPath =
        (NonAlignedFullPath) IFullPath.convertToIFullPath(node.getSeriesPath());

    SeriesScanOptions.Builder scanOptionsBuilder = getSeriesScanOptionsBuilder(context);
    scanOptionsBuilder.withAllSensors(
        context.getAllSensors(seriesPath.getDeviceId(), seriesPath.getMeasurement()));

    Expression pushDownPredicate = node.getPushDownPredicate();
    boolean predicateCanPushIntoScan = canPushIntoScan(pushDownPredicate);
    if (pushDownPredicate != null && predicateCanPushIntoScan) {
      scanOptionsBuilder.withPushDownFilter(
          convertPredicateToFilter(
              pushDownPredicate,
              Collections.singletonList(node.getSeriesPath().getMeasurement()),
              context.getTypeProvider().getTemplatedInfo() != null,
              context.getTypeProvider(),
              context.getZoneId()));
    }
    if (pushDownPredicate == null || predicateCanPushIntoScan) {
      scanOptionsBuilder.withPushDownLimit(node.getPushDownLimit());
      scanOptionsBuilder.withPushDownOffset(node.getPushDownOffset());
    }

    OperatorContext operatorContext =
        context
            .getDriverContext()
            .addOperatorContext(
                context.getNextOperatorId(),
                node.getPlanNodeId(),
                SeriesScanOperator.class.getSimpleName());
    operatorContext.recordSpecifiedInfo("SeriesPath", seriesPath.toString());
    SeriesScanOperator seriesScanOperator =
        new SeriesScanOperator(
            operatorContext,
            node.getPlanNodeId(),
            seriesPath,
            node.getScanOrder(),
            scanOptionsBuilder.build());

    ((DataDriverContext) context.getDriverContext()).addSourceOperator(seriesScanOperator);
    ((DataDriverContext) context.getDriverContext()).addPath(seriesPath);
    context.getDriverContext().setInputDriver(true);

    if (!predicateCanPushIntoScan) {
      checkState(!context.isBuildPlanUseTemplate(), "Push down predicate is not supported yet");
      Operator rootOperator =
          constructFilterOperator(
              pushDownPredicate,
              seriesScanOperator,
              Collections.singletonList(ExpressionFactory.timeSeries(node.getSeriesPath()))
                  .toArray(new Expression[0]),
              Collections.singletonList(node.getSeriesPath().getSeriesType()),
              makeLayout(Collections.singletonList(node)),
              false,
              node.getPlanNodeId(),
              node.getScanOrder(),
              context);
      if (node.getPushDownOffset() > 0) {
        rootOperator =
            new OffsetOperator(
                context
                    .getDriverContext()
                    .addOperatorContext(
                        context.getNextOperatorId(),
                        node.getPlanNodeId(),
                        OffsetOperator.class.getSimpleName()),
                node.getPushDownOffset(),
                rootOperator);
      }
      if (node.getPushDownLimit() > 0) {
        rootOperator =
            new LimitOperator(
                context
                    .getDriverContext()
                    .addOperatorContext(
                        context.getNextOperatorId(),
                        node.getPlanNodeId(),
                        LimitOperator.class.getSimpleName()),
                node.getPushDownLimit(),
                rootOperator);
      }
      return rootOperator;
    }
    return seriesScanOperator;
  }
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