@Override
  public PlanNode visitShowTimeSeries(
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
    LogicalPlanBuilder planBuilder = new LogicalPlanBuilder(analysis, context);

    long limit = showTimeSeriesStatement.getLimit();
    long offset = showTimeSeriesStatement.getOffset();
    if (showTimeSeriesStatement.hasTimeCondition()) {
      planBuilder =
          planBuilder
              .planTimeseriesRegionScan(analysis.getDeviceToTimeseriesSchemas(), false)
              .planLimit(limit)
              .planOffset(offset);
      return planBuilder.getRoot();
    }

    // If there is only one region, we can push down the offset and limit operation to
    // source operator.
    boolean canPushDownOffsetLimit =
        analysis.getSchemaPartitionInfo() != null
            && analysis.getSchemaPartitionInfo().getDistributionInfo().size() == 1
            && !showTimeSeriesStatement.isOrderByHeat();

    if (showTimeSeriesStatement.isOrderByHeat()) {
      limit = 0;
      offset = 0;
    } else if (!canPushDownOffsetLimit) {
      limit = showTimeSeriesStatement.getLimit() + showTimeSeriesStatement.getOffset();
      offset = 0;
    }
    planBuilder =
        planBuilder
            .planTimeSeriesSchemaSource(
                showTimeSeriesStatement.getPathPattern(),
                showTimeSeriesStatement.getSchemaFilter(),
                limit,
                offset,
                showTimeSeriesStatement.isOrderByHeat(),
                showTimeSeriesStatement.isPrefixPath(),
                analysis.getRelatedTemplateInfo(),
                showTimeSeriesStatement.getAuthorityScope())
            .planSchemaQueryMerge(showTimeSeriesStatement.isOrderByHeat());

    // show latest timeseries
    if (showTimeSeriesStatement.isOrderByHeat()
        && null != analysis.getDataPartitionInfo()
        && !analysis.getDataPartitionInfo().getDataPartitionMap().isEmpty()) {
      PlanNode lastPlanNode =
          new LogicalPlanBuilder(analysis, context).planLast(analysis, null).getRoot();
      planBuilder = planBuilder.planSchemaQueryOrderByHeat(lastPlanNode);
    }

    if (canPushDownOffsetLimit) {
      return planBuilder.getRoot();
    }

    return planBuilder
        .planOffset(showTimeSeriesStatement.getOffset())
        .planLimit(showTimeSeriesStatement.getLimit())
        .getRoot();
  }
This visitor is used to generate a logical plan for the statement and returns the {@link
PlanNode}.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java