]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Disallow set-returning functions within window OVER clauses.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 Jun 2026 21:21:23 +0000 (17:21 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 Jun 2026 21:21:23 +0000 (17:21 -0400)
We previously allowed this, but it leads to odd behaviors, basically
because putting a SRF there is inconsistent with the principle that a
window function doesn't change the number of rows in the query result.
There doesn't seem to be a strong reason to try to make such cases
behave consistently.  Users should put their SRFs in lateral FROM
clauses instead.

This issue has been sitting on the back burner for multiple years
now, partially because it didn't seem wise to back-patch such a
change.  Let's squeeze it into v19 before it's too late.

Bug: #17502
Bug: #19535
Reported-by: Daniel Farkaš <daniel.farkas@datoris.com>
Reported-by: Qifan Liu <imchifan@163.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/17502-281a7aaacfaa872a@postgresql.org
Discussion: https://postgr.es/m/19535-376081d7cc07c86d@postgresql.org
Backpatch-through: 19

src/backend/parser/parse_func.c
src/test/regress/expected/tsrf.out
src/test/regress/sql/tsrf.sql

index 9cdbaa542fe1288d97717e24095992d707a5054f..a9b6be7203b3de098ece79b68f2eb27fb017b91a 100644 (file)
@@ -2700,9 +2700,6 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
                        break;
                case EXPR_KIND_WINDOW_PARTITION:
                case EXPR_KIND_WINDOW_ORDER:
-                       /* okay, these are effectively GROUP BY/ORDER BY */
-                       pstate->p_hasTargetSRFs = true;
-                       break;
                case EXPR_KIND_WINDOW_FRAME_RANGE:
                case EXPR_KIND_WINDOW_FRAME_ROWS:
                case EXPR_KIND_WINDOW_FRAME_GROUPS:
index c4f7b187f5baf8f9047041a12c787f2820376342..005f1268f4b2c8748671a564da828d4b09ce9a9a 100644 (file)
@@ -267,7 +267,21 @@ ERROR:  window function calls cannot contain set-returning function calls
 LINE 1: SELECT min(generate_series(1, 3)) OVER() FROM few;
                    ^
 HINT:  You might be able to move the set-returning function into a LATERAL FROM item.
--- SRFs are normally computed after window functions
+--- ... nor in window definitions
+SELECT sum(id) OVER (PARTITION BY generate_series(1, 3)) FROM few;
+ERROR:  set-returning functions are not allowed in window definitions
+LINE 1: SELECT sum(id) OVER (PARTITION BY generate_series(1, 3)) FRO...
+                                          ^
+SELECT sum(id) OVER (ORDER BY generate_series(1, 3)) FROM few;
+ERROR:  set-returning functions are not allowed in window definitions
+LINE 1: SELECT sum(id) OVER (ORDER BY generate_series(1, 3)) FROM fe...
+                                      ^
+SELECT sum(id) OVER (ROWS BETWEEN UNBOUNDED PRECEDING
+                     AND generate_series(1, 3) FOLLOWING) FROM few;
+ERROR:  set-returning functions are not allowed in window definitions
+LINE 2:                      AND generate_series(1, 3) FOLLOWING) FR...
+                                 ^
+-- SRFs are computed after window functions
 SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few;
  id | lag | count | generate_series 
 ----+-----+-------+-----------------
@@ -282,15 +296,6 @@ SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few;
   3 |   2 |     3 |               3
 (9 rows)
 
--- unless referencing SRFs
-SELECT SUM(count(*)) OVER(PARTITION BY generate_series(1,3) ORDER BY generate_series(1,3)), generate_series(1,3) g FROM few GROUP BY g;
- sum | g 
------+---
-   3 | 1
-   3 | 2
-   3 | 3
-(3 rows)
-
 -- sorting + grouping
 SELECT few.dataa, count(*), min(id), max(id), generate_series(1,3) FROM few GROUP BY few.dataa ORDER BY 5, 1;
  dataa | count | min | max | generate_series 
index 7c22529a0db0a6f15dff6b6e89a7c2304a269c2f..8442ba9e743b32a8f188de87875cb7538b4247d0 100644 (file)
@@ -82,10 +82,14 @@ SELECT sum((3 = ANY(SELECT lag(x) over(order by x)
 -- SRFs are not allowed in window function arguments, either
 SELECT min(generate_series(1, 3)) OVER() FROM few;
 
--- SRFs are normally computed after window functions
+--- ... nor in window definitions
+SELECT sum(id) OVER (PARTITION BY generate_series(1, 3)) FROM few;
+SELECT sum(id) OVER (ORDER BY generate_series(1, 3)) FROM few;
+SELECT sum(id) OVER (ROWS BETWEEN UNBOUNDED PRECEDING
+                     AND generate_series(1, 3) FOLLOWING) FROM few;
+
+-- SRFs are computed after window functions
 SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few;
--- unless referencing SRFs
-SELECT SUM(count(*)) OVER(PARTITION BY generate_series(1,3) ORDER BY generate_series(1,3)), generate_series(1,3) g FROM few GROUP BY g;
 
 -- sorting + grouping
 SELECT few.dataa, count(*), min(id), max(id), generate_series(1,3) FROM few GROUP BY few.dataa ORDER BY 5, 1;