| 225 | } |
| 226 | |
| 227 | Status ScalarAggregateNode::InputReceived(ExecNode* input, ExecBatch batch) { |
| 228 | auto scope = TraceInputReceived(batch); |
| 229 | DCHECK_EQ(input, inputs_[0]); |
| 230 | |
| 231 | auto thread_index = plan_->query_context()->GetThreadIndex(); |
| 232 | auto handler = [this, thread_index](const ExecBatch& full_batch, |
| 233 | const Segment& segment) { |
| 234 | // (1) The segment is starting of a new segment group and points to |
| 235 | // the beginning of the batch, then it means no data in the batch belongs |
| 236 | // to the current segment group. We can output and reset kernel states. |
| 237 | if (!segment.extends && segment.offset == 0) |
| 238 | RETURN_NOT_OK(OutputResult(/*is_last=*/false)); |
| 239 | |
| 240 | // We add segment to the current segment group aggregation |
| 241 | auto exec_batch = full_batch.Slice(segment.offset, segment.length); |
| 242 | RETURN_NOT_OK(DoConsume(ExecSpan(exec_batch), thread_index)); |
| 243 | RETURN_NOT_OK( |
| 244 | ExtractSegmenterValues(&segmenter_values_, exec_batch, segment_field_ids_)); |
| 245 | |
| 246 | // If the segment closes the current segment group, we can output segment group |
| 247 | // aggregation. |
| 248 | if (!segment.is_open) RETURN_NOT_OK(OutputResult(/*is_last=*/false)); |
| 249 | |
| 250 | return Status::OK(); |
| 251 | }; |
| 252 | RETURN_NOT_OK(HandleSegments(segmenter_.get(), batch, segment_field_ids_, handler)); |
| 253 | |
| 254 | if (input_counter_.Increment()) { |
| 255 | RETURN_NOT_OK(OutputResult(/*is_last=*/true)); |
| 256 | } |
| 257 | return Status::OK(); |
| 258 | } |
| 259 | |
| 260 | Status ScalarAggregateNode::InputFinished(ExecNode* input, int total_batches) { |
| 261 | auto scope = TraceFinish(); |
no test coverage detected