diff --git a/core/translate/optimizer/constraints.rs b/core/translate/optimizer/constraints.rs index f0e5d54bc..b10c6cb8b 100644 --- a/core/translate/optimizer/constraints.rs +++ b/core/translate/optimizer/constraints.rs @@ -319,7 +319,7 @@ pub fn usable_constraints_for_join_order<'a>( if other_side_refers_to_self { break; } - let lhs_mask = TableMask::from_iter( + let lhs_mask = TableMask::from_table_number_iter( join_order .iter() .take(join_order.len() - 1) diff --git a/core/translate/optimizer/join.rs b/core/translate/optimizer/join.rs index a0805a287..36d11b967 100644 --- a/core/translate/optimizer/join.rs +++ b/core/translate/optimizer/join.rs @@ -66,7 +66,7 @@ pub fn join_lhs_and_rhs<'a>( best_access_methods.push(access_methods_arena.borrow().len() - 1); let lhs_mask = lhs.map_or(TableMask::new(), |l| { - TableMask::from_iter(l.table_numbers.iter().cloned()) + TableMask::from_table_number_iter(l.table_numbers.iter().cloned()) }); // Output cardinality is reduced by the product of the selectivities of the constraints that can be used with this join order. let output_cardinality_multiplier = rhs_constraints diff --git a/core/translate/planner.rs b/core/translate/planner.rs index decf44549..c6326bac2 100644 --- a/core/translate/planner.rs +++ b/core/translate/planner.rs @@ -588,6 +588,24 @@ pub fn determine_where_to_eval_term( return determine_where_to_eval_expr(&term.expr, join_order); } +/// A bitmask representing a set of tables in a query plan. +/// Tables are numbered by their index in [SelectPlan::table_references]. +/// In the bitmask, the first bit is unused so that a mask with all zeros +/// can represent "no tables". +/// +/// E.g. table 0 is represented by bit index 1, table 1 by bit index 2, etc. +/// +/// Usage in Join Optimization +/// +/// In join optimization, [TableMask] is used to: +/// - Generate subsets of tables for dynamic programming in join optimization +/// - Ensure tables are joined in valid orders (e.g., respecting LEFT JOIN order) +/// +/// Usage with constraints (WHERE clause) +/// +/// [TableMask] helps determine: +/// - Which tables are referenced in a constraint +/// - When a constraint can be applied as a join condition (all referenced tables must be on the left side of the table being joined) #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TableMask(pub u128); @@ -598,24 +616,33 @@ impl std::ops::BitOrAssign for TableMask { } impl TableMask { + /// Creates a new empty table mask. + /// + /// The initial mask represents an empty set of tables. pub fn new() -> Self { Self(0) } + /// Returns true if the mask represents an empty set of tables. pub fn is_empty(&self) -> bool { self.0 == 0 } + /// Creates a new mask that is the same as this one but without the specified table. pub fn without_table(&self, table_no: usize) -> Self { assert!(table_no < 127, "table_no must be less than 127"); Self(self.0 ^ (1 << (table_no + 1))) } + /// Creates a table mask from raw bits. + /// + /// The bits are shifted left by 1 to maintain the convention that table 0 is at bit 1. pub fn from_bits(bits: u128) -> Self { Self(bits << 1) } - pub fn from_iter(iter: impl Iterator) -> Self { + /// Creates a table mask from an iterator of table numbers. + pub fn from_table_number_iter(iter: impl Iterator) -> Self { iter.fold(Self::new(), |mut mask, table_no| { assert!(table_no < 127, "table_no must be less than 127"); mask.add_table(table_no); @@ -623,29 +650,36 @@ impl TableMask { }) } + /// Adds a table to the mask. pub fn add_table(&mut self, table_no: usize) { assert!(table_no < 127, "table_no must be less than 127"); self.0 |= 1 << (table_no + 1); } + /// Returns true if the mask contains the specified table. pub fn contains_table(&self, table_no: usize) -> bool { assert!(table_no < 127, "table_no must be less than 127"); self.0 & (1 << (table_no + 1)) != 0 } + /// Returns true if this mask contains all tables in the other mask. pub fn contains_all(&self, other: &TableMask) -> bool { self.0 & other.0 == other.0 } + /// Returns the number of tables in the mask. pub fn table_count(&self) -> usize { self.0.count_ones() as usize } + /// Returns true if this mask shares any tables with the other mask. pub fn intersects(&self, other: &TableMask) -> bool { self.0 & other.0 != 0 } } +/// Returns a [TableMask] representing the tables referenced in the given expression. +/// Used in the optimizer for constraint analysis. pub fn table_mask_from_expr(expr: &Expr) -> Result { let mut mask = TableMask::new(); match expr {