1#include "duckdb/execution/operator/join/physical_cross_product.hpp"
2
3#include "duckdb/common/vector_operations/vector_operations.hpp"
4
5using namespace duckdb;
6using namespace std;
7
8class PhysicalCrossProductOperatorState : public PhysicalOperatorState {
9public:
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
20PhysicalCrossProduct::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
27void 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
88unique_ptr<PhysicalOperatorState> PhysicalCrossProduct::GetOperatorState() {
89 return make_unique<PhysicalCrossProductOperatorState>(children[0].get(), children[1].get());
90}
91