use super::*;
pub(super) struct KeyRange {
pub(super) low: Option<RangeBound>,
pub(super) high: Option<RangeBound>,
pub(super) collation: Collation,
pub(super) descending: bool,
pub(super) column: u16,
}
pub(super) fn key_range(
context: &CandidateContext<'_>,
key_column: &crate::catalog_view::IndexColumnInfo,
used: &mut Vec<usize>,
) -> Option<KeyRange> {
let column = key_column.column?;
let collation = collation_of(&key_column.collation);
let mut low = None;
let mut high = None;
for (term_index, term) in context.terms.iter().enumerate() {
let taken = context.consumed.get(term_index).copied().unwrap_or(false);
if taken || used.contains(&term_index) {
continue;
}
if let Some((low_bound, high_bound)) =
pattern::pattern_range(context.id, column, term, collation, key_column.descending)
{
if low.is_none() && high.is_none() {
low = low_bound;
high = high_bound;
}
continue;
}
let Some((op, value)) = indexable_comparison(context.id, column, term) else {
continue;
};
if !is_available(context.position, context.ids, &value)
|| comparison_collation(term) != collation
{
continue;
}
let Some((kind, at_low)) = walk_bound(op, key_column.descending) else {
continue;
};
let slot = if at_low { &mut low } else { &mut high };
if slot.is_none() {
*slot = Some(RangeBound {
kind,
value,
unconverted: compares_unconverted(term),
});
used.push(term_index);
}
}
if low.is_none() && high.is_none() {
return None;
}
Some(KeyRange {
low,
high,
collation,
descending: key_column.descending,
column,
})
}
fn walk_bound(op: BinaryOp, descending: bool) -> Option<(BoundKind, bool)> {
Some(match (op, descending) {
(BinaryOp::Greater, false) => (BoundKind::Greater, true),
(BinaryOp::GreaterEqual, false) => (BoundKind::GreaterEqual, true),
(BinaryOp::Less, false) => (BoundKind::Less, false),
(BinaryOp::LessEqual, false) => (BoundKind::LessEqual, false),
(BinaryOp::Greater, true) => (BoundKind::Less, false),
(BinaryOp::GreaterEqual, true) => (BoundKind::LessEqual, false),
(BinaryOp::Less, true) => (BoundKind::Greater, true),
(BinaryOp::LessEqual, true) => (BoundKind::GreaterEqual, true),
_ => return None,
})
}