class_docstr: Apply the function expression to the input data, merge the output of the function
  with the input data, and yield the result to the parent. The current implementation
  assumes an inner join while merging. Therefore, if the function does not return any
  output, the input rows are dropped.
  Arguments:
      node (AbstractPlan): ApplyAndMergePlan
code: def exec(self, *args, **kwargs) -> Iterator[Batch]:
      child_executor = self.children[0]
      for batch in child_executor.exec(**kwargs):
          func_result = self.func_expr.evaluate(batch)
  
          output = Batch.merge_column_wise([batch, func_result])
          if self.do_unnest:
              output.unnest(func_result.columns)
              # we reset the index as after unnest there can be duplicate index
              output.reset_index()
  
          yield output
  
      # persist stats of function expression
      instrument_function_expression_cost(
          self.func_expr, self.catalog()
      )
  
file_path: evadb/evadb/executor/apply_and_merge_executor.py
imports: from typing import Iterator
  from evadb.database import EvaDBDatabase
  from evadb.executor.abstract_executor import AbstractExecutor
  from evadb.executor.executor_utils import instrument_function_expression_cost
  from evadb.models.storage.batch import Batch
  from evadb.plan_nodes.apply_and_merge_plan import ApplyAndMergePlan
label_desc: Use image node_id 2 for calling the ApplyAndMergeExecutor obj's underlying member method code with example usage: obj.exec() without return types