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 | |