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.98.2) (envelope-from ) id 1xBphZ-00000003PR6-2Ukm for pgsql-bugs@arkaria.postgresql.org; Wed, 30 Sep 2026 08:30:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1xBphY-000000012xb-1PH9 for pgsql-bugs@arkaria.postgresql.org; Wed, 30 Sep 2026 08:30:08 +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.98.2) (envelope-from ) id 1xBl66-000000000jY-0YDu for pgsql-bugs@lists.postgresql.org; Wed, 30 Sep 2026 03:35:10 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1xBl62-00000001yLq-3iKV for pgsql-bugs@lists.postgresql.org; Wed, 30 Sep 2026 03:35:09 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=x6iSn11y6Ibvutt5f9dWIq02UT0TJ92KEUC6UIqmjW0=; b=QGAclACtNHUhrBWJYS73yhFZWE QsyYOKi5EYcTs/zTIFDugNSRMPQsYQiKfYyWPu8HXgrT2KZvGnvzYdz6jpoCYJmXPWC11kz7LikZu rDDO/km9UUA5FHphUCnBSbqgsZGvwvaqnY4y7MK0ifgxdQAdZ6c/m/YkYB8RdwF7Wr/7f13KtuU0n onHvyQeZa1Nmz7ISzqbmCtfc+ds9Vf/z1xSj+Wk9XCUMW//j4COb/WCTF42+ChBS6/Z19icVJuM0a zhz9OxbEvIbklGJr0yggrwBUFZzCi78v8VpDFGe3bd7NECqMihluMsAGOPEAkurC+ExCJ5Y2jpL3Z XjrTqBwA==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1xBl61-000jlK-2c for pgsql-bugs@lists.postgresql.org; Wed, 30 Sep 2026 03:35:05 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1xBl5z-0000000GxeU-41FZ for pgsql-bugs@lists.postgresql.org; Wed, 30 Sep 2026 03:35:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19732: first_value/last_value/nth_value return NULL with EXCLUDE TIES when the current row is outside its f To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: theshallow27@gmail.com Reply-To: theshallow27@gmail.com, pgsql-bugs@lists.postgresql.org Date: Wed, 30 Sep 2026 03:34:33 +0000 Message-ID: <19732-d4eed889e3021ef8@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19732 Logged by: Shallow Email address: theshallow27@gmail.com PostgreSQL version: 18.6 Operating system: Linux Description: =20 With a ROWS frame that does not contain the current row, such as `1 FOLLOWING AND UNBOUNDED FOLLOWING`, and `EXCLUDE TIES`, `first_value`, `nth_value` and `last_value` can return NULL although the frame has rows. This happens when the frame edge falls on a peer of the current row. `array_agg` over the same window shows the rows. ```sql SELECT k, first_value(k) OVER w, nth_value(k, 1) OVER w, array_agg(k) OVER w FROM (VALUES (0), (0), (1)) t(k) WINDOW w AS (ORDER BY k ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING EXCLUDE TIES); k | first_value | nth_value | array_agg ---+-------------+-----------+----------- 0 | | | {1} <- expected 1, 1 0 | 1 | 1 | {1} 1 | | | SELECT k, last_value(k) OVER w, array_agg(k) OVER w FROM (VALUES (0), (1), (1)) t(k) WINDOW w AS (ORDER BY k ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING EXCLUDE TIES); k | last_value | array_agg ---+------------+----------- 0 | | 1 | 0 | {0} 1 | | {0} <- expected 0 ``` For the first row of the first query, the frame is rows 2 and 3. Row 2 is a peer of the current row, so `EXCLUDE TIES` removes it, and row 3 (k =3D 1) remains. Without `EXCLUDE TIES`, the same frame gives the right values. In `WinGetFuncArgInFrame` (nodeWindowAgg.c), the `FRAMEOPTION_EXCLUDE_TIES` case replaces `abs_pos` by `winstate->currentpos` when the frame edge is the first row of the overlap between the frame and the current row's peer group. This is right only when the current row is inside the frame. The comment before the switch expects the out-of-frame case to end with "deciding the row is out of frame", but that returns NULL here although later frame rows remain. The frame-tail branch has the same substitution.