| From: | Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com> |
|---|---|
| To: | pgsql-hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Cc: | Richard Guo <guofenglinux(at)gmail(dot)com> |
| Subject: | [PATCH] SAOP nullability analysis below NOT/BooleanTest |
| Date: | 2026-07-27 13:09:20 |
| Message-ID: | CAJTYsWV3vqRJmST-gv1NsXEef-zOnjVJpYS910aBaiuMij4nFg@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
While looking at the recent work around converting NOT IN sublinks to
anti-joins, I came across what looks like a possible issue in the
ScalarArrayOpExpr handling in find_nonnullable_rels() and
find_nonnullable_vars().
Both walkers call is_strict_saop(expr, true), even when top_level is
false because the walk has descended below NOT, a BooleanTest, or a
strict function. My understanding is that falseOK = true is suitable
at the top level of a qual, where either FALSE or NULL rejects the row.
Below one of those nodes, however, don't we need the SAOP itself to
return NULL for NULL input?
An empty ANY array seems to expose the distinction:
CREATE TEMP TABLE saop_outer (x int NOT NULL);
CREATE TEMP TABLE saop_inner (y int);
INSERT INTO saop_outer VALUES (1);
INSERT INTO saop_inner VALUES (NULL);
SELECT * FROM saop_outer
WHERE x NOT IN (
SELECT y FROM saop_inner
WHERE NOT (y = ANY ('{}'::int[]))
);
I would expect no rows, since the subquery returns NULL and
1 NOT IN (NULL) is unknown. On current master I get x = 1, with the
query converted to a hash anti-join.
A related outer-join case is:
SELECT saop_outer.*
FROM saop_outer LEFT JOIN saop_inner ON x = y
WHERE (y = ANY ('{}'::int[])) IS FALSE;
I would expect x = 1 from the null-extended row. Current master returns
no rows after reducing the LEFT JOIN to an inner join.
Would it be appropriate to pass top_level as falseOK in both walkers?
That is the small change in the attached patch:
is_strict_saop(expr, top_level)
As far as I can tell, this preserves the existing top-level inference.
Below top level, it only gives up the proof when the array cannot be
shown to be nonempty. I noticed that 72153c0582 added the falseOK
handling to avoid a planning regression for foo <> ALL(array), so I
may be missing a case where using top_level here loses a valid and
important optimization.
Thoughts?
Regards,
Ayush
| Attachment | Content-Type | Size |
|---|---|---|
| 0001-Fix-SAOP-nullability-analysis-below-top-level.patch | application/octet-stream | 3.9 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Aleksander Alekseev | 2026-07-27 13:19:24 | Re: [PATCH] Cover get_json_table_plan() with tests |
| Previous Message | Jonathan Gonzalez V. | 2026-07-27 13:06:34 | Re: [PATCH] Cover get_json_table_plan() with tests |