summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndi Albrecht <albrecht.andi@gmail.com>2013-04-05 05:46:41 +0200
committerAndi Albrecht <albrecht.andi@gmail.com>2013-04-05 05:46:41 +0200
commit341143e294c842d700dfd3c6a6224c05d8b8b8d6 (patch)
treef58da4333925db8f320ffae40d219a758786a234
parentbd530692165729051a4caf28934a6e9ad32fbc3e (diff)
downloadsqlparse-341143e294c842d700dfd3c6a6224c05d8b8b8d6.tar.gz
Add order criterion to identifier in ORDER BY clause (fixes #89).
-rw-r--r--CHANGES3
-rw-r--r--sqlparse/engine/grouping.py15
-rw-r--r--sqlparse/keywords.py4
-rw-r--r--sqlparse/sql.py7
-rw-r--r--tests/test_format.py11
-rw-r--r--tests/test_grouping.py11
6 files changed, 48 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index bca59c1..471615c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,9 +9,10 @@ Bug Fixes
invalid SQL statements.
Enhancements
- * Improve parsing speed when SQL contains CLOBs or BLOBs (issue86).
* Top-level API functions now accept encoding keyword to parse
statements in certain encodings more reliable (issue20).
+ * Improve parsing speed when SQL contains CLOBs or BLOBs (issue86).
+ * Improve formatting of ORDER BY clauses (issue89).
Other
* Documentation updates.
diff --git a/sqlparse/engine/grouping.py b/sqlparse/engine/grouping.py
index 0f39dd2..d03e483 100644
--- a/sqlparse/engine/grouping.py
+++ b/sqlparse/engine/grouping.py
@@ -332,6 +332,20 @@ def group_functions(tlist):
token = tlist.token_next_by_type(idx, T.Name)
+def group_order(tlist):
+ idx = 0
+ token = tlist.token_next_by_type(idx, T.Keyword.Order)
+ while token:
+ prev = tlist.token_prev(token)
+ if isinstance(prev, sql.Identifier):
+ ido = tlist.group_tokens(sql.Identifier,
+ tlist.tokens_between(prev, token))
+ idx = tlist.token_index(ido) + 1
+ else:
+ idx = tlist.token_index(token) + 1
+ token = tlist.token_next_by_type(idx, T.Keyword.Order)
+
+
def group(tlist):
for func in [
group_comments,
@@ -340,6 +354,7 @@ def group(tlist):
group_where,
group_case,
group_identifier,
+ group_order,
group_typecasts,
group_as,
group_aliased,
diff --git a/sqlparse/keywords.py b/sqlparse/keywords.py
index c11a3a6..ed741d4 100644
--- a/sqlparse/keywords.py
+++ b/sqlparse/keywords.py
@@ -17,7 +17,7 @@ KEYWORDS = {
'ANALYZE': tokens.Keyword,
'ANY': tokens.Keyword,
'ARE': tokens.Keyword,
- 'ASC': tokens.Keyword,
+ 'ASC': tokens.Keyword.Order,
'ASENSITIVE': tokens.Keyword,
'ASSERTION': tokens.Keyword,
'ASSIGNMENT': tokens.Keyword,
@@ -124,7 +124,7 @@ KEYWORDS = {
'DELIMITER': tokens.Keyword,
'DELIMITERS': tokens.Keyword,
'DEREF': tokens.Keyword,
- 'DESC': tokens.Keyword,
+ 'DESC': tokens.Keyword.Order,
'DESCRIBE': tokens.Keyword,
'DESCRIPTOR': tokens.Keyword,
'DESTROY': tokens.Keyword,
diff --git a/sqlparse/sql.py b/sqlparse/sql.py
index 6fb99c6..7b495a9 100644
--- a/sqlparse/sql.py
+++ b/sqlparse/sql.py
@@ -495,6 +495,13 @@ class Identifier(TokenList):
return None
return unicode(next_)
+ def get_ordering(self):
+ """Returns the ordering or ``None`` as uppercase string."""
+ ordering = self.token_next_by_type(0, T.Keyword.Order)
+ if ordering is None:
+ return None
+ return ordering.value.upper()
+
class IdentifierList(TokenList):
"""A list of :class:`~sqlparse.sql.Identifier`\'s."""
diff --git a/tests/test_format.py b/tests/test_format.py
index c33ac93..17bdc17 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -267,3 +267,14 @@ class TestOutputFormat(TestCaseBase):
sql = 'select * from foo;'
f = lambda sql: sqlparse.format(sql, output_format='sql')
self.ndiffAssertEqual(f(sql), 'select * from foo;')
+
+
+def test_format_column_ordering(): # issue89
+ sql = 'select * from foo order by c1 desc, c2, c3;'
+ formatted = sqlparse.format(sql, reindent=True)
+ expected = '\n'.join(['select *',
+ 'from foo',
+ 'order by c1 desc,',
+ ' c2,',
+ ' c3;'])
+ assert formatted == expected
diff --git a/tests/test_grouping.py b/tests/test_grouping.py
index 345e62f..674982f 100644
--- a/tests/test_grouping.py
+++ b/tests/test_grouping.py
@@ -231,3 +231,14 @@ def test_identifier_string_concat():
p = sqlparse.parse('\'foo\' || bar')[0]
assert len(p.tokens) == 1
assert isinstance(p.tokens[0], sql.Identifier)
+
+
+def test_identifier_consumes_ordering(): # issue89
+ p = sqlparse.parse('select * from foo order by c1 desc, c2, c3')[0]
+ assert isinstance(p.tokens[-1], sql.IdentifierList)
+ ids = list(p.tokens[-1].get_identifiers())
+ assert len(ids) == 3
+ assert ids[0].get_name() == 'c1'
+ assert ids[0].get_ordering() == 'DESC'
+ assert ids[1].get_name() == 'c2'
+ assert ids[1].get_ordering() is None