Fix some major issues with the error context printer (#6772)

There were two major problems:
 * The line immediately before the error was always skipped in the context
 * The long line truncating, which would try to show the contents around
   the error column, would try to do that when truncating context lines too,
   which made no sense and meant that truncated context lines often
   contained newlines.

Additionally, things were complicated by doing a search for each line
instead of doing one search for the error line and indexing from it.

I decided to just get rid of all the truncation logic, since it would mostly
just serve to impede debugging, though it would be possible to do
something more correct than what we do know. (Though I'd bump the
limit up from 120, which is very low.)

Hopefully now this will actually be useful in debugging bootstrap SQL
failures.
This commit is contained in:
Michael J. Sullivan 2024-02-01 22:44:07 -08:00 committed by GitHub
parent 2a43256f8f
commit 6b29802935
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 11 additions and 87 deletions

View file

@ -90,10 +90,6 @@ class ParserContext(markup.MarkupExceptionContext):
def as_markup(cls, self, *, ctx):
me = markup.elements
body = []
lines = []
line_numbers = []
start = self.start_point
# TODO: do more with end?
end = self.end_point
@ -107,94 +103,22 @@ class ParserContext(markup.MarkupExceptionContext):
offset = match.end()
line_offsets.append(offset)
for i in range(self.context_lines + 1, 1, -1):
try:
ctx_line, _ = self._get_line_snippet(
start, offset=-i, line_offsets=line_offsets)
except ValueError:
pass
else:
lines.append(ctx_line)
line_numbers.append(start.line - i)
line_no = bisect.bisect_right(line_offsets, start.offset) - 1
snippet, _ = self._get_line_snippet(start, line_offsets=line_offsets)
lines.append(snippet)
line_numbers.append(start.line)
for i in range(1, self.context_lines + 1):
try:
ctx_line, _ = self._get_line_snippet(
start, offset=i, line_offsets=line_offsets)
except ValueError:
pass
else:
lines.append(ctx_line)
line_numbers.append(start.line + i)
context_start = max(0, line_no - self.context_lines)
context_end = min(line_no + self.context_lines + 1, len(buf_lines))
endcol = end.column if start.line == end.line else None
tbp = me.lang.TracebackPoint(
name=self.name, filename=self.name, lineno=start.line,
colno=start.column, end_colno=endcol,
lines=lines, line_numbers=line_numbers,
context=True)
lines=buf_lines[context_start:context_end],
# Line numbers are 1 indexed here
line_numbers=list(range(context_start + 1, context_end + 1)),
context=True,
)
body.append(tbp)
return me.lang.ExceptionContext(title=self.title, body=body)
def _find_line(self, point, offset=0, *, line_offsets):
len_buffer = len(self.buffer)
if point.line == 0:
if offset < 0:
raise ValueError('not enough lines in buffer')
else:
return 0, len_buffer
line_no = bisect.bisect_right(line_offsets, point.offset) - 1 + offset
if line_no >= len(line_offsets):
raise ValueError('not enough lines in buffer')
# start and end cannot be less than 0 and greater than the
# buffer length
try:
linestart = min(len_buffer, max(0, line_offsets[line_no]))
except IndexError:
if line_no < 0:
# Can't be negative
linestart = 0
else:
# Can't be beyond the buffer's length
linestart = len_buffer
try:
lineend = min(len_buffer, max(0, line_offsets[line_no + 1] - 1))
except IndexError:
if line_no + 1 < 0:
# Can't be negative
lineend = 0
else:
# Can't be beyond the buffer's length
lineend = len_buffer
return linestart, lineend
def _get_line_snippet(
self, point, max_length=120, *, offset=0, line_offsets):
line_start, line_end = self._find_line(
point, offset=offset, line_offsets=line_offsets)
line_len = line_end - line_start
if line_len > max_length:
before = min(max_length // 2, point.offset - line_start)
after = max_length - before
else:
before = point.offset - line_start
after = line_len - before
start = point.offset - before
end = point.offset + after
return self.buffer[start:end], before
return me.lang.ExceptionContext(title=self.title, body=[tbp])
def _get_context(items, *, reverse=False):

View file

@ -7272,11 +7272,11 @@ async def execute_sql_script(
text = None
if position is not None:
point = int(position)
point = int(position) - 1
text = sql_text
elif internal_position is not None:
point = int(internal_position)
point = int(internal_position) - 1
text = e.get_field('q')
elif pl_func_line: