Skip to content

Commit fa7def0

Browse files
fredywandialbrecht
authored andcommitted
Fix formatting on INSERT (fixes andialbrecht#329)
This patch fixes the formatting on INSERT by creating a new instance of sql.Values to group all the values. SQL: insert into foo values (1, 'foo'), (2, 'bar'), (3, 'baz') Before: insert into foo values (1, 'foo'), (2, 'bar'), (3, 'baz') After: insert into foo values (1, 'foo'), (2, 'bar'), (3, 'baz')
1 parent 53dd1d5 commit fa7def0

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

sqlparse/engine/grouping.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,18 @@ def align_comments(tlist):
327327
tidx, token = tlist.token_next_by(i=sql.Comment, idx=tidx)
328328

329329

330+
def group_values(tlist):
331+
tidx, token = tlist.token_next_by(m=(T.Keyword, 'VALUES'))
332+
start_idx = tidx
333+
end_idx = -1
334+
while token:
335+
if isinstance(token, sql.Parenthesis):
336+
end_idx = tidx
337+
tidx, token = tlist.token_next(tidx)
338+
if end_idx != -1:
339+
tlist.group_tokens(sql.Values, start_idx, end_idx, extend=True)
340+
341+
330342
def group(stmt):
331343
for func in [
332344
group_comments,
@@ -354,6 +366,7 @@ def group(stmt):
354366

355367
align_comments,
356368
group_identifier_list,
369+
group_values,
357370
]:
358371
func(stmt)
359372
return stmt

sqlparse/filters/reindent.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def _process_identifierlist(self, tlist):
133133
first = next(identifiers.pop(0).flatten())
134134
num_offset = 1 if self.char == '\t' else self._get_offset(first)
135135

136-
if not tlist.within(sql.Function):
136+
if not tlist.within(sql.Function) and not tlist.within(sql.Values):
137137
with offset(self, num_offset):
138138
position = 0
139139
for token in identifiers:
@@ -206,6 +206,23 @@ def _process_case(self, tlist):
206206
if end_idx is not None:
207207
tlist.insert_before(end_idx, self.nl())
208208

209+
def _process_values(self, tlist):
210+
tlist.insert_before(0, self.nl())
211+
tidx, token = tlist.token_next_by(i=sql.Parenthesis)
212+
first_token = token
213+
while token:
214+
ptidx, ptoken = tlist.token_next_by(m=(T.Punctuation, ','),
215+
idx=tidx)
216+
if ptoken:
217+
if self.comma_first:
218+
adjust = -2
219+
offset = self._get_offset(first_token) + adjust
220+
tlist.insert_before(ptoken, self.nl(offset))
221+
else:
222+
tlist.insert_after(ptoken,
223+
self.nl(self._get_offset(token)))
224+
tidx, token = tlist.token_next_by(i=sql.Parenthesis, idx=tidx)
225+
209226
def _process_default(self, tlist, stmts=True):
210227
self._split_statements(tlist) if stmts else None
211228
self._split_kwds(tlist)

sqlparse/sql.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,3 +621,7 @@ class Begin(TokenList):
621621

622622
class Operation(TokenList):
623623
"""Grouping of operations"""
624+
625+
626+
class Values(TokenList):
627+
"""Grouping of values"""

tests/test_format.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,49 @@ def test_identifier_and_functions(self):
554554
' nvl(1)',
555555
'from dual'])
556556

557+
def test_insert_values(self):
558+
# issue 329
559+
f = lambda sql: sqlparse.format(sql, reindent=True)
560+
s = 'insert into foo values (1, 2)'
561+
assert f(s) == '\n'.join([
562+
'insert into foo',
563+
'values (1, 2)'])
564+
565+
s = 'insert into foo values (1, 2), (3, 4), (5, 6)'
566+
assert f(s) == '\n'.join([
567+
'insert into foo',
568+
'values (1, 2),',
569+
' (3, 4),',
570+
' (5, 6)'])
571+
572+
s = 'insert into foo(a, b) values (1, 2), (3, 4), (5, 6)'
573+
assert f(s) == '\n'.join([
574+
'insert into foo(a, b)',
575+
'values (1, 2),',
576+
' (3, 4),',
577+
' (5, 6)'])
578+
579+
f = lambda sql: sqlparse.format(sql, reindent=True,
580+
comma_first=True)
581+
s = 'insert into foo values (1, 2)'
582+
assert f(s) == '\n'.join([
583+
'insert into foo',
584+
'values (1, 2)'])
585+
586+
s = 'insert into foo values (1, 2), (3, 4), (5, 6)'
587+
assert f(s) == '\n'.join([
588+
'insert into foo',
589+
'values (1, 2)',
590+
' , (3, 4)',
591+
' , (5, 6)'])
592+
593+
s = 'insert into foo(a, b) values (1, 2), (3, 4), (5, 6)'
594+
assert f(s) == '\n'.join([
595+
'insert into foo(a, b)',
596+
'values (1, 2)',
597+
' , (3, 4)',
598+
' , (5, 6)'])
599+
557600

558601
class TestOutputFormat(object):
559602
def test_python(self):

tests/test_grouping.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@ def test_grouping_identifiers():
4949
assert str(parsed) == s
5050
assert isinstance(parsed.tokens[-1].tokens[3], sql.Identifier)
5151

52-
s = "INSERT INTO `test` VALUES('foo', 'bar');"
53-
parsed = sqlparse.parse(s)[0]
54-
types = [l.ttype for l in parsed.tokens if not l.is_whitespace]
55-
assert types == [T.DML, T.Keyword, None, T.Keyword, None, T.Punctuation]
52+
for s in ["INSERT INTO `test` VALUES('foo', 'bar');",
53+
"INSERT INTO `test` VALUES(1, 2), (3, 4), (5, 6);",
54+
"INSERT INTO `test(a, b)` VALUES(1, 2), (3, 4), (5, 6);"]:
55+
parsed = sqlparse.parse(s)[0]
56+
types = [l.ttype for l in parsed.tokens if not l.is_whitespace]
57+
assert types == [T.DML, T.Keyword, None, None, T.Punctuation]
58+
assert isinstance(parsed.tokens[6], sql.Values)
5659

5760
s = "select 1.0*(a+b) as col, sum(c)/sum(d) from myschema.mytable"
5861
parsed = sqlparse.parse(s)[0]

0 commit comments

Comments
 (0)