Skip to content

Commit 4a3c96e

Browse files
authored
Support expressions (dotted column refs) in DISTINCT ON (#258)
parseDistinctOn() was calling parseIdent() which only handles simple identifiers. Queries like DISTINCT ON (t.id, t.name) would fail because the dot was not recognized. Changed to parseExpr() so that any valid column expression (including table.column references) is accepted.
1 parent d468e13 commit 4a3c96e

7 files changed

Lines changed: 186 additions & 13 deletions

parser/ast.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5201,7 +5201,7 @@ func (s *SelectQuery) Accept(visitor ASTVisitor) error {
52015201
}
52025202

52035203
type DistinctOn struct {
5204-
Idents []*Ident
5204+
Idents []*NestedIdentifier
52055205
DistinctOnPos Pos
52065206
DistinctOnEnd Pos
52075207
}

parser/parser_query.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,20 @@ func (p *Parser) parseDistinctOn(pos Pos) (*DistinctOn, error) {
8989
return nil, err
9090
}
9191

92-
ident, err := p.parseIdent()
92+
col, err := p.ParseNestedIdentifier(p.Pos())
9393
if err != nil {
9494
return nil, err
9595
}
96-
idents := []*Ident{ident}
96+
idents := []*NestedIdentifier{col}
9797

9898
for p.matchTokenKind(TokenKindComma) {
9999
_ = p.lexer.consumeToken()
100100

101-
ident, err = p.parseIdent()
101+
col, err = p.ParseNestedIdentifier(p.Pos())
102102
if err != nil {
103103
return nil, err
104104
}
105-
idents = append(idents, ident)
105+
idents = append(idents, col)
106106
}
107107

108108
if err := p.expectTokenKind(TokenKindRParen); err != nil {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-- Origin SQL:
2+
SELECT DISTINCT ON (t.id, t.name) t.id, t.name, t.value FROM test_table t
3+
4+
-- Beautify SQL:
5+
SELECT DISTINCT ON (t.id, t.name)
6+
t.id,
7+
t.name,
8+
t.value
9+
FROM
10+
test_table AS t;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- Origin SQL:
2+
SELECT DISTINCT ON (t.id, t.name) t.id, t.name, t.value FROM test_table t
3+
4+
-- Format SQL:
5+
SELECT DISTINCT ON (t.id, t.name) t.id, t.name, t.value FROM test_table AS t;
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
[
2+
{
3+
"SelectPos": 0,
4+
"StatementEnd": 73,
5+
"With": null,
6+
"Top": null,
7+
"HasDistinct": true,
8+
"DistinctOn": {
9+
"Idents": [
10+
{
11+
"Ident": {
12+
"Name": "t",
13+
"QuoteType": 1,
14+
"NamePos": 20,
15+
"NameEnd": 21
16+
},
17+
"DotIdent": {
18+
"Name": "id",
19+
"QuoteType": 1,
20+
"NamePos": 22,
21+
"NameEnd": 24
22+
}
23+
},
24+
{
25+
"Ident": {
26+
"Name": "t",
27+
"QuoteType": 1,
28+
"NamePos": 26,
29+
"NameEnd": 27
30+
},
31+
"DotIdent": {
32+
"Name": "name",
33+
"QuoteType": 1,
34+
"NamePos": 28,
35+
"NameEnd": 32
36+
}
37+
}
38+
],
39+
"DistinctOnPos": 16,
40+
"DistinctOnEnd": 34
41+
},
42+
"SelectItems": [
43+
{
44+
"Expr": {
45+
"Fields": [
46+
{
47+
"Name": "t",
48+
"QuoteType": 1,
49+
"NamePos": 34,
50+
"NameEnd": 35
51+
},
52+
{
53+
"Name": "id",
54+
"QuoteType": 1,
55+
"NamePos": 36,
56+
"NameEnd": 38
57+
}
58+
]
59+
},
60+
"Modifiers": [],
61+
"Alias": null
62+
},
63+
{
64+
"Expr": {
65+
"Fields": [
66+
{
67+
"Name": "t",
68+
"QuoteType": 1,
69+
"NamePos": 40,
70+
"NameEnd": 41
71+
},
72+
{
73+
"Name": "name",
74+
"QuoteType": 1,
75+
"NamePos": 42,
76+
"NameEnd": 46
77+
}
78+
]
79+
},
80+
"Modifiers": [],
81+
"Alias": null
82+
},
83+
{
84+
"Expr": {
85+
"Fields": [
86+
{
87+
"Name": "t",
88+
"QuoteType": 1,
89+
"NamePos": 48,
90+
"NameEnd": 49
91+
},
92+
{
93+
"Name": "value",
94+
"QuoteType": 1,
95+
"NamePos": 50,
96+
"NameEnd": 55
97+
}
98+
]
99+
},
100+
"Modifiers": [],
101+
"Alias": null
102+
}
103+
],
104+
"From": {
105+
"FromPos": 56,
106+
"Expr": {
107+
"Table": {
108+
"TablePos": 61,
109+
"TableEnd": 73,
110+
"Alias": null,
111+
"Expr": {
112+
"Expr": {
113+
"Database": null,
114+
"Table": {
115+
"Name": "test_table",
116+
"QuoteType": 1,
117+
"NamePos": 61,
118+
"NameEnd": 71
119+
}
120+
},
121+
"AliasPos": 72,
122+
"Alias": {
123+
"Name": "t",
124+
"QuoteType": 1,
125+
"NamePos": 72,
126+
"NameEnd": 73
127+
}
128+
},
129+
"HasFinal": false
130+
},
131+
"StatementEnd": 73,
132+
"SampleRatio": null,
133+
"HasFinal": false
134+
}
135+
},
136+
"Window": null,
137+
"Prewhere": null,
138+
"Where": null,
139+
"GroupBy": null,
140+
"WithTotal": false,
141+
"Having": null,
142+
"OrderBy": null,
143+
"LimitBy": null,
144+
"Limit": null,
145+
"Settings": null,
146+
"Format": null,
147+
"UnionAll": null,
148+
"UnionDistinct": null,
149+
"Except": null
150+
}
151+
]

parser/testdata/query/output/select_with_distinct_on_keyword.sql.golden.json

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,22 @@
88
"DistinctOn": {
99
"Idents": [
1010
{
11-
"Name": "album",
12-
"QuoteType": 1,
13-
"NamePos": 19,
14-
"NameEnd": 24
11+
"Ident": {
12+
"Name": "album",
13+
"QuoteType": 1,
14+
"NamePos": 19,
15+
"NameEnd": 24
16+
},
17+
"DotIdent": null
1518
},
1619
{
17-
"Name": "artist",
18-
"QuoteType": 1,
19-
"NamePos": 25,
20-
"NameEnd": 31
20+
"Ident": {
21+
"Name": "artist",
22+
"QuoteType": 1,
23+
"NamePos": 25,
24+
"NameEnd": 31
25+
},
26+
"DotIdent": null
2127
}
2228
],
2329
"DistinctOnPos": 16,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SELECT DISTINCT ON (t.id, t.name) t.id, t.name, t.value FROM test_table t

0 commit comments

Comments
 (0)