| 1116 | } |
| 1117 | |
| 1118 | Result<acero::ExecNode*> MakeOrderedSinkNode(acero::ExecPlan* plan, |
| 1119 | std::vector<acero::ExecNode*> inputs, |
| 1120 | const acero::ExecNodeOptions& options) { |
| 1121 | if (inputs.size() != 1) { |
| 1122 | return Status::Invalid("Ordered SinkNode requires exactly 1 input, got ", |
| 1123 | inputs.size()); |
| 1124 | } |
| 1125 | auto input = inputs[0]; |
| 1126 | |
| 1127 | AsyncGenerator<std::optional<compute::ExecBatch>> unordered; |
| 1128 | ARROW_ASSIGN_OR_RAISE(auto node, |
| 1129 | acero::MakeExecNode("sink", plan, std::move(inputs), |
| 1130 | acero::SinkNodeOptions{&unordered})); |
| 1131 | |
| 1132 | const Schema& schema = *input->output_schema(); |
| 1133 | ARROW_ASSIGN_OR_RAISE(FieldPath match, FieldRef("__fragment_index").FindOne(schema)); |
| 1134 | int i = match[0]; |
| 1135 | auto fragment_index = [i](const compute::ExecBatch& batch) { |
| 1136 | return batch.values[i].scalar_as<Int32Scalar>().value; |
| 1137 | }; |
| 1138 | compute::ExecBatch before_any{{}, 0}; |
| 1139 | before_any.values.resize(i + 1); |
| 1140 | before_any.values.back() = Datum(-1); |
| 1141 | |
| 1142 | ARROW_ASSIGN_OR_RAISE(match, FieldRef("__batch_index").FindOne(schema)); |
| 1143 | i = match[0]; |
| 1144 | auto batch_index = [i](const compute::ExecBatch& batch) { |
| 1145 | return batch.values[i].scalar_as<Int32Scalar>().value; |
| 1146 | }; |
| 1147 | |
| 1148 | ARROW_ASSIGN_OR_RAISE(match, FieldRef("__last_in_fragment").FindOne(schema)); |
| 1149 | i = match[0]; |
| 1150 | auto last_in_fragment = [i](const compute::ExecBatch& batch) { |
| 1151 | return batch.values[i].scalar_as<BooleanScalar>().value; |
| 1152 | }; |
| 1153 | |
| 1154 | auto is_before_any = [=](const compute::ExecBatch& batch) { |
| 1155 | return fragment_index(batch) < 0; |
| 1156 | }; |
| 1157 | |
| 1158 | auto left_after_right = [=](const std::optional<compute::ExecBatch>& left, |
| 1159 | const std::optional<compute::ExecBatch>& right) { |
| 1160 | // Before any comes first |
| 1161 | if (is_before_any(*left)) { |
| 1162 | return false; |
| 1163 | } |
| 1164 | if (is_before_any(*right)) { |
| 1165 | return true; |
| 1166 | } |
| 1167 | // Compare batches if fragment is the same |
| 1168 | if (fragment_index(*left) == fragment_index(*right)) { |
| 1169 | return batch_index(*left) > batch_index(*right); |
| 1170 | } |
| 1171 | // Otherwise compare fragment |
| 1172 | return fragment_index(*left) > fragment_index(*right); |
| 1173 | }; |
| 1174 | |
| 1175 | auto is_next = [=](const std::optional<compute::ExecBatch>& prev, |
nothing calls this directly
no test coverage detected