Re: BUG #19007: Planner fails to choose partial index with spurious 'not null'

Richard Guo <guofenglinux@gmail.com>

From: Richard Guo <guofenglinux@gmail.com>
To: David Rowley <dgrowleyml@gmail.com>
Cc: Tom Lane <tgl@sss.pgh.pa.us>, bryfox@gmail.com, pgsql-bugs@lists.postgresql.org
Date: 2025-08-04T09:14:32Z
Lists: pgsql-bugs

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Fix const-simplification for index expressions and predicate

  2. Fix const-simplification for constraints and stats

On Mon, Aug 4, 2025 at 1:29 PM David Rowley <dgrowleyml@gmail.com> wrote:
> I guess it doesn't because in RelationGetIndexPredicate(), the call to
> eval_const_expressions() passes NULL for the PlannerInfo, resulting in
> the NOT NULL information not being available during
> eval_const_expressions().

Exactly.  The comment of eval_const_expressions also notes that when
"root" is NULL, NullTest quals will not be reduced.

 * NOTE: "root" can be passed as NULL if the caller never wants to do any
 * Param substitutions nor receive info about inlined functions nor reduce
 * NullTest for Vars to constant true or constant false.

> Looks like we keep the indpred varnos as 1 during
> RelationGetIndexPredicate() and only change them to the actual varno
> of the relation after that call inside get_relation_info(), so it
> wouldn't be valid to pass the PlannerInfo down without first rewriting
> the varnos and it doesn't seem correct to rewrite the varnos in the
> relcache code.

Yeah.  And in addition, the fact that we cache the pg_index.indpred in
the relcache entry means that we cannot rewrite the varnos within
RelationGetIndexPredicate().

> Seems like what it would take to make this work is *another* call to
> eval_const_expressions() inside get_relation_info() just after the
> varnos have been changed.

I wonder if we could move const-simplification and canonicalization of
index predicates out of RelationGetIndexPredicate() and into its
callers, after the varnos have been updated.  That would require
changing every caller, though.


BTW, I wonder if we should also be concerned about index expressions,
in cases like:

create table t (a int, b int not null);
create index on t ((b is not null));
explain select * from t where b is not null;

Thanks
Richard