Decide whether the query's WHERE conjuncts entail the partial-index predicate. `None` predicate means a full index — trivially entailed. Initial version uses conjunct-level structural equality: every conjunct of the index predicate must appear (by `PartialEq`) as a conjunct of the query. This is conservative and deliberately so — a false positive here would silently omit rows from query results.
(predicate: Option<&str>, query_conjuncts: &[SqlExpr])
| 372 | /// conjunct of the query. This is conservative and deliberately so — |
| 373 | /// a false positive here would silently omit rows from query results. |
| 374 | fn partial_index_entailed(predicate: Option<&str>, query_conjuncts: &[SqlExpr]) -> bool { |
| 375 | let Some(text) = predicate else { |
| 376 | return true; |
| 377 | }; |
| 378 | let Ok(parsed) = crate::parse_expr_string(text) else { |
| 379 | // A catalog predicate we can't parse is not entailed — refuse |
| 380 | // to use the index rather than assume anything about its |
| 381 | // contents. The DDL path validates at CREATE INDEX time, so |
| 382 | // reaching this branch indicates drift. |
| 383 | return false; |
| 384 | }; |
| 385 | let mut index_conjuncts: Vec<SqlExpr> = Vec::new(); |
| 386 | flatten_and(&parsed, &mut index_conjuncts); |
| 387 | // Structural equality via the stable `Debug` representation: |
| 388 | // `SqlExpr` doesn't derive `PartialEq` (several nested variants |
| 389 | // carry types that can't derive it cheaply), but the Debug form is |
| 390 | // canonical for equivalent trees produced by the same parser. This |
| 391 | // is conservative — it matches only identical AST shapes and not, |
| 392 | // e.g., `a = 1` vs `1 = a`. Callers should write index predicates |
| 393 | // in the same normal form they use in query WHERE clauses, which |
| 394 | // is the convention everywhere else in the codebase. |
| 395 | index_conjuncts.iter().all(|ic| { |
| 396 | let ic_dbg = format!("{ic:?}"); |
| 397 | query_conjuncts.iter().any(|qc| format!("{qc:?}") == ic_dbg) |
| 398 | }) |
| 399 | } |
| 400 | |
| 401 | fn is_column_eq_literal(expr: &SqlExpr) -> bool { |
| 402 | matches!( |
no test coverage detected