Skip to content

Commit af6df6c

Browse files
skryzhandialbrecht
authored andcommitted
[fix] fixing SQL-Hint deleting when clearing script from comments
1 parent a2c7e64 commit af6df6c

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ MANIFEST
77
.cache/
88
*.egg-info/
99
htmlcov/
10-
.pytest_cache
10+
.pytest_cache
11+
**/.vscode
12+
**/.env

sqlparse/filters/others.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class StripCommentsFilter:
1515

1616
@staticmethod
1717
def _process(tlist):
18-
def get_next_comment():
18+
def get_next_comment(idx=-1):
1919
# TODO(andi) Comment types should be unified, see related issue38
20-
return tlist.token_next_by(i=sql.Comment, t=T.Comment)
20+
return tlist.token_next_by(i=sql.Comment, t=T.Comment, idx=idx)
2121

2222
def _get_insert_token(token):
2323
"""Returns either a whitespace or the line breaks from token."""
@@ -31,15 +31,35 @@ def _get_insert_token(token):
3131
else:
3232
return sql.Token(T.Whitespace, ' ')
3333

34+
sql_hints = (T.Comment.Multiline.Hint, T.Comment.Single.Hint)
3435
tidx, token = get_next_comment()
3536
while token:
37+
# skipping token remove if token is a SQL hint
38+
is_sql_hint = False
39+
if token.ttype in sql_hints:
40+
is_sql_hint = True
41+
elif isinstance(token, sql.Comment):
42+
comment_tokens = token.tokens
43+
if len(comment_tokens) > 0:
44+
if comment_tokens[0].ttype in sql_hints:
45+
is_sql_hint = True
46+
47+
if is_sql_hint:
48+
# using current index as start index to search next token for
49+
# preventing infinite loop in cases when token type is a
50+
# "SQL-Hint"and has to be skipped
51+
tidx, token = get_next_comment(idx=tidx)
52+
continue
53+
3654
pidx, prev_ = tlist.token_prev(tidx, skip_ws=False)
3755
nidx, next_ = tlist.token_next(tidx, skip_ws=False)
3856
# Replace by whitespace if prev and next exist and if they're not
3957
# whitespaces. This doesn't apply if prev or next is a parenthesis.
40-
if (prev_ is None or next_ is None
41-
or prev_.is_whitespace or prev_.match(T.Punctuation, '(')
42-
or next_.is_whitespace or next_.match(T.Punctuation, ')')):
58+
if (
59+
prev_ is None or next_ is None
60+
or prev_.is_whitespace or prev_.match(T.Punctuation, '(')
61+
or next_.is_whitespace or next_.match(T.Punctuation, ')')
62+
):
4363
# Insert a whitespace to ensure the following SQL produces
4464
# a valid SQL (see #425).
4565
if prev_ is not None and not prev_.match(T.Punctuation, '('):
@@ -48,7 +68,10 @@ def _get_insert_token(token):
4868
else:
4969
tlist.tokens[tidx] = _get_insert_token(token)
5070

51-
tidx, token = get_next_comment()
71+
# using current index as start index to search next token for
72+
# preventing infinite loop in cases when token type is a
73+
# "SQL-Hint"and has to be skipped
74+
tidx, token = get_next_comment(idx=tidx)
5275

5376
def process(self, stmt):
5477
[self.process(sgroup) for sgroup in stmt.get_sublists()]

tests/test_format.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,25 @@ def test_strip_comments_single(self):
6161
'from foo--comment\nf'
6262
res = sqlparse.format(sql, strip_comments=True)
6363
assert res == 'select a\nfrom foo\nf'
64+
# SQL-Hints have to be preserved
65+
sql = 'select --+full(u)'
66+
res = sqlparse.format(sql, strip_comments=True)
67+
assert res == sql
68+
sql = '#+ hint\nselect * from foo'
69+
res = sqlparse.format(sql, strip_comments=True)
70+
assert res == sql
71+
72+
sql = 'select --+full(u)\n--comment simple'
73+
res = sqlparse.format(sql, strip_comments=True)
74+
assert res == 'select --+full(u)\n'
75+
76+
sql = '#+ hint\nselect * from foo\n# comment simple'
77+
res = sqlparse.format(sql, strip_comments=True)
78+
assert res == '#+ hint\nselect * from foo\n'
79+
80+
# sql = ''
81+
# res = sqlparse.format(sql, strip_comments=True)
82+
# assert res == ''
6483

6584
def test_strip_comments_invalid_option(self):
6685
sql = 'select-- foo\nfrom -- bar\nwhere'
@@ -83,6 +102,17 @@ def test_strip_comments_multi(self):
83102
sql = 'select (/* sql /* starts here */ select 2)'
84103
res = sqlparse.format(sql, strip_comments=True, strip_whitespace=True)
85104
assert res == 'select (select 2)'
105+
# SQL-Hints have to be preserved
106+
sql = 'SELECT /*+cluster(T)*/* FROM T_EEE T where A >:1'
107+
res = sqlparse.format(sql, strip_comments=True)
108+
assert res == sql
109+
sql = 'insert /*+ DIRECT */ into sch.table_name as select * from foo'
110+
res = sqlparse.format(sql, strip_comments=True)
111+
assert res == sql
112+
113+
sql = ''
114+
res = sqlparse.format(sql, strip_comments=True)
115+
assert res == ''
86116

87117
def test_strip_comments_preserves_linebreak(self):
88118
sql = 'select * -- a comment\r\nfrom foo'

0 commit comments

Comments
 (0)