public boolean hasNextFile() throws IOException {
    if (!paginationController.hasCurLimit()) {
      return false;
    }

    if (!unSeqPageReaders.isEmpty()
        || firstPageReader != null
        || mergeReader.hasNextTimeValuePair()) {
      throw new IllegalStateException(
          "all cached pages should be consumed first unSeqPageReaders.isEmpty() is "
              + unSeqPageReaders.isEmpty()
              + " firstPageReader != null is "
              + (firstPageReader != null)
              + " mergeReader.hasNextTimeValuePair() = "
              + mergeReader.hasNextTimeValuePair());
    }

    if (firstChunkMetadata != null || !cachedChunkMetadata.isEmpty()) {
      throw new IllegalStateException("all cached chunks should be consumed first");
    }

    if (firstTimeSeriesMetadata != null) {
      return true;
    }

    while (firstTimeSeriesMetadata == null
        && (orderUtils.hasNextSeqResource()
            || orderUtils.hasNextUnseqResource()
            || !seqTimeSeriesMetadata.isEmpty()
            || !unSeqTimeSeriesMetadata.isEmpty())) {
      // init first time series metadata whose startTime is minimum
      tryToUnpackAllOverlappedFilesToTimeSeriesMetadata();
      // filter file based on push-down conditions
      filterFirstTimeSeriesMetadata();
    }

    return firstTimeSeriesMetadata != null;
  }
Initialize the query data source. This method should be called <b>before any other methods</b>.

@param dataSource the query data source
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanUtil.java