@SuppressWarnings("squid:S3776")
  @Override
  public TsBlock next() throws Exception {

    // make sure we call child.next() at most once
    if (cachedTsBlock.isEmpty() && !tryToGetNextTsBlock()) {
      return null;
    }

    TsBlock tempResult = null;
    while (tempResult == null && !cachedTsBlock.isEmpty()) {
      TsBlock originTsBlock = cachedTsBlock.get(0);
      long currentEndRowIndex =
          cachedRowIndex.get(0) + cachedLastRowIndexForNonNullHelperColumn.get(0);
      // Step 1: judge whether we can fill current TsBlock, if TsBlock that we can get is not
      // enough,
      // we just return null
      for (int columnIndex = 0; columnIndex < outputColumnCount; columnIndex++) {
        // current valueColumn can't be filled using current information
        if (fillArray[columnIndex].needPrepareForNext(
            currentEndRowIndex,
            originTsBlock.getColumn(columnIndex),
            cachedLastRowIndexForNonNullHelperColumn.get(0))) {
          // current cached TsBlock is not enough to fill this column
          while (!isCachedTsBlockEnough(columnIndex, currentEndRowIndex)) {
            // if we failed to get next TsBlock
            if (!tryToGetNextTsBlock()) {
              // there is no more TsBlock for current group, so we have to fill this Column
              if (noMoreTsBlockForCurrentGroup()) {
                // break the while-loop, continue to judge next Column
                break;
              } else {
                // there is still more TsBlock, so current calculation is not finished, and we just
                // return null
                return buildFinalResult(tempResult);
              }
            }
          }
        }
      }
      // Step 2: fill current TsBlock
      originTsBlock = cachedTsBlock.remove(0);
      long startRowIndex = cachedRowIndex.remove(0);
      cachedLastRowIndexForNonNullHelperColumn.remove(0);
      resetFill();

      Column[] columns = new Column[outputColumnCount];
      for (int i = 0; i < outputColumnCount; i++) {
        columns[i] =
            fillArray[i].fill(
                getHelperColumn(originTsBlock), originTsBlock.getColumn(i), startRowIndex);
      }
      tempResult = append(originTsBlock.getPositionCount(), originTsBlock.getTimeColumn(), columns);
      for (int i = 0; i < outputColumnCount; i++) {
        // make sure nextTsBlockIndex for each column >= 1
        nextTsBlockIndex[i] = Math.max(1, nextTsBlockIndex[i] - 1);
      }
    }
    return buildFinalResult(tempResult);
  }
indicate whether we can call child.next(). it's used to make sure that child.next() will only
be called once in AbstractLinearFillOperator.next().
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/AbstractLinearFillOperator.java