Skip to content

Commit c4e9dae

Browse files
John Bodleyandialbrecht
authored andcommitted
[tokenizer] Grouping GROUP/ORDER BY
1 parent 8fd25a9 commit c4e9dae

6 files changed

Lines changed: 30 additions & 9 deletions

File tree

sqlparse/filters/aligned_indent.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ class AlignedIndentFilter(object):
1515
join_words = (r'((LEFT\s+|RIGHT\s+|FULL\s+)?'
1616
r'(INNER\s+|OUTER\s+|STRAIGHT\s+)?|'
1717
r'(CROSS\s+|NATURAL\s+)?)?JOIN\b')
18+
by_words = ('GROUP BY', 'ORDER BY')
1819
split_words = ('FROM',
1920
join_words, 'ON',
2021
'WHERE', 'AND', 'OR',
21-
'GROUP', 'HAVING', 'LIMIT',
22-
'ORDER', 'UNION', 'VALUES',
22+
'GROUP BY', 'HAVING', 'LIMIT',
23+
'ORDER BY', 'UNION', 'VALUES',
2324
'SET', 'BETWEEN', 'EXCEPT')
2425

2526
def __init__(self, char=' ', n='\n'):
@@ -101,8 +102,12 @@ def _next_token(self, tlist, idx=-1):
101102
def _split_kwds(self, tlist):
102103
tidx, token = self._next_token(tlist)
103104
while token:
104-
# joins are special case. only consider the first word as aligner
105-
if token.match(T.Keyword, self.join_words, regex=True):
105+
# joins, group/order by are special case. only consider the first
106+
# word as aligner
107+
if (
108+
token.match(T.Keyword, self.join_words, regex=True) or
109+
token.match(T.Keyword, ('GROUP BY', 'ORDER BY'))
110+
):
106111
token_indent = token.value.split()[0]
107112
else:
108113
token_indent = text_type(token)
@@ -117,7 +122,9 @@ def _process_default(self, tlist):
117122
idx = tlist.token_index(sgroup)
118123
pidx, prev_ = tlist.token_prev(idx)
119124
# HACK: make "group/order by" work. Longer than max_len.
120-
offset_ = 3 if (prev_ and prev_.match(T.Keyword, 'BY')) else 0
125+
offset_ = 3 if (
126+
prev_ and prev_.match(T.Keyword, ('GROUP BY', 'ORDER BY'))
127+
) else 0
121128
with offset(self, offset_):
122129
self._process(sgroup)
123130

sqlparse/filters/reindent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def nl(self, offset=0):
5454

5555
def _next_token(self, tlist, idx=-1):
5656
split_words = ('FROM', 'STRAIGHT_JOIN$', 'JOIN$', 'AND', 'OR',
57-
'GROUP', 'ORDER', 'UNION', 'VALUES',
57+
'GROUP BY', 'ORDER BY', 'UNION', 'VALUES',
5858
'SET', 'BETWEEN', 'EXCEPT', 'HAVING', 'LIMIT')
5959
m_split = T.Keyword, split_words, True
6060
tidx, token = tlist.token_next_by(m=m_split, idx=idx)

sqlparse/keywords.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ def is_keyword(value):
7878
(r'UNION\s+ALL\b', tokens.Keyword),
7979
(r'CREATE(\s+OR\s+REPLACE)?\b', tokens.Keyword.DDL),
8080
(r'DOUBLE\s+PRECISION\b', tokens.Name.Builtin),
81+
(r'GROUP\s+BY\b', tokens.Keyword),
82+
(r'ORDER\s+BY\b', tokens.Keyword),
8183

8284
(r'[0-9_A-ZÀ-Ü][_$#\w]*', is_keyword),
8385

sqlparse/sql.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,14 @@ class Where(TokenList):
536536
"""A WHERE clause."""
537537
M_OPEN = T.Keyword, 'WHERE'
538538
M_CLOSE = T.Keyword, (
539-
'ORDER', 'GROUP', 'LIMIT', 'UNION', 'UNION ALL', 'EXCEPT',
539+
'ORDER BY', 'GROUP BY', 'LIMIT', 'UNION', 'UNION ALL', 'EXCEPT',
540540
'HAVING', 'RETURNING', 'INTO')
541541

542542

543543
class Having(TokenList):
544544
"""A HAVING clause."""
545545
M_OPEN = T.Keyword, 'HAVING'
546-
M_CLOSE = T.Keyword, ('ORDER', 'LIMIT')
546+
M_CLOSE = T.Keyword, ('ORDER BY', 'LIMIT')
547547

548548

549549
class Case(TokenList):

tests/test_grouping.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def test_grouping_where():
211211
s = 'select * from foo where bar = 1 order by id desc'
212212
p = sqlparse.parse(s)[0]
213213
assert str(p) == s
214-
assert len(p.tokens) == 14
214+
assert len(p.tokens) == 12
215215

216216
s = 'select x from (select y from foo where bar = 1) z'
217217
p = sqlparse.parse(s)[0]

tests/test_tokenize.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,15 @@ def test_parse_identifiers(s):
183183
token = p.tokens[0]
184184
assert str(token) == s
185185
assert isinstance(token, sql.Identifier)
186+
187+
188+
def test_parse_group_by():
189+
p = sqlparse.parse('GROUP BY')[0]
190+
assert len(p.tokens) == 1
191+
assert p.tokens[0].ttype is T.Keyword
192+
193+
194+
def test_parse_order_by():
195+
p = sqlparse.parse('ORDER BY')[0]
196+
assert len(p.tokens) == 1
197+
assert p.tokens[0].ttype is T.Keyword

0 commit comments

Comments
 (0)