mirror of
https://github.com/postgres/postgres.git
synced 2026-02-10 14:23:26 -05:00
Teach the parser to reject misplaced set-returning functions during parse
analysis using p_expr_kind, in much the same way as we do for aggregates
and window functions (cf commit eaccfded9). While this isn't complete
(it misses nesting-based restrictions), it's much better than the previous
error reporting for such cases, and it allows elimination of assorted
ad-hoc expression_returns_set() error checks. We could add nesting checks
later if it seems important to catch all cases at parse time.
There is one case the parser will now throw error for although previous
versions allowed it, which is SRFs in the tlist of an UPDATE. That never
behaved sensibly (since it's ill-defined which generated row should be
used to perform the update) and it's hard to see why it should not be
treated as an error. It's a release-note-worthy change though.
Also, add a new Query field hasTargetSRFs reporting whether there are
any SRFs in the targetlist (including GROUP BY/ORDER BY expressions).
The parser can now set that basically for free during parse analysis,
and we can use it in a number of places to avoid expression_returns_set
searches. (There will be more such checks soon.) In some places, this
allows decontorting the logic since it's no longer expensive to check for
SRFs in the tlist --- so I made the checks parallel to the handling of
hasAggs/hasWindowFuncs wherever it seemed appropriate.
catversion bump because adding a Query field changes stored rules.
Andres Freund and Tom Lane
Discussion: <24639.1473782855@sss.pgh.pa.us>
124 lines
5.4 KiB
SQL
124 lines
5.4 KiB
SQL
--
|
|
-- tsrf - targetlist set returning function tests
|
|
--
|
|
|
|
-- simple srf
|
|
SELECT generate_series(1, 3);
|
|
|
|
-- parallel iteration
|
|
SELECT generate_series(1, 3), generate_series(3,5);
|
|
|
|
-- parallel iteration, different number of rows
|
|
SELECT generate_series(1, 2), generate_series(1,4);
|
|
|
|
-- srf, with SRF argument
|
|
SELECT generate_series(1, generate_series(1, 3));
|
|
|
|
-- srf, with two SRF arguments
|
|
SELECT generate_series(generate_series(1,3), generate_series(2, 4));
|
|
|
|
CREATE TABLE few(id int, dataa text, datab text);
|
|
INSERT INTO few VALUES(1, 'a', 'foo'),(2, 'a', 'bar'),(3, 'b', 'bar');
|
|
|
|
-- SRF output order of sorting is maintained, if SRF is not referenced
|
|
SELECT few.id, generate_series(1,3) g FROM few ORDER BY id DESC;
|
|
|
|
-- but SRFs can be referenced in sort
|
|
SELECT few.id, generate_series(1,3) g FROM few ORDER BY id, g DESC;
|
|
SELECT few.id, generate_series(1,3) g FROM few ORDER BY id, generate_series(1,3) DESC;
|
|
|
|
-- it's weird to have ORDER BYs that increase the number of results
|
|
SELECT few.id FROM few ORDER BY id, generate_series(1,3) DESC;
|
|
|
|
-- SRFs are computed after aggregation
|
|
SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa;
|
|
-- unless referenced in GROUP BY clause
|
|
SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa, unnest('{1,1,3}'::int[]);
|
|
SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa, 5;
|
|
|
|
-- check HAVING works when GROUP BY does [not] reference SRF output
|
|
SELECT dataa, generate_series(1,1), count(*) FROM few GROUP BY 1 HAVING count(*) > 1;
|
|
SELECT dataa, generate_series(1,1), count(*) FROM few GROUP BY 1, 2 HAVING count(*) > 1;
|
|
|
|
-- it's weird to have GROUP BYs that increase the number of results
|
|
SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa ORDER BY 2;
|
|
SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa, unnest('{1,1,3}'::int[]) ORDER BY 2;
|
|
|
|
-- SRFs are not allowed in aggregate arguments
|
|
SELECT min(generate_series(1, 3)) FROM few;
|
|
|
|
-- SRFs are normally 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;
|
|
|
|
-- grouping sets are a bit special, they produce NULLs in columns not actually NULL
|
|
SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab);
|
|
SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab) ORDER BY dataa;
|
|
SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab) ORDER BY g;
|
|
SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g);
|
|
SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY dataa;
|
|
SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY g;
|
|
|
|
-- data modification
|
|
CREATE TABLE fewmore AS SELECT generate_series(1,3) AS data;
|
|
INSERT INTO fewmore VALUES(generate_series(4,5));
|
|
SELECT * FROM fewmore;
|
|
|
|
-- SRFs are not allowed in UPDATE (they once were, but it was nonsense)
|
|
UPDATE fewmore SET data = generate_series(4,9);
|
|
|
|
-- SRFs are not allowed in RETURNING
|
|
INSERT INTO fewmore VALUES(1) RETURNING generate_series(1,3);
|
|
-- nor aggregate arguments
|
|
SELECT count(generate_series(1,3)) FROM few;
|
|
-- nor standalone VALUES (but surely this is a bug?)
|
|
VALUES(1, generate_series(1,2));
|
|
|
|
-- DISTINCT ON is evaluated before tSRF evaluation if SRF is not
|
|
-- referenced either in ORDER BY or in the DISTINCT ON list. The ORDER
|
|
-- BY reference can be implicitly generated, if there's no other ORDER BY.
|
|
|
|
-- implicit reference (via implicit ORDER) to all columns
|
|
SELECT DISTINCT ON (a) a, b, generate_series(1,3) g
|
|
FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b);
|
|
|
|
-- unreferenced in DISTINCT ON or ORDER BY
|
|
SELECT DISTINCT ON (a) a, b, generate_series(1,3) g
|
|
FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b)
|
|
ORDER BY a, b DESC;
|
|
|
|
-- referenced in ORDER BY
|
|
SELECT DISTINCT ON (a) a, b, generate_series(1,3) g
|
|
FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b)
|
|
ORDER BY a, b DESC, g DESC;
|
|
|
|
-- referenced in ORDER BY and DISTINCT ON
|
|
SELECT DISTINCT ON (a, b, g) a, b, generate_series(1,3) g
|
|
FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b)
|
|
ORDER BY a, b DESC, g DESC;
|
|
|
|
-- only SRF mentioned in DISTINCT ON
|
|
SELECT DISTINCT ON (g) a, b, generate_series(1,3) g
|
|
FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b);
|
|
|
|
-- LIMIT / OFFSET is evaluated after SRF evaluation
|
|
SELECT a, generate_series(1,2) FROM (VALUES(1),(2),(3)) r(a) LIMIT 2 OFFSET 2;
|
|
-- SRFs are not allowed in LIMIT.
|
|
SELECT 1 LIMIT generate_series(1,3);
|
|
|
|
-- tSRF in correlated subquery, referencing table outside
|
|
SELECT (SELECT generate_series(1,3) LIMIT 1 OFFSET few.id) FROM few;
|
|
-- tSRF in correlated subquery, referencing SRF outside
|
|
SELECT (SELECT generate_series(1,3) LIMIT 1 OFFSET g.i) FROM generate_series(0,3) g(i);
|
|
|
|
-- Operators can return sets too
|
|
CREATE OPERATOR |@| (PROCEDURE = unnest, RIGHTARG = ANYARRAY);
|
|
SELECT |@|ARRAY[1,2,3];
|
|
|
|
-- Clean up
|
|
DROP TABLE few;
|
|
DROP TABLE fewmore;
|