Skip to content

Commit

Permalink
Show SQL query when reporting time limit error, closes #1819
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Sep 26, 2022
1 parent 212137a commit 5f9f567
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 13 deletions.
5 changes: 4 additions & 1 deletion datasette/database.py
Expand Up @@ -476,7 +476,10 @@ def __init__(self, fn, task_id, reply_queue):


class QueryInterrupted(Exception):
pass
def __init__(self, e, sql, params):
self.e = e
self.sql = sql
self.params = params


class MultipleValues(Exception):
Expand Down
21 changes: 13 additions & 8 deletions datasette/views/base.py
@@ -1,10 +1,12 @@
import asyncio
import csv
import hashlib
import re
import sys
import textwrap
import time
import urllib
from markupsafe import escape


import pint

Expand All @@ -24,11 +26,9 @@
path_with_removed_args,
path_with_format,
sqlite3,
HASH_LENGTH,
)
from datasette.utils.asgi import (
AsgiStream,
Forbidden,
NotFound,
Response,
BadRequest,
Expand Down Expand Up @@ -371,13 +371,18 @@ async def get(self, request):
) = response_or_template_contexts
else:
data, extra_template_data, templates = response_or_template_contexts
except QueryInterrupted:
except QueryInterrupted as ex:
raise DatasetteError(
"""
SQL query took too long. The time limit is controlled by the
textwrap.dedent(
"""
<p>SQL query took too long. The time limit is controlled by the
<a href="https://docs.datasette.io/en/stable/settings.html#sql-time-limit-ms">sql_time_limit_ms</a>
configuration option.
""",
configuration option.</p>
<pre>{}</pre>
""".format(
escape(ex.sql)
)
).strip(),
title="SQL Interrupted",
status=400,
message_is_html=True,
Expand Down
12 changes: 11 additions & 1 deletion tests/test_api.py
Expand Up @@ -656,7 +656,17 @@ def test_custom_sql(app_client):
def test_sql_time_limit(app_client_shorter_time_limit):
response = app_client_shorter_time_limit.get("/fixtures.json?sql=select+sleep(0.5)")
assert 400 == response.status
assert "SQL Interrupted" == response.json["title"]
assert response.json == {
"ok": False,
"error": (
"<p>SQL query took too long. The time limit is controlled by the\n"
'<a href="https://docs.datasette.io/en/stable/settings.html#sql-time-limit-ms">sql_time_limit_ms</a>\n'
"configuration option.</p>\n"
"<pre>select sleep(0.5)</pre>"
),
"status": 400,
"title": "SQL Interrupted",
}


def test_custom_sql_time_limit(app_client):
Expand Down
10 changes: 7 additions & 3 deletions tests/test_html.py
Expand Up @@ -168,10 +168,14 @@ def test_disallowed_custom_sql_pragma(app_client):
def test_sql_time_limit(app_client_shorter_time_limit):
response = app_client_shorter_time_limit.get("/fixtures?sql=select+sleep(0.5)")
assert 400 == response.status
expected_html_fragment = """
expected_html_fragments = [
"""
<a href="https://docs.datasette.io/en/stable/settings.html#sql-time-limit-ms">sql_time_limit_ms</a>
""".strip()
assert expected_html_fragment in response.text
""".strip(),
"<pre>select sleep(0.5)</pre>",
]
for expected_html_fragment in expected_html_fragments:
assert expected_html_fragment in response.text


def test_row_page_does_not_truncate():
Expand Down

0 comments on commit 5f9f567

Please sign in to comment.