Skip to content

Commit 378d38b

Browse files
committed
Improve error matching on missing EOF
1 parent f096369 commit 378d38b

File tree

5 files changed

+66
-12
lines changed

5 files changed

+66
-12
lines changed

CHANGES.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
# Changelog
22

33
## Unreleased
4+
- Fix error matching issue when missing EOF
5+
6+
## 2024/10/25 v0.0.9
7+
- Set CrateDB version to 5.8.3
8+
- Fix error matching issue due to wrong error.query trimming in find_suitable_error
9+
10+
## 2024/10/16 v0.0.8
411
- Export `Statement` in both Python and Javascript target
512
- Fixed query parsing when expression includes special characters like `\n`, `\r`, or `\t`
613
- Fixed sqlparse crash on missing error context
7-
- Set CrateDB version to 5.8.3
814

915
## 2024/09/18 v0.0.7
10-
- Improve error matching on single statement
16+
- Improve error matching on single statements
1117

1218
## v0.0.6 skipped
1319

cratedb_sqlparse_js/cratedb_sqlparse/parser.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class ExceptionCollectorListener extends ErrorListener {
135135

136136
} else {
137137
const min_to_check = Math.max(1, offendingSymbol.tokenIndex - 2)
138-
const tokens = recognizer.getTokenStream().tokens.slice(min_to_check, offendingSymbol.tokenIndex + 1)
138+
const tokens = recognizer.getTokenStream().tokens.slice(min_to_check, offendingSymbol.tokenIndex)
139139
query = tokens.map((el) => el.text).join("")
140140
}
141141

@@ -192,7 +192,7 @@ function findSuitableError(statement, errors) {
192192
errorQuery = errorQuery.trimStart().trimEnd()
193193

194194
// If a good match error_query contains statement.query
195-
if (errorQuery.includes(statement.query)) {
195+
if (statement.query.includes(errorQuery)) {
196196
statement.exception = error;
197197
errors.splice(errors.indexOf(error), 1);
198198
}

cratedb_sqlparse_js/tests/exceptions.test.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ test('Special characters should not avoid exception catching', () => {
114114
]
115115
for (const stmt in stmts) {
116116
let r = sqlparse(stmt)
117-
expect(r[0].exception).toBeDefined();
117+
expect(r[0].exception).not.toBeNull();
118118
}
119119
})
120120

@@ -146,8 +146,29 @@ test('Special query with several errors should correctly be matched regardless o
146146
]
147147
for (const stmt of stmts) {
148148
const r = sqlparse(stmt)
149-
expect(r[0].exception).toBeDefined()
149+
expect(r[0].exception).not.toBeNull()
150150
expect(r[1].exception).toBeNull()
151-
expect(r[2].exception).toBeDefined()
151+
expect(r[2].exception).not.toBeNull()
152+
}
153+
})
154+
155+
test('Missing EOF should not block error catching', () => {
156+
const stmts = [
157+
`
158+
select 1;
159+
select 2
160+
select 3;
161+
`,
162+
`
163+
select 1;
164+
select 1 I can put anything here
165+
select 3
166+
`
167+
]
168+
169+
for (const stmt of stmts) {
170+
const r = sqlparse(stmt)
171+
expect(r[0].exception).toBeNull()
172+
expect(r[1].exception).not.toBeNull()
152173
}
153174
})

cratedb_sqlparse_py/cratedb_sqlparse/parser.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
128128
# The newly generated query will be either the offendingToken + one token to the left
129129
# or offendingToken + two tokens to the left, if the second is possible it takes precedence.
130130
min_token_to_check = max(1, offendingSymbol.tokenIndex - 2)
131-
tokens = recognizer.getTokenStream().tokens[min_token_to_check : offendingSymbol.tokenIndex + 1]
131+
tokens = recognizer.getTokenStream().tokens
132+
133+
tokens = tokens[min_token_to_check : offendingSymbol.tokenIndex]
132134
query = "".join(token.text for token in tokens)
133135

134136
error = ParsingException(
@@ -184,16 +186,14 @@ def __repr__(self):
184186

185187
def find_suitable_error(statement, errors):
186188
for error in errors[:]:
187-
# We clean the error_query of ';' and spaces because ironically,
188-
# we can get the full query in the error but not in the parsed statement.
189189
error_query = error.query
190190
if error_query.endswith(";"):
191191
error_query = error_query[: len(error_query) - 1]
192192

193193
error_query = error_query.lstrip().rstrip()
194194

195-
# If a good match error_query contains statement.query
196-
if statement.query in error_query:
195+
# If a good match, error_query contains statement.query
196+
if error_query in statement.query:
197197
statement.exception = error
198198
errors.pop(errors.index(error))
199199

cratedb_sqlparse_py/tests/test_exceptions.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,30 @@ def test_sqlparse_match_exceptions_spaces():
156156
assert r[0]
157157
assert r[1]
158158
assert r[2]
159+
160+
161+
def test_sqlparse_match_exception_missing_eof():
162+
"""
163+
Statements that miss an eof should be detected as one, and catch the appropriate exception
164+
165+
See https://github.com/crate/cratedb-sqlparse/issues/113
166+
"""
167+
from cratedb_sqlparse import sqlparse
168+
169+
stmts = [
170+
"""
171+
select 1;
172+
select 2
173+
select 3;
174+
""",
175+
"""
176+
select 1;
177+
select 1 I can put anything here
178+
select 3
179+
""",
180+
]
181+
for stmt in stmts:
182+
r = sqlparse(stmt)
183+
assert len(r) == 2
184+
assert not r[0].exception
185+
assert r[1].exception

0 commit comments

Comments
 (0)