| From: | Tomas Vondra <tomas(at)vondra(dot)me> |
|---|---|
| To: | Kirill Reshke <reshkekirill(at)gmail(dot)com> |
| Cc: | Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org> |
| Subject: | Re: reconsider_full_join_clause fails to consider if COALESCE() arguments are NULL-preserving |
| Date: | 2026-11-12 09:26:19 |
| Message-ID: | cbba497d-dfea-4a43-89a5-1a9f4be676d0@vondra.me |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On 11/12/26 10:22, Tomas Vondra wrote:
>
> On 11/12/26 07:38, Kirill Reshke wrote:
>> On Thu, 12 Nov 2026 at 02:48, Tomas Vondra <tomas(at)vondra(dot)me> wrote:
>>>
>>> Hi,
>>>
>>> Here's a rebased version of the patch(es). I've made no change to the
>>> code itself, I've tried to improve the commit message to explain why the
>>> expressions need to be null-preserving, handling of COALESCE clauses and
>>> placeholders.
>>
>> Hi!
>>
>>> 1) Is is_full_join_expr_null_preserving() necessary? Or is there some
>> existing piece of code checking the expression preserves NULLs? Possibly
>> with some additional smartness I haven't thought of?
>>
>> I think it is. There is find_nonnullable_rels which solves similar
>> task, but I don't see any additional smartness in it.
>> There is also is_standard_join_alias_expression function but it
>> doesn't check for functions strictness
>>
>>> 2) Is is_full_join_expr_null_preserving() correct?
>>
>> I think it is.
>>
>>
>> It does lose some optimizations for safe filter pushdows, because
>> this doesn't recurse
>> + if (IsA(node, PlaceHolderVar))
>> + return ((PlaceHolderVar *) node)->phlevelsup == 0;
>>
>
> Why would that matter? That returns 'true' for all PlaceHolderVars,
> treating them as null-preserving, i.e. allowing pushdown. Why would it
> block the optimization in the example you posted?
>
Correction. It does return true for placeholders with (phlevelsup == 0),
but that is the case of the expression at hand:
{OPEXPR :opno 551 :opfuncid 177 :opresulttype 23 :opretset false
:opcollid 0 :inputcollid 0 :args ({PLACEHOLDERVAR :phexpr {COALESCEEXPR
:coalescetype 23 :coalescecollid 0 :args ({VAR :varno 4 :varattno 1
:vartype 23 :vartypmod -1 :varcollid 0 :varnullingrels (b) :varlevelsup
0 :varreturningtype 0 :varnosyn 4 :varattnosyn 1 :location -1} {CONST
:consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval
true :constisnull false :location -1 :constvalue 4 [ 0 0 0 0 0 0 0 0 ]})
:location -1} :phrels (b 4) :phnullingrels (b) :phid 1 :phlevelsup 0}
{CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4
:constbyval true :constisnull false :location -1 :constvalue 4 [ 0 0 0 0
0 0 0 0 ]}) :location -1}
because that has ":phlevelsup 0".
--
Tomas Vondra
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Bertrand Drouvot | 2026-11-12 09:32:17 | Re: pgstat: Flush some statistics within running transactions, take 2 |
| Previous Message | Tomas Vondra | 2026-11-12 09:22:24 | Re: reconsider_full_join_clause fails to consider if COALESCE() arguments are NULL-preserving |