@Override
  public List<ByteString> getNextRows(int fetchRowNum) throws IOException {
    List<ByteString> rows = new ArrayList<ByteString>();
    int startRow = currentRow;
    int endRow = startRow + fetchRowNum;

    if (physicalExec == null) {
      return rows;
    }

    while (currentRow < endRow) {
      Tuple currentTuple = physicalExec.next();

      if (currentTuple == null) {
        physicalExec.close();
        physicalExec = null;
        break;
      }

      currentRow++;
      rows.add(ByteString.copyFrom(encoder.toBytes(currentTuple)));

      if (currentRow >= maxRow) {
        physicalExec.close();
        physicalExec = null;
        break;
      }
    }

    return rows;
  }
  @Override
  public void init() throws IOException {
    QueryContext queryContext = new QueryContext(masterContext.getConf());
    currentRow = 0;

    MasterPlan masterPlan = new MasterPlan(queryId, queryContext, logicalPlan);
    GlobalPlanner globalPlanner =
        new GlobalPlanner(masterContext.getConf(), masterContext.getCatalog());
    try {
      globalPlanner.build(queryContext, masterPlan);
    } catch (PlanningException e) {
      throw new RuntimeException(e);
    }

    ExecutionBlockCursor cursor = new ExecutionBlockCursor(masterPlan);
    ExecutionBlock leafBlock = null;
    for (ExecutionBlock block : cursor) {
      if (masterPlan.isLeaf(block)) {
        leafBlock = block;
        break;
      }
    }

    if (leafBlock == null) {
      throw new InvalidQueryException("Global planner could not find any leaf block.");
    }

    taskContext =
        new TaskAttemptContext(
            queryContext, null, new TaskAttemptId(new TaskId(leafBlock.getId(), 0), 0), null, null);
    physicalExec =
        new SimplePhysicalPlannerImpl(masterContext.getConf())
            .createPlan(taskContext, leafBlock.getPlan());

    tableDesc =
        new TableDesc(
            "table_" + System.currentTimeMillis(),
            physicalExec.getSchema(),
            new TableMeta("SYSTEM", new KeyValueSet()),
            null);
    outSchema = physicalExec.getSchema();
    encoder = RowStoreUtil.createEncoder(getLogicalSchema());

    physicalExec.init();
  }
 @Override
 public void close() throws Exception {
   tableDesc = null;
   outSchema = null;
   encoder = null;
   if (physicalExec != null) {
     try {
       physicalExec.close();
     } catch (Exception ignored) {
     }
   }
   physicalExec = null;
   currentRow = -1;
 }