Execute UNION operation
(
&self,
left: QueryResult,
right: QueryResult,
distinct: bool,
)
| 7653 | |
| 7654 | /// Execute UNION operation |
| 7655 | fn execute_union( |
| 7656 | &self, |
| 7657 | left: QueryResult, |
| 7658 | right: QueryResult, |
| 7659 | distinct: bool, |
| 7660 | ) -> Result<QueryResult, ExecutionError> { |
| 7661 | // Check if we should use identity-based or value-based comparison |
| 7662 | let use_identity = left.rows.iter().any(|r| r.has_entities()) |
| 7663 | || right.rows.iter().any(|r| r.has_entities()); |
| 7664 | |
| 7665 | let mut result_rows = Vec::new(); |
| 7666 | let target_variables; |
| 7667 | |
| 7668 | if use_identity { |
| 7669 | // Identity-based UNION: combine rows and optionally deduplicate by entity identity |
| 7670 | // Don't convert to positional - preserve source_entities |
| 7671 | target_variables = if left.variables.is_empty() && !right.variables.is_empty() { |
| 7672 | right.variables.clone() |
| 7673 | } else { |
| 7674 | left.variables.clone() |
| 7675 | }; |
| 7676 | |
| 7677 | // Add all left rows |
| 7678 | result_rows.extend(left.rows); |
| 7679 | |
| 7680 | // Handle UNION vs UNION ALL |
| 7681 | // Note: 'distinct' parameter is 'keep_all' - true for UNION ALL, false for UNION |
| 7682 | if distinct { |
| 7683 | // UNION ALL: Keep all rows, no deduplication |
| 7684 | result_rows.extend(right.rows); |
| 7685 | } else { |
| 7686 | // UNION: Deduplicate by identity |
| 7687 | for right_row in right.rows { |
| 7688 | if !right_row.has_entities() { |
| 7689 | // No entities, add unconditionally |
| 7690 | result_rows.push(right_row); |
| 7691 | continue; |
| 7692 | } |
| 7693 | |
| 7694 | // Check if this entity already exists in result |
| 7695 | let mut found = false; |
| 7696 | for result_row in &result_rows { |
| 7697 | if result_row.has_entities() |
| 7698 | && self.rows_equal_by_identity(&right_row, result_row) |
| 7699 | { |
| 7700 | found = true; |
| 7701 | break; |
| 7702 | } |
| 7703 | } |
| 7704 | |
| 7705 | if !found { |
| 7706 | result_rows.push(right_row); |
| 7707 | } |
| 7708 | } |
| 7709 | } |
| 7710 | } else { |
| 7711 | // Value-based UNION: convert to positional format for proper set operation semantics |
| 7712 | // Choose target variables from the non-empty side for alignment |
no test coverage detected