Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wh7VU-0000x7-1c for pgsql-hackers@arkaria.postgresql.org; Tue, 07 Jul 2026 15:14:44 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wh7VS-001Bvb-2Q for pgsql-hackers@arkaria.postgresql.org; Tue, 07 Jul 2026 15:14:43 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wh7VS-001BvT-11 for pgsql-hackers@lists.postgresql.org; Tue, 07 Jul 2026 15:14:43 +0000 Received: from mail-pf1-x433.google.com ([2607:f8b0:4864:20::433]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wh7VP-000000000E5-2bVM for pgsql-hackers@lists.postgresql.org; Tue, 07 Jul 2026 15:14:41 +0000 Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-842338c18e0so3521123b3a.1 for ; Tue, 07 Jul 2026 08:14:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783437277; x=1784042077; darn=lists.postgresql.org; h=to:cc:date:message-id:subject:mime-version:content-type:from:from :to:cc:subject:date:message-id:reply-to:content-type; bh=JRvSf2lxQ6QynrimgrpZJ4WaS1RE9ntyMeU8wk0S28o=; b=lD8QBxw4H1TTAoOGOTukv6oHDCi3QxggPpSBFfZDkxLEHLlC3doC1DTmpG23R3FBZB gNP7t0hC2Fnz/DEqero+/e6hTr0iXTnEM9H+MQ1YI2zk/hMUBn66LbTCp5+lViwW4kay UU3fZxgUwk8mQUCUuFfWuu+JGKV6JM9hG7FoMQWNfPxt7Sl7mV2qPak59jyCONP6pe+x pESN3gjePeDJvywHkAuuPVbG8wsCxqALVNTe0SnoDzYh0JAi2ydAQUb3VJ88qdCt9aje l9cmpP0MR/RwV/E5ej8RhqpYsaDcrPuCnBj9WcrGa9XeHXuvRGDXNxLapfNMykNFzSP4 iuFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783437277; x=1784042077; h=to:cc:date:message-id:subject:mime-version:content-type:from :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to:content-type; bh=JRvSf2lxQ6QynrimgrpZJ4WaS1RE9ntyMeU8wk0S28o=; b=d7e9UXITmSjIUIiLv7IRJ15d77TFXHvKBaU9gm29EGGRT6PpJfEbsmQh0QmspYBAOH CFIZyxz3m20p+7xsbXEpYOcONz54QD3jGhjNE3S8FTwh5ilO2LSCr3+7VwkvwZwQBEW8 4iog++GGYalTkAOHvBLpAdesk+rO0SXFl6RB6x0Tn2QWxR2y7sHGG+SsUofXmwCgzNdI nfMQHc4hTK/G1Wp3wWv50qV84EbcKOeFXc5wDT7dlJsBjINg0k/4tsBsBtX0bcwsV4nI LdSxoxAl5M2zlflZaGY9HFLfwgO2ce0UWy06WJxo08ecOnUwQcu9EsSO/5rH+ip7xb7F 194A== X-Gm-Message-State: AOJu0YytrnT39DxtysSg6RQo18Usna7F+jw6ckDeWanYNNJQomkzrrYY GgT1iFQgyGMUXJRayhyUiis73Emcc6sdszOTHNUacnJRFOhl7cDM7JCNyOWrZQ== X-Gm-Gg: AfdE7cnRd09jSkNnMyn0zyHI/2LZR90ZPcQCnsChOudyRhFB4S37bGfbRIhF82IGSH2 Ne4PR64Qn3mPEcUHUHMraz6sIv/kF0oBxhErXG/uulaN+Gb+1bT795cNbEVyW5oYYGfnhqsJQLA AqIh9lAWXIjRwX6zMrKgSJJEqj80uEvI/Na+FiVXe0gwT2ecRXAM1/R/bEn1zxcnLGzhX5G2iOa 3NOE3iAGsuVYq8NCedgp8cjyfRnJXOkZCu4cr6Zu9r23wi5lEUjXtuRAyuK+O0s623DSIAyJ8UN yDOIum5yznBvmIZUZfNY7gWhufQ0rs2VDyUrO12iWx6YwcfiSBUBD7uV1CLdcGsTUy0w9XeS3Ga 7q+6i3EfUC9Ygr+qHtnY9vAgLNlCwGwgBOu9IuE47a9yuGn+1gcLhGhUyj1ckjpYtBWd6Z+lKjD 6MJ9wrGKJqs2G4Uo+hm0Rp9X+dBLYC0GAXe8ONo50C+AfdY60= X-Received: by 2002:a05:6a20:72a3:b0:3bf:b523:2aed with SMTP id adf61e73a8af0-3c08ec7167emr6946262637.8.1783437277091; Tue, 07 Jul 2026 08:14:37 -0700 (PDT) Received: from smtpclient.apple ([2601:642:4c02:1659:3d11:2e85:ffb1:3cbe]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-13b659c865asm9610803c88.11.2026.07.07.08.14.34 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Jul 2026 08:14:35 -0700 (PDT) From: Chao Li Content-Type: multipart/mixed; boundary="Apple-Mail=_C33696E4-B273-473B-8716-B908580B28C7" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Fix duplicate detection for null-treatment window functions Message-Id: <5D2C9081-5DFE-4E27-AB14-7358238EA1BC@gmail.com> Date: Tue, 7 Jul 2026 08:14:03 -0700 Cc: Tatsuo Ishii To: PostgreSQL-development X-Mailer: Apple Mail (2.3864.600.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_C33696E4-B273-473B-8716-B908580B28C7 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hi, I just spotted an oversight from =E2=80=9C[25a30bbd4] Add IGNORE = NULLS/RESPECT NULLS option to Window functions=E2=80=9D. In ExecInitWindowAgg(), there is logic to detect duplicate functions: ``` if (i <=3D wfuncno && wfunc->ignore_nulls =3D=3D = perfunc[i].ignore_nulls) { /* Found a match to an existing entry, so just = mark it */ wfuncstate->wfuncno =3D i; continue; } ``` However, when appending function info to perfunc, ignore_nulls is not = copied: ``` /* Fill in the perfuncstate data */ perfuncstate->wfuncstate =3D wfuncstate; perfuncstate->wfunc =3D wfunc; perfuncstate->numArguments =3D = list_length(wfuncstate->args); perfuncstate->winCollation =3D wfunc->inputcollid; ``` As a result, wfunc->ignore_nulls =3D=3D perfunc[i].ignore_nulls can = never be true for duplicate IGNORE NULLS or explicit RESPECT NULLS = calls. This means duplicate detection doesn't work for those calls. This = bug is easy to prove by adding temporary logs, and the fix is = straightforward: copy ignore_nulls when filling in the perfuncstate = data. This is a simple repro: Without the fix: ``` evantest=3D# WITH t(x) AS (VALUES (NULL::int), (1), (2)) evantest-# SELECT first_value(x) IGNORE NULLS OVER w AS a, evantest-# first_value(x) IGNORE NULLS OVER w AS b evantest-# FROM t evantest-# WINDOW w AS (ORDER BY x NULLS FIRST evantest(# ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED = FOLLOWING); INFO: WindowAgg duplicate cache miss: no previous match, ignore_nulls 1 INFO: WindowAgg duplicate cache miss: matched wfuncno 0, ignore_nulls = 1, cached ignore_nulls 0 a | b ---+--- 1 | 1 1 | 1 1 | 1 (3 rows) ``` With the fix: ``` evantest=3D# WITH t(x) AS (VALUES (NULL::int), (1), (2)) evantest-# SELECT first_value(x) IGNORE NULLS OVER w AS a, evantest-# first_value(x) IGNORE NULLS OVER w AS b evantest-# FROM t evantest-# WINDOW w AS (ORDER BY x NULLS FIRST evantest(# ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED = FOLLOWING); INFO: WindowAgg duplicate cache miss: no previous match, ignore_nulls 1 INFO: WindowAgg duplicate cache hit: existing wfuncno 0, ignore_nulls 1 a | b ---+--- 1 | 1 1 | 1 1 | 1 (3 rows) ``` See the attached patch for details. The actual fix is only one line. The = INFO logs above were produced with temporary debug logs added around the = duplicate-function lookup, those logs are not part of the proposed fix. = I left those logs in the patch with TODO comments only so reviewers can = see the behavior before and after the fix. They should be removed before = pushing. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_C33696E4-B273-473B-8716-B908580B28C7 Content-Disposition: attachment; filename=v1-0001-Fix-duplicate-detection-for-null-treatment-window.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v1-0001-Fix-duplicate-detection-for-null-treatment-window.patch" Content-Transfer-Encoding: quoted-printable =46rom=20252b1e9b361feb82a12931787bb6108b11063598=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Tue,=207=20Jul=202026=2008:10:58=20-0700=0ASubject:=20[PATCH=20= v1]=20Fix=20duplicate=20detection=20for=20null-treatment=20window=0A=20= functions=0A=0A`ExecInitWindowAgg()`=20checks=20= `perfunc[i].ignore_nulls`=20when=20deciding=0Awhether=20a=20window=20= function=20call=20can=20reuse=20an=20existing=20`WindowStatePerFunc`=0A= entry.=20However,=20that=20field=20was=20never=20initialized=20when=20= filling=20the=0A`perfuncstate`=20data,=20so=20it=20remained=20zero=20= from=20`palloc0_array()`.=0A=0AAs=20a=20result,=20duplicate=20calls=20= using=20`IGNORE=20NULLS`=20or=20explicit=0A`RESPECT=20NULLS`=20failed=20= to=20reuse=20the=20existing=20entry,=20because=20their=0A= `wfunc->ignore_nulls`=20value=20did=20not=20match=20the=20zeroed=20= per-function=20state.=0APlain=20calls=20were=20unaffected=20because=20= their=20null-treatment=20value=20is=20also=20zero.=0A=0ACopy=20= `wfunc->ignore_nulls`=20into=20`perfuncstate->ignore_nulls`=20during=0A= initialization=20so=20duplicate=20null-treatment=20window=20function=20= calls=20are=0Adeduplicated=20as=20intended.=0A=0AOversight=20in=20= 25a30bbd423.=0A=0AAuthor:=20Chao=20Li=20=0A---=0A=20= src/backend/executor/nodeWindowAgg.c=20|=2013=20+++++++++++++=0A=201=20= file=20changed,=2013=20insertions(+)=0A=0Adiff=20--git=20= a/src/backend/executor/nodeWindowAgg.c=20= b/src/backend/executor/nodeWindowAgg.c=0Aindex=20= f1c524d00df..676fe024965=20100644=0A---=20= a/src/backend/executor/nodeWindowAgg.c=0A+++=20= b/src/backend/executor/nodeWindowAgg.c=0A@@=20-2749,11=20+2749,23=20@@=20= ExecInitWindowAgg(WindowAgg=20*node,=20EState=20*estate,=20int=20eflags)=0A= =20=09=09}=0A=20=09=09if=20(i=20<=3D=20wfuncno=20&&=20= wfunc->ignore_nulls=20=3D=3D=20perfunc[i].ignore_nulls)=0A=20=09=09{=0A+=09= =09=09/*=20TODO:=20remove=20this=20log=20before=20pushing=20*/=0A+=09=09=09= elog(INFO,=20"WindowAgg=20duplicate=20cache=20hit:=20existing=20wfuncno=20= %d,=20ignore_nulls=20%d",=0A+=09=09=09=09=20i,=20wfunc->ignore_nulls);=0A= +=0A=20=09=09=09/*=20Found=20a=20match=20to=20an=20existing=20entry,=20= so=20just=20mark=20it=20*/=0A=20=09=09=09wfuncstate->wfuncno=20=3D=20i;=0A= =20=09=09=09continue;=0A=20=09=09}=0A=20=0A+=09=09/*=20TODO:=20remove=20= this=20log=20before=20pushing=20*/=0A+=09=09if=20(i=20<=3D=20wfuncno)=0A= +=09=09=09elog(INFO,=20"WindowAgg=20duplicate=20cache=20miss:=20matched=20= wfuncno=20%d,=20ignore_nulls=20%d,=20cached=20ignore_nulls=20%d",=0A+=09=09= =09=09=20i,=20wfunc->ignore_nulls,=20perfunc[i].ignore_nulls);=0A+=09=09= else=0A+=09=09=09elog(INFO,=20"WindowAgg=20duplicate=20cache=20miss:=20= no=20previous=20match,=20ignore_nulls=20%d",=0A+=09=09=09=09=20= wfunc->ignore_nulls);=0A+=0A=20=09=09/*=20Nope,=20so=20assign=20a=20new=20= PerAgg=20record=20*/=0A=20=09=09perfuncstate=20=3D=20= &perfunc[++wfuncno];=0A=20=0A@@=20-2773,6=20+2785,7=20@@=20= ExecInitWindowAgg(WindowAgg=20*node,=20EState=20*estate,=20int=20eflags)=0A= =20=09=09perfuncstate->wfunc=20=3D=20wfunc;=0A=20=09=09= perfuncstate->numArguments=20=3D=20list_length(wfuncstate->args);=0A=20=09= =09perfuncstate->winCollation=20=3D=20wfunc->inputcollid;=0A+=09=09= perfuncstate->ignore_nulls=20=3D=20wfunc->ignore_nulls;=0A=20=0A=20=09=09= get_typlenbyval(wfunc->wintype,=0A=20=09=09=09=09=09=09= &perfuncstate->resulttypeLen,=0A--=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_C33696E4-B273-473B-8716-B908580B28C7--