Skip to content

Commit 969dc8c

Browse files
committed
Fix grammar for subscripting or field selection from a sub-SELECT result.
Such cases should work, but the grammar failed to accept them because of our ancient precedence hacks to convince bison that extra parentheses around a sub-SELECT in an expression are unambiguous. (Formally, they *are* ambiguous, but we don't especially care whether they're treated as part of the sub-SELECT or part of the expression. Bison cares, though.) Fix by adding a redundant-looking production for this case. This is a fine example of why fixing shift/reduce conflicts via precedence declarations is more dangerous than it looks: you can easily cause the parser to reject cases that should work. This has been wrong since commit 3db4056 or maybe before, and apparently some people have been working around it by inserting no-op casts. That method introduces a dump/reload hazard, as illustrated in bug #7838 from Jan Mate. Hence, back-patch to all active branches.
1 parent 8879c35 commit 969dc8c

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

src/backend/parser/gram.y

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9258,6 +9258,29 @@ c_expr: columnref { $$ = $1; }
92589258
n->location = @1;
92599259
$$ = (Node *)n;
92609260
}
9261+
| select_with_parens indirection
9262+
{
9263+
/*
9264+
* Because the select_with_parens nonterminal is designed
9265+
* to "eat" as many levels of parens as possible, the
9266+
* '(' a_expr ')' opt_indirection production above will
9267+
* fail to match a sub-SELECT with indirection decoration;
9268+
* the sub-SELECT won't be regarded as an a_expr as long
9269+
* as there are parens around it. To support applying
9270+
* subscripting or field selection to a sub-SELECT result,
9271+
* we need this redundant-looking production.
9272+
*/
9273+
SubLink *n = makeNode(SubLink);
9274+
A_Indirection *a = makeNode(A_Indirection);
9275+
n->subLinkType = EXPR_SUBLINK;
9276+
n->testexpr = NULL;
9277+
n->operName = NIL;
9278+
n->subselect = $1;
9279+
n->location = @1;
9280+
a->arg = (Node *)n;
9281+
a->indirection = check_indirection($2, yyscanner);
9282+
$$ = (Node *)a;
9283+
}
92619284
| EXISTS select_with_parens
92629285
{
92639286
SubLink *n = makeNode(SubLink);

src/test/regress/expected/subselect.out

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,61 @@ SELECT 1 AS zero WHERE 1 IN (SELECT 2);
1717
------
1818
(0 rows)
1919

20+
-- Check grammar's handling of extra parens in assorted contexts
21+
SELECT * FROM (SELECT 1 AS x) ss;
22+
x
23+
---
24+
1
25+
(1 row)
26+
27+
SELECT * FROM ((SELECT 1 AS x)) ss;
28+
x
29+
---
30+
1
31+
(1 row)
32+
33+
(SELECT 2) UNION SELECT 2;
34+
?column?
35+
----------
36+
2
37+
(1 row)
38+
39+
((SELECT 2)) UNION SELECT 2;
40+
?column?
41+
----------
42+
2
43+
(1 row)
44+
45+
SELECT ((SELECT 2) UNION SELECT 2);
46+
?column?
47+
----------
48+
2
49+
(1 row)
50+
51+
SELECT (((SELECT 2)) UNION SELECT 2);
52+
?column?
53+
----------
54+
2
55+
(1 row)
56+
57+
SELECT (SELECT ARRAY[1,2,3])[1];
58+
?column?
59+
----------
60+
1
61+
(1 row)
62+
63+
SELECT ((SELECT ARRAY[1,2,3]))[2];
64+
?column?
65+
----------
66+
2
67+
(1 row)
68+
69+
SELECT (((SELECT ARRAY[1,2,3])))[3];
70+
?column?
71+
----------
72+
3
73+
(1 row)
74+
2075
-- Set up some simple test tables
2176
CREATE TABLE SUBSELECT_TBL (
2277
f1 integer,

src/test/regress/sql/subselect.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@ SELECT 1 AS zero WHERE 1 NOT IN (SELECT 1);
88

99
SELECT 1 AS zero WHERE 1 IN (SELECT 2);
1010

11+
-- Check grammar's handling of extra parens in assorted contexts
12+
13+
SELECT * FROM (SELECT 1 AS x) ss;
14+
SELECT * FROM ((SELECT 1 AS x)) ss;
15+
16+
(SELECT 2) UNION SELECT 2;
17+
((SELECT 2)) UNION SELECT 2;
18+
19+
SELECT ((SELECT 2) UNION SELECT 2);
20+
SELECT (((SELECT 2)) UNION SELECT 2);
21+
22+
SELECT (SELECT ARRAY[1,2,3])[1];
23+
SELECT ((SELECT ARRAY[1,2,3]))[2];
24+
SELECT (((SELECT ARRAY[1,2,3])))[3];
25+
1126
-- Set up some simple test tables
1227

1328
CREATE TABLE SUBSELECT_TBL (

0 commit comments

Comments
 (0)