Execute EXCEPT operation
(
&self,
left: QueryResult,
right: QueryResult,
distinct: bool,
)
| 7934 | |
| 7935 | /// Execute EXCEPT operation |
| 7936 | fn execute_except( |
| 7937 | &self, |
| 7938 | left: QueryResult, |
| 7939 | right: QueryResult, |
| 7940 | distinct: bool, |
| 7941 | ) -> Result<QueryResult, ExecutionError> { |
| 7942 | use std::collections::HashSet; |
| 7943 | |
| 7944 | // Check if we should use identity-based or value-based comparison |
| 7945 | let use_identity = left.rows.iter().any(|r| r.has_entities()) |
| 7946 | || right.rows.iter().any(|r| r.has_entities()); |
| 7947 | |
| 7948 | let mut result_rows = Vec::new(); |
| 7949 | |
| 7950 | if use_identity { |
| 7951 | // Identity-based EXCEPT: remove rows from left that match by entity identity in right |
| 7952 | // Don't convert to positional - preserve source_entities |
| 7953 | for left_row in left.rows { |
| 7954 | if !left_row.has_entities() { |
| 7955 | // No entities, keep it (can't match by identity) |
| 7956 | result_rows.push(left_row); |
| 7957 | continue; |
| 7958 | } |
| 7959 | |
| 7960 | // Check if this left row's entity exists in right |
| 7961 | let mut found_in_right = false; |
| 7962 | for right_row in &right.rows { |
| 7963 | if right_row.has_entities() && self.rows_equal_by_identity(&left_row, right_row) |
| 7964 | { |
| 7965 | found_in_right = true; |
| 7966 | break; |
| 7967 | } |
| 7968 | } |
| 7969 | |
| 7970 | // Only keep if NOT found in right |
| 7971 | if !found_in_right { |
| 7972 | result_rows.push(left_row); |
| 7973 | } |
| 7974 | } |
| 7975 | |
| 7976 | // Note: For identity-based EXCEPT, 'distinct' is handled by identity uniqueness |
| 7977 | } else { |
| 7978 | // Value-based EXCEPT: convert to positional format for proper set operation semantics |
| 7979 | let left_positional = self.convert_to_positional_rows(left.rows, &left.variables); |
| 7980 | let right_positional = self.convert_to_positional_rows_aligned( |
| 7981 | right.rows, |
| 7982 | &right.variables, |
| 7983 | &left.variables, |
| 7984 | ); |
| 7985 | |
| 7986 | let right_set: HashSet<Row> = right_positional.into_iter().collect(); |
| 7987 | |
| 7988 | for row in left_positional { |
| 7989 | if !right_set.contains(&row) { |
| 7990 | result_rows.push(row); |
| 7991 | } |
| 7992 | } |
| 7993 |
no test coverage detected