| 1 | #include "duckdb/execution/operator/join/physical_cross_product.hpp" |
| 2 | |
| 3 | #include "duckdb/common/vector_operations/vector_operations.hpp" |
| 4 | |
| 5 | using namespace duckdb; |
| 6 | using namespace std; |
| 7 | |
| 8 | class PhysicalCrossProductOperatorState : public PhysicalOperatorState { |
| 9 | public: |
| 10 | PhysicalCrossProductOperatorState(PhysicalOperator *left, PhysicalOperator *right) |
| 11 | : PhysicalOperatorState(left), left_position(0) { |
| 12 | assert(left && right); |
| 13 | } |
| 14 | |
| 15 | idx_t left_position; |
| 16 | idx_t right_position; |
| 17 | ChunkCollection right_data; |
| 18 | }; |
| 19 | |
| 20 | PhysicalCrossProduct::PhysicalCrossProduct(LogicalOperator &op, unique_ptr<PhysicalOperator> left, |
| 21 | unique_ptr<PhysicalOperator> right) |
| 22 | : PhysicalOperator(PhysicalOperatorType::CROSS_PRODUCT, op.types) { |
| 23 | children.push_back(move(left)); |
| 24 | children.push_back(move(right)); |
| 25 | } |
| 26 | |
| 27 | void PhysicalCrossProduct::GetChunkInternal(ClientContext &context, DataChunk &chunk, PhysicalOperatorState *state_) { |
| 28 | auto state = reinterpret_cast<PhysicalCrossProductOperatorState *>(state_); |
| 29 | // first we fully materialize the right child, if we haven't done that yet |
| 30 | if (state->right_data.column_count() == 0) { |
| 31 | auto right_state = children[1]->GetOperatorState(); |
| 32 | auto types = children[1]->GetTypes(); |
| 33 | |
| 34 | DataChunk new_chunk; |
| 35 | new_chunk.Initialize(types); |
| 36 | do { |
| 37 | children[1]->GetChunk(context, new_chunk, right_state.get()); |
| 38 | if (new_chunk.size() == 0) { |
| 39 | break; |
| 40 | } |
| 41 | state->right_data.Append(new_chunk); |
| 42 | } while (new_chunk.size() > 0); |
| 43 | |
| 44 | if (state->right_data.count == 0) { |
| 45 | return; |
| 46 | } |
| 47 | state->left_position = 0; |
| 48 | state->right_position = 0; |
| 49 | children[0]->GetChunk(context, state->child_chunk, state->child_state.get()); |
| 50 | state->child_chunk.Normalify(); |
| 51 | } |
| 52 | |
| 53 | if (state->left_position >= state->child_chunk.size()) { |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | auto &left_chunk = state->child_chunk; |
| 58 | auto &right_chunk = *state->right_data.chunks[state->right_position]; |
| 59 | // now match the current row of the left relation with the current chunk |
| 60 | // from the right relation |
| 61 | chunk.SetCardinality(right_chunk.size()); |
| 62 | for (idx_t i = 0; i < left_chunk.column_count(); i++) { |
| 63 | // first duplicate the values of the left side |
| 64 | auto lvalue = left_chunk.GetValue(i, state->left_position); |
| 65 | chunk.data[i].Reference(lvalue); |
| 66 | } |
| 67 | for (idx_t i = 0; i < right_chunk.column_count(); i++) { |
| 68 | // now create a reference to the vectors of the right chunk |
| 69 | chunk.data[left_chunk.column_count() + i].Reference(right_chunk.data[i]); |
| 70 | } |
| 71 | |
| 72 | // for the next iteration, move to the next position on the left side |
| 73 | state->left_position++; |
| 74 | if (state->left_position >= state->child_chunk.size()) { |
| 75 | // ran out of this chunk |
| 76 | // move to the next chunk on the right side |
| 77 | state->left_position = 0; |
| 78 | state->right_position++; |
| 79 | if (state->right_position >= state->right_data.chunks.size()) { |
| 80 | state->right_position = 0; |
| 81 | // move to the next chunk on the left side |
| 82 | children[0]->GetChunk(context, state->child_chunk, state->child_state.get()); |
| 83 | state->child_chunk.Normalify(); |
| 84 | } |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | unique_ptr<PhysicalOperatorState> PhysicalCrossProduct::GetOperatorState() { |
| 89 | return make_unique<PhysicalCrossProductOperatorState>(children[0].get(), children[1].get()); |
| 90 | } |
| 91 | |