Show SQL query when reporting time limit error, closes #1819

pull/1465/merge
Simon Willison 2022-09-26 16:06:01 -07:00
rodzic 212137a90b
commit 5f9f567acb
4 zmienionych plików z 35 dodań i 13 usunięć

Wyświetl plik

@ -476,7 +476,10 @@ class WriteTask:
class QueryInterrupted(Exception): class QueryInterrupted(Exception):
pass def __init__(self, e, sql, params):
self.e = e
self.sql = sql
self.params = params
class MultipleValues(Exception): class MultipleValues(Exception):

Wyświetl plik

@ -1,10 +1,12 @@
import asyncio import asyncio
import csv import csv
import hashlib import hashlib
import re
import sys import sys
import textwrap
import time import time
import urllib import urllib
from markupsafe import escape
import pint import pint
@ -24,11 +26,9 @@ from datasette.utils import (
path_with_removed_args, path_with_removed_args,
path_with_format, path_with_format,
sqlite3, sqlite3,
HASH_LENGTH,
) )
from datasette.utils.asgi import ( from datasette.utils.asgi import (
AsgiStream, AsgiStream,
Forbidden,
NotFound, NotFound,
Response, Response,
BadRequest, BadRequest,
@ -371,13 +371,18 @@ class DataView(BaseView):
) = response_or_template_contexts ) = response_or_template_contexts
else: else:
data, extra_template_data, templates = response_or_template_contexts data, extra_template_data, templates = response_or_template_contexts
except QueryInterrupted: except QueryInterrupted as ex:
raise DatasetteError( raise DatasetteError(
""" textwrap.dedent(
SQL query took too long. The time limit is controlled by the """
<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> <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", title="SQL Interrupted",
status=400, status=400,
message_is_html=True, message_is_html=True,

Wyświetl plik

@ -656,7 +656,17 @@ def test_custom_sql(app_client):
def test_sql_time_limit(app_client_shorter_time_limit): def test_sql_time_limit(app_client_shorter_time_limit):
response = app_client_shorter_time_limit.get("/fixtures.json?sql=select+sleep(0.5)") response = app_client_shorter_time_limit.get("/fixtures.json?sql=select+sleep(0.5)")
assert 400 == response.status 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): def test_custom_sql_time_limit(app_client):

Wyświetl plik

@ -168,10 +168,14 @@ def test_disallowed_custom_sql_pragma(app_client):
def test_sql_time_limit(app_client_shorter_time_limit): def test_sql_time_limit(app_client_shorter_time_limit):
response = app_client_shorter_time_limit.get("/fixtures?sql=select+sleep(0.5)") response = app_client_shorter_time_limit.get("/fixtures?sql=select+sleep(0.5)")
assert 400 == response.status 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> <a href="https://docs.datasette.io/en/stable/settings.html#sql-time-limit-ms">sql_time_limit_ms</a>
""".strip() """.strip(),
assert expected_html_fragment in response.text "<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(): def test_row_page_does_not_truncate():