| 608 | } |
| 609 | |
| 610 | Status AnalyticEvalNode::ProcessChildBatches(RuntimeState* state) { |
| 611 | // Consume child batches until eos or there are enough rows to return more than an |
| 612 | // output batch. Ensuring there is at least one more row left after returning results |
| 613 | // allows us to simplify the logic dealing with last_result_idx_ and result_tuples_. |
| 614 | while (!input_eos_ && NumOutputRowsReady() < state->batch_size() + 1) { |
| 615 | RETURN_IF_CANCELLED(state); |
| 616 | if (has_partition_or_order_by_expr_eval() && prev_input_tuple_ != nullptr |
| 617 | && curr_child_batch_->num_rows() > 0) { |
| 618 | // 'prev_input_tuple_' is from the last row in 'curr_child_batch_' and is needed |
| 619 | // by subsequent calls to ProcessChildBatch(). Deep copy it so that we can safely |
| 620 | // free the memory backing it. 'prev_input_tuple_pool_' is not backing the previous |
| 621 | // input tuple any more - it is from the last row in 'curr_child_batch_' and |
| 622 | // therefore backed by 'curr_child_batch_'. |
| 623 | prev_input_tuple_pool_->Clear(); |
| 624 | prev_input_tuple_ = prev_input_tuple_->DeepCopy( |
| 625 | *child(0)->row_desc()->tuple_descriptors()[0], prev_input_tuple_pool_.get()); |
| 626 | } |
| 627 | curr_child_batch_->Reset(); |
| 628 | RETURN_IF_ERROR(child(0)->GetNext(state, curr_child_batch_.get(), &input_eos_)); |
| 629 | RETURN_IF_ERROR(QueryMaintenance(state)); |
| 630 | RETURN_IF_ERROR(ProcessChildBatch(state)); |
| 631 | // TODO: DCHECK that the size of result_tuples_ is bounded. It shouldn't be larger |
| 632 | // than 2x the batch size unless the end bound has an offset preceding, in which |
| 633 | // case it may be slightly larger (proportional to the offset but still bounded). |
| 634 | } |
| 635 | return Status::OK(); |
| 636 | } |
| 637 | |
| 638 | Status AnalyticEvalNode::ProcessChildBatch(RuntimeState* state) { |
| 639 | // TODO: DCHECK input is sorted (even just first row vs prev_input_tuple_) |