gitql_engine/
engine_join.rs1use std::collections::HashMap;
2
3use gitql_ast::statement::Join;
4use gitql_ast::statement::JoinKind;
5use gitql_ast::statement::JoinOperand;
6use gitql_ast::statement::TableSelection;
7use gitql_core::environment::Environment;
8use gitql_core::object::Row;
9use gitql_core::values::boolean::BoolValue;
10use gitql_core::values::null::NullValue;
11use gitql_core::values::Value;
12
13use crate::engine_evaluator::evaluate_expression;
14
15#[inline(always)]
16pub(crate) fn apply_join_operation(
17 env: &mut Environment,
18 all_rows: &mut Vec<Row>,
19 joins: &Vec<Join>,
20 tables_selections: &Vec<TableSelection>,
21 selected_rows_per_table: &mut HashMap<String, Vec<Row>>,
22 hidden_selection_per_table: &HashMap<String, usize>,
23 titles: &[String],
24) -> Result<(), String> {
25 if joins.is_empty() {
27 for table_selection in tables_selections {
28 let table_rows = selected_rows_per_table
29 .get_mut(&table_selection.table_name)
30 .unwrap();
31 all_rows.append(table_rows);
32 }
33 return Ok(());
34 }
35
36 let mut current_tables_rows: Vec<Row> = vec![];
37 let mut all_rows_hidden_count = 0;
38
39 for join in joins {
41 let mut current_join_rows: Vec<Row> = vec![];
42
43 let left_rows: &Vec<Row>;
44 let left_hidden_count: usize;
45
46 let right_rows: &Vec<Row>;
47 let right_hidden_count: usize;
48
49 match &join.operand {
50 JoinOperand::OuterAndInner(outer, inner) => {
51 left_hidden_count = *hidden_selection_per_table.get(outer).unwrap_or(&0);
52 right_hidden_count = *hidden_selection_per_table.get(inner).unwrap_or(&0);
53 all_rows_hidden_count += left_hidden_count + right_hidden_count;
54
55 left_rows = selected_rows_per_table.get(outer).unwrap();
56 right_rows = selected_rows_per_table.get(inner).unwrap();
57 }
58
59 JoinOperand::Inner(inner) => {
60 left_hidden_count = all_rows_hidden_count;
61 right_hidden_count = *hidden_selection_per_table.get(inner).unwrap_or(&0);
62 all_rows_hidden_count += right_hidden_count;
63
64 left_rows = ¤t_tables_rows;
65 right_rows = selected_rows_per_table.get(inner).unwrap();
66 }
67 }
68
69 if join.kind == JoinKind::Cross && (left_rows.is_empty() || right_rows.is_empty()) {
71 continue;
72 }
73
74 for outer in left_rows {
76 for inner in right_rows {
77 let row_len = outer.values.len() + inner.values.len();
78 let mut joined_row: Vec<Box<dyn Value>> = Vec::with_capacity(row_len);
79 joined_row.append(&mut outer.values.clone());
80
81 let inner_rows = inner.values.clone();
82 let inner_hidden_values = &inner_rows[0..right_hidden_count];
83 joined_row.splice(
84 left_hidden_count..left_hidden_count,
85 inner_hidden_values.to_vec(),
86 );
87
88 let inner_other_values = &inner_rows[right_hidden_count..];
89 joined_row.extend_from_slice(inner_other_values);
90
91 if let Some(predicate) = &join.predicate {
93 let predicate_value = evaluate_expression(env, predicate, titles, &joined_row)?;
94 if let Some(bool_value) = predicate_value.as_any().downcast_ref::<BoolValue>() {
95 if bool_value.value {
96 current_join_rows.push(Row { values: joined_row });
97 continue;
98 }
99 }
100
101 match join.kind {
105 JoinKind::Left => {
106 let mut left_joined_row: Vec<Box<dyn Value>> =
107 Vec::with_capacity(row_len);
108 left_joined_row.append(&mut outer.values.clone());
110 for _ in 0..inner.values.len() {
112 left_joined_row.push(Box::new(NullValue));
113 }
114 }
115 JoinKind::Right => {
116 let mut right_joined_row: Vec<Box<dyn Value>> =
117 Vec::with_capacity(row_len);
118 for _ in 0..outer.values.len() {
120 right_joined_row.push(Box::new(NullValue));
121 }
122 right_joined_row.append(&mut inner.values.clone());
124 }
125 _ => {}
126 }
127 continue;
128 }
129
130 current_join_rows.push(Row { values: joined_row });
132 }
133 }
134
135 current_tables_rows.clear();
137 current_tables_rows.append(&mut current_join_rows);
139 }
140
141 all_rows.append(&mut current_tables_rows);
143
144 Ok(())
145}