Execute nested loop join
(
&self,
join_type: &crate::plan::logical::JoinType,
condition: Option<&Expression>,
left: &PhysicalNode,
right: &PhysicalNode,
context: &mut ExecutionC
| 3749 | |
| 3750 | /// Execute nested loop join |
| 3751 | fn execute_nested_loop_join( |
| 3752 | &self, |
| 3753 | join_type: &crate::plan::logical::JoinType, |
| 3754 | condition: Option<&Expression>, |
| 3755 | left: &PhysicalNode, |
| 3756 | right: &PhysicalNode, |
| 3757 | context: &mut ExecutionContext, |
| 3758 | graph: &Arc<GraphCache>, |
| 3759 | ) -> Result<Vec<Row>, ExecutionError> { |
| 3760 | // Execute left and right inputs |
| 3761 | let left_rows = self.execute_node_with_graph(left, context, graph)?; |
| 3762 | let right_rows = self.execute_node_with_graph(right, context, graph)?; |
| 3763 | |
| 3764 | let mut result_rows = Vec::new(); |
| 3765 | |
| 3766 | // Nested loop join implementation |
| 3767 | for left_row in &left_rows { |
| 3768 | for right_row in &right_rows { |
| 3769 | // Create combined row |
| 3770 | let mut combined_row = Row::new(); |
| 3771 | |
| 3772 | // Add all variables from left row |
| 3773 | for (key, value) in &left_row.values { |
| 3774 | combined_row.values.insert(key.clone(), value.clone()); |
| 3775 | } |
| 3776 | |
| 3777 | // Add all variables from right row |
| 3778 | for (key, value) in &right_row.values { |
| 3779 | combined_row.values.insert(key.clone(), value.clone()); |
| 3780 | } |
| 3781 | |
| 3782 | // Preserve text search metadata from left row (Week 6.3) |
| 3783 | // Left row takes precedence for metadata in joins |
| 3784 | if let Some(score) = left_row.get_text_score() { |
| 3785 | combined_row.set_text_score(score); |
| 3786 | // Also preserve TEXT_SCORE() pseudo-column for ORDER BY support |
| 3787 | combined_row |
| 3788 | .values |
| 3789 | .insert("TEXT_SCORE()".to_string(), Value::Number(score)); |
| 3790 | } |
| 3791 | if let Some(snippet) = left_row.get_highlight_snippet() { |
| 3792 | combined_row.set_highlight_snippet(snippet.to_string()); |
| 3793 | } |
| 3794 | |
| 3795 | // Check join condition if present |
| 3796 | let matches_condition = if let Some(cond) = condition { |
| 3797 | // Set up context with combined row for condition evaluation |
| 3798 | let mut temp_context = context.clone(); |
| 3799 | for (key, value) in &combined_row.values { |
| 3800 | temp_context.set_variable(key.clone(), value.clone()); |
| 3801 | } |
| 3802 | |
| 3803 | match self.evaluate_expression(cond, &temp_context) { |
| 3804 | Ok(Value::Boolean(b)) => b, |
| 3805 | Ok(_) => false, // Non-boolean results are treated as false |
| 3806 | Err(_) => false, // Errors are treated as false |
| 3807 | } |
| 3808 | } else { |
no test coverage detected