Skip to content

Commit 71ba45a

Browse files
committed
Add tests for UNBOUNDED syntax ambiguity
There is a syntactic ambiguity in the SQL standard. Since UNBOUNDED is a non-reserved word, it could be the name of a function parameter and be used as an expression. There is a grammar hack to resolve such cases as the keyword. Add some tests to record this behavior. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://www.postgresql.org/message-id/flat/b2a09a77-3c8f-7c68-c9b7-824054f87d98%40enterprisedb.com
1 parent 3788c66 commit 71ba45a

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed

src/test/regress/expected/window.out

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,6 +1839,146 @@ window w as
18391839
| 43 | 42 | 43
18401840
(7 rows)
18411841

1842+
-- There is a syntactic ambiguity in the SQL standard. Since
1843+
-- UNBOUNDED is a non-reserved word, it could be the name of a
1844+
-- function parameter and be used as an expression. There is a
1845+
-- grammar hack to resolve such cases as the keyword. The following
1846+
-- tests record this behavior.
1847+
CREATE FUNCTION unbounded_syntax_test1a(x int) RETURNS TABLE (a int, b int, c int)
1848+
LANGUAGE SQL
1849+
BEGIN ATOMIC
1850+
SELECT sum(unique1) over (rows between x preceding and x following),
1851+
unique1, four
1852+
FROM tenk1 WHERE unique1 < 10;
1853+
END;
1854+
CREATE FUNCTION unbounded_syntax_test1b(x int) RETURNS TABLE (a int, b int, c int)
1855+
LANGUAGE SQL
1856+
AS $$
1857+
SELECT sum(unique1) over (rows between x preceding and x following),
1858+
unique1, four
1859+
FROM tenk1 WHERE unique1 < 10;
1860+
$$;
1861+
-- These will apply the argument to the window specification inside the function.
1862+
SELECT * FROM unbounded_syntax_test1a(2);
1863+
a | b | c
1864+
----+---+---
1865+
7 | 4 | 0
1866+
13 | 2 | 2
1867+
22 | 1 | 1
1868+
26 | 6 | 2
1869+
29 | 9 | 1
1870+
31 | 8 | 0
1871+
32 | 5 | 1
1872+
23 | 3 | 3
1873+
15 | 7 | 3
1874+
10 | 0 | 0
1875+
(10 rows)
1876+
1877+
SELECT * FROM unbounded_syntax_test1b(2);
1878+
a | b | c
1879+
----+---+---
1880+
7 | 4 | 0
1881+
13 | 2 | 2
1882+
22 | 1 | 1
1883+
26 | 6 | 2
1884+
29 | 9 | 1
1885+
31 | 8 | 0
1886+
32 | 5 | 1
1887+
23 | 3 | 3
1888+
15 | 7 | 3
1889+
10 | 0 | 0
1890+
(10 rows)
1891+
1892+
CREATE FUNCTION unbounded_syntax_test2a(unbounded int) RETURNS TABLE (a int, b int, c int)
1893+
LANGUAGE SQL
1894+
BEGIN ATOMIC
1895+
SELECT sum(unique1) over (rows between unbounded preceding and unbounded following),
1896+
unique1, four
1897+
FROM tenk1 WHERE unique1 < 10;
1898+
END;
1899+
CREATE FUNCTION unbounded_syntax_test2b(unbounded int) RETURNS TABLE (a int, b int, c int)
1900+
LANGUAGE SQL
1901+
AS $$
1902+
SELECT sum(unique1) over (rows between unbounded preceding and unbounded following),
1903+
unique1, four
1904+
FROM tenk1 WHERE unique1 < 10;
1905+
$$;
1906+
-- These will not apply the argument but instead treat UNBOUNDED as a keyword.
1907+
SELECT * FROM unbounded_syntax_test2a(2);
1908+
a | b | c
1909+
----+---+---
1910+
45 | 4 | 0
1911+
45 | 2 | 2
1912+
45 | 1 | 1
1913+
45 | 6 | 2
1914+
45 | 9 | 1
1915+
45 | 8 | 0
1916+
45 | 5 | 1
1917+
45 | 3 | 3
1918+
45 | 7 | 3
1919+
45 | 0 | 0
1920+
(10 rows)
1921+
1922+
SELECT * FROM unbounded_syntax_test2b(2);
1923+
a | b | c
1924+
----+---+---
1925+
45 | 4 | 0
1926+
45 | 2 | 2
1927+
45 | 1 | 1
1928+
45 | 6 | 2
1929+
45 | 9 | 1
1930+
45 | 8 | 0
1931+
45 | 5 | 1
1932+
45 | 3 | 3
1933+
45 | 7 | 3
1934+
45 | 0 | 0
1935+
(10 rows)
1936+
1937+
DROP FUNCTION unbounded_syntax_test1a, unbounded_syntax_test1b,
1938+
unbounded_syntax_test2a, unbounded_syntax_test2b;
1939+
-- Other tests with token UNBOUNDED in potentially problematic position
1940+
CREATE FUNCTION unbounded(x int) RETURNS int LANGUAGE SQL IMMUTABLE RETURN x;
1941+
SELECT sum(unique1) over (rows between 1 preceding and 1 following),
1942+
unique1, four
1943+
FROM tenk1 WHERE unique1 < 10;
1944+
sum | unique1 | four
1945+
-----+---------+------
1946+
6 | 4 | 0
1947+
7 | 2 | 2
1948+
9 | 1 | 1
1949+
16 | 6 | 2
1950+
23 | 9 | 1
1951+
22 | 8 | 0
1952+
16 | 5 | 1
1953+
15 | 3 | 3
1954+
10 | 7 | 3
1955+
7 | 0 | 0
1956+
(10 rows)
1957+
1958+
SELECT sum(unique1) over (rows between unbounded(1) preceding and unbounded(1) following),
1959+
unique1, four
1960+
FROM tenk1 WHERE unique1 < 10;
1961+
sum | unique1 | four
1962+
-----+---------+------
1963+
6 | 4 | 0
1964+
7 | 2 | 2
1965+
9 | 1 | 1
1966+
16 | 6 | 2
1967+
23 | 9 | 1
1968+
22 | 8 | 0
1969+
16 | 5 | 1
1970+
15 | 3 | 3
1971+
10 | 7 | 3
1972+
7 | 0 | 0
1973+
(10 rows)
1974+
1975+
SELECT sum(unique1) over (rows between unbounded.x preceding and unbounded.x following),
1976+
unique1, four
1977+
FROM tenk1, (values (1)) as unbounded(x) WHERE unique1 < 10;
1978+
ERROR: argument of ROWS must not contain variables
1979+
LINE 1: SELECT sum(unique1) over (rows between unbounded.x preceding...
1980+
^
1981+
DROP FUNCTION unbounded;
18421982
-- Check overflow behavior for various integer sizes
18431983
select x, last_value(x) over (order by x::smallint range between current row and 2147450884 following)
18441984
from generate_series(32764, 32766) x;

src/test/regress/sql/window.sql

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,72 @@ from
471471
window w as
472472
(order by x desc nulls last range between 2 preceding and 2 following);
473473

474+
-- There is a syntactic ambiguity in the SQL standard. Since
475+
-- UNBOUNDED is a non-reserved word, it could be the name of a
476+
-- function parameter and be used as an expression. There is a
477+
-- grammar hack to resolve such cases as the keyword. The following
478+
-- tests record this behavior.
479+
480+
CREATE FUNCTION unbounded_syntax_test1a(x int) RETURNS TABLE (a int, b int, c int)
481+
LANGUAGE SQL
482+
BEGIN ATOMIC
483+
SELECT sum(unique1) over (rows between x preceding and x following),
484+
unique1, four
485+
FROM tenk1 WHERE unique1 < 10;
486+
END;
487+
488+
CREATE FUNCTION unbounded_syntax_test1b(x int) RETURNS TABLE (a int, b int, c int)
489+
LANGUAGE SQL
490+
AS $$
491+
SELECT sum(unique1) over (rows between x preceding and x following),
492+
unique1, four
493+
FROM tenk1 WHERE unique1 < 10;
494+
$$;
495+
496+
-- These will apply the argument to the window specification inside the function.
497+
SELECT * FROM unbounded_syntax_test1a(2);
498+
SELECT * FROM unbounded_syntax_test1b(2);
499+
500+
CREATE FUNCTION unbounded_syntax_test2a(unbounded int) RETURNS TABLE (a int, b int, c int)
501+
LANGUAGE SQL
502+
BEGIN ATOMIC
503+
SELECT sum(unique1) over (rows between unbounded preceding and unbounded following),
504+
unique1, four
505+
FROM tenk1 WHERE unique1 < 10;
506+
END;
507+
508+
CREATE FUNCTION unbounded_syntax_test2b(unbounded int) RETURNS TABLE (a int, b int, c int)
509+
LANGUAGE SQL
510+
AS $$
511+
SELECT sum(unique1) over (rows between unbounded preceding and unbounded following),
512+
unique1, four
513+
FROM tenk1 WHERE unique1 < 10;
514+
$$;
515+
516+
-- These will not apply the argument but instead treat UNBOUNDED as a keyword.
517+
SELECT * FROM unbounded_syntax_test2a(2);
518+
SELECT * FROM unbounded_syntax_test2b(2);
519+
520+
DROP FUNCTION unbounded_syntax_test1a, unbounded_syntax_test1b,
521+
unbounded_syntax_test2a, unbounded_syntax_test2b;
522+
523+
-- Other tests with token UNBOUNDED in potentially problematic position
524+
CREATE FUNCTION unbounded(x int) RETURNS int LANGUAGE SQL IMMUTABLE RETURN x;
525+
526+
SELECT sum(unique1) over (rows between 1 preceding and 1 following),
527+
unique1, four
528+
FROM tenk1 WHERE unique1 < 10;
529+
530+
SELECT sum(unique1) over (rows between unbounded(1) preceding and unbounded(1) following),
531+
unique1, four
532+
FROM tenk1 WHERE unique1 < 10;
533+
534+
SELECT sum(unique1) over (rows between unbounded.x preceding and unbounded.x following),
535+
unique1, four
536+
FROM tenk1, (values (1)) as unbounded(x) WHERE unique1 < 10;
537+
538+
DROP FUNCTION unbounded;
539+
474540
-- Check overflow behavior for various integer sizes
475541

476542
select x, last_value(x) over (order by x::smallint range between current row and 2147450884 following)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy