Skip to content

Commit 54551c4

Browse files
authored
Merge branch 'master' into master
2 parents 4dd31c4 + 0dd67c7 commit 54551c4

File tree

8 files changed

+57
-17
lines changed

8 files changed

+57
-17
lines changed

AUTHORS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Alphabetical list of contributors:
1616
* Cristian Orellana <[email protected]>
1717
* Dag Wieers <[email protected]>
1818
* Darik Gamble <[email protected]>
19+
* Demetrio92 <[email protected]>
1920
* Dennis Taylor <[email protected]>
2021
* Florian Bauer <[email protected]>
2122
* Gavin Wahl <[email protected]>
@@ -27,6 +28,7 @@ Alphabetical list of contributors:
2728
* Michael Schuller <[email protected]>
2829
* Mike Amy <[email protected]>
2930
31+
* Oleg Broytman <[email protected]>
3032
* Piet Delport <[email protected]>
3133
* Prudhvi Vatala <[email protected]>
3234

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
Development Version
22
-------------------
33

4+
Enhancements
5+
6+
* Add more keywords for MySQL table options (pr328, pr333, by phdru).
7+
* Add more PL/pgSQL keywords (pr357, by Demetrio92).
8+
49
Bug Fixes
510

11+
* Fix parsing of MySQL table names starting with digits (issue337).
612
* Fix detection of identifiers using comparisons (issue327).
13+
* Fix parsing of UNION ALL after WHERE (issue349).
14+
715

816

917
Release 0.2.3 (Mar 02, 2017)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[wheel]
1+
[bdist_wheel]
22
universal = 1
33

44
[tool:pytest]

sqlparse/keywords.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def is_keyword(value):
1414
val = value.upper()
1515
return (KEYWORDS_COMMON.get(val) or
1616
KEYWORDS_ORACLE.get(val) or
17+
KEYWORDS_PLPGSQL.get(val) or
1718
KEYWORDS.get(val, tokens.Name)), value
1819

1920

@@ -35,7 +36,7 @@ def is_keyword(value):
3536

3637
(r"`(``|[^`])*`", tokens.Name),
3738
(r"´(´´|[^´])*´", tokens.Name),
38-
(r'(\$(?:[_A-Z]\w*)?\$)[\s\S]*?\1', tokens.Literal),
39+
(r'(\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1', tokens.Literal),
3940

4041
(r'\?', tokens.Name.Placeholder),
4142
(r'%(\(\w+\))?s', tokens.Name.Placeholder),
@@ -47,22 +48,20 @@ def is_keyword(value):
4748
# is never a functino, see issue183
4849
(r'(CASE|IN|VALUES|USING)\b', tokens.Keyword),
4950

50-
(r'(@|##|#)[A-Z]\w+', tokens.Name),
51+
(r'(@|##|#)[A-ZÀ-Ü]\w+', tokens.Name),
5152

5253
# see issue #39
5354
# Spaces around period `schema . name` are valid identifier
5455
# TODO: Spaces before period not implemented
55-
(r'[A-Z]\w*(?=\s*\.)', tokens.Name), # 'Name' .
56+
(r'[A-ZÀ-Ü]\w*(?=\s*\.)', tokens.Name), # 'Name' .
5657
# FIXME(atronah): never match,
5758
# because `re.match` doesn't work with lookbehind regexp feature
58-
(r'(?<=\.)[A-Z]\w*', tokens.Name), # .'Name'
59-
(r'[A-Z]\w*(?=\()', tokens.Name), # side effect: change kw to func
60-
59+
(r'(?<=\.)[A-ZÀ-Ü]\w*', tokens.Name), # .'Name'
60+
(r'[A-ZÀ-Ü]\w*(?=\()', tokens.Name), # side effect: change kw to func
6161
(r'-?0x[\dA-F]+', tokens.Number.Hexadecimal),
6262
(r'-?\d*(\.\d+)?E-?\d+', tokens.Number.Float),
6363
(r'-?(\d+(\.\d*)|\.\d+)', tokens.Number.Float),
64-
(r'-?\d+', tokens.Number.Integer),
65-
64+
(r'-?\d+(?![_A-ZÀ-Ü])', tokens.Number.Integer),
6665
(r"'(''|\\\\|\\'|[^'])*'", tokens.String.Single),
6766
# not a real string literal in ANSI SQL:
6867
(r'(""|".*?[^\\]")', tokens.String.Symbol),
@@ -78,7 +77,7 @@ def is_keyword(value):
7877
(r'CREATE(\s+OR\s+REPLACE)?\b', tokens.Keyword.DDL),
7978
(r'DOUBLE\s+PRECISION\b', tokens.Name.Builtin),
8079

81-
(r'[_A-Z][_$#\w]*', is_keyword),
80+
(r'[0-9_A-ZÀ-Ü][_$#\w]*', is_keyword),
8281

8382
(r'[;:()\[\],\.]', tokens.Punctuation),
8483
(r'[<>=~!]+', tokens.Operator.Comparison),
@@ -115,6 +114,7 @@ def is_keyword(value):
115114
'ATOMIC': tokens.Keyword,
116115
'AUDIT': tokens.Keyword,
117116
'AUTHORIZATION': tokens.Keyword,
117+
'AUTO_INCREMENT': tokens.Keyword,
118118
'AVG': tokens.Keyword,
119119

120120
'BACKWARD': tokens.Keyword,
@@ -143,6 +143,7 @@ def is_keyword(value):
143143
'CHARACTER_SET_NAME': tokens.Keyword,
144144
'CHARACTER_SET_SCHEMA': tokens.Keyword,
145145
'CHAR_LENGTH': tokens.Keyword,
146+
'CHARSET': tokens.Keyword,
146147
'CHECK': tokens.Keyword,
147148
'CHECKED': tokens.Keyword,
148149
'CHECKPOINT': tokens.Keyword,
@@ -239,6 +240,7 @@ def is_keyword(value):
239240
'ENCODING': tokens.Keyword,
240241
'ENCRYPTED': tokens.Keyword,
241242
'END-EXEC': tokens.Keyword,
243+
'ENGINE': tokens.Keyword,
242244
'EQUALS': tokens.Keyword,
243245
'ESCAPE': tokens.Keyword,
244246
'EVERY': tokens.Keyword,
@@ -637,7 +639,7 @@ def is_keyword(value):
637639
'SERIAL8': tokens.Name.Builtin,
638640
'SIGNED': tokens.Name.Builtin,
639641
'SMALLINT': tokens.Name.Builtin,
640-
'SYSDATE': tokens.Name.Builtin,
642+
'SYSDATE': tokens.Name,
641643
'TEXT': tokens.Name.Builtin,
642644
'TINYINT': tokens.Name.Builtin,
643645
'UNSIGNED': tokens.Name.Builtin,
@@ -798,3 +800,18 @@ def is_keyword(value):
798800
'UNLIMITED': tokens.Keyword,
799801
'UNLOCK': tokens.Keyword,
800802
}
803+
804+
# PostgreSQL Syntax
805+
KEYWORDS_PLPGSQL = {
806+
'PARTITION': tokens.Keyword,
807+
'OVER': tokens.Keyword,
808+
'PERFORM': tokens.Keyword,
809+
'NOTICE': tokens.Keyword,
810+
'PLPGSQL': tokens.Keyword,
811+
'INHERIT': tokens.Keyword,
812+
'INDEXES': tokens.Keyword,
813+
814+
'FOR': tokens.Keyword,
815+
'IN': tokens.Keyword,
816+
'LOOP': tokens.Keyword,
817+
}

sqlparse/sql.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,9 @@ def is_multiline(self):
526526
class Where(TokenList):
527527
"""A WHERE clause."""
528528
M_OPEN = T.Keyword, 'WHERE'
529-
M_CLOSE = T.Keyword, ('ORDER', 'GROUP', 'LIMIT', 'UNION', 'EXCEPT',
530-
'HAVING', 'RETURNING', 'INTO')
529+
M_CLOSE = T.Keyword, (
530+
'ORDER', 'GROUP', 'LIMIT', 'UNION', 'UNION ALL', 'EXCEPT',
531+
'HAVING', 'RETURNING', 'INTO')
531532

532533

533534
class Case(TokenList):

sqlparse/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ def imt(token, i=None, m=None, t=None):
9595
return False
9696
elif clss and isinstance(token, clss):
9797
return True
98-
elif mpatterns and any((token.match(*pattern) for pattern in mpatterns)):
98+
elif mpatterns and any(token.match(*pattern) for pattern in mpatterns):
9999
return True
100-
elif types and any([token.ttype in ttype for ttype in types]):
100+
elif types and any(token.ttype in ttype for ttype in types):
101101
return True
102102
else:
103103
return False

tests/test_grouping.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ def test_grouping_where():
216216
assert isinstance(p.tokens[-1].tokens[0].tokens[-2], sql.Where)
217217

218218

219+
@pytest.mark.parametrize('s', (
220+
'select 1 where 1 = 2 union select 2',
221+
'select 1 where 1 = 2 union all select 2',
222+
))
223+
def test_grouping_where_union(s):
224+
p = sqlparse.parse(s)[0]
225+
assert p.tokens[5].value.startswith('union')
226+
227+
219228
def test_returning_kw_ends_where_clause():
220229
s = 'delete from foo where x > y returning z'
221230
p = sqlparse.parse(s)[0]

tests/test_parse.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,14 @@ def test_quoted_identifier():
135135
assert t[2].get_real_name() == 'y'
136136

137137

138-
@pytest.mark.parametrize('name', ['foo', '_foo'])
138+
@pytest.mark.parametrize('name', [
139+
'foo', '_foo', # issue175
140+
'1_data', # valid MySQL table name, see issue337
141+
])
139142
def test_valid_identifier_names(name):
140-
# issue175
141143
t = sqlparse.parse(name)[0].tokens
142144
assert isinstance(t[0], sql.Identifier)
145+
assert t[0].get_name() == name
143146

144147

145148
def test_psql_quotation_marks():

0 commit comments

Comments
 (0)