Fix 500 error when accessing query page without ?sql= parameter (#2744)

Closes #2743
This commit is contained in:
Simon Willison 2026-05-25 12:33:57 -07:00 committed by GitHub
commit de55a76d40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 50 additions and 24 deletions

View file

@ -46,14 +46,14 @@
{% if not hide_sql %}
{% if editable and allow_execute_sql %}
<p><textarea id="sql-editor" name="sql"{% if query and query.sql %} style="height: {{ query.sql.split("\n")|length + 2 }}em"{% endif %}
>{% if query and query.sql %}{{ query.sql }}{% else %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}</textarea></p>
>{% if query and query.sql %}{{ query.sql }}{% elif tables %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}</textarea></p>
{% else %}
<pre id="sql-query">{% if query %}{{ query.sql }}{% endif %}</pre>
{% endif %}
{% else %}
{% if not canned_query %}
<input type="hidden" name="sql"
value="{% if query and query.sql %}{{ query.sql }}{% else %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}"
value="{% if query and query.sql %}{{ query.sql }}{% elif tables %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}"
>
{% endif %}
{% endif %}

View file

@ -577,7 +577,7 @@ class QueryView(View):
named_parameters = []
if canned_query and canned_query.get("params"):
named_parameters = canned_query["params"]
if not named_parameters:
if not named_parameters and sql:
named_parameters = derive_named_parameters(sql)
named_parameter_values = {
named_parameter: params.get(named_parameter) or ""
@ -602,7 +602,7 @@ class QueryView(View):
params_for_query = params
if not canned_query_write:
if sql and not canned_query_write:
try:
if not canned_query:
# For regular queries we only allow SELECT, plus other rules
@ -646,6 +646,8 @@ class QueryView(View):
# Handle formats from plugins
if format_ == "csv":
if not sql:
raise DatasetteError("?sql= is required", status=400)
async def fetch_data_for_csv(request, _next=None):
results = await db.execute(sql, params, truncate=True)
@ -771,25 +773,26 @@ class QueryView(View):
# - No magic parameters, so no :_ in the SQL string
edit_sql_url = None
is_validated_sql = False
try:
validate_sql_select(sql)
is_validated_sql = True
except InvalidSql:
pass
if allow_execute_sql and is_validated_sql and ":_" not in sql:
edit_sql_url = (
datasette.urls.database(database)
+ "/-/query"
+ "?"
+ urlencode(
{
**{
"sql": sql,
},
**named_parameter_values,
}
if sql:
try:
validate_sql_select(sql)
is_validated_sql = True
except InvalidSql:
pass
if allow_execute_sql and is_validated_sql and ":_" not in sql:
edit_sql_url = (
datasette.urls.database(database)
+ "/-/query"
+ "?"
+ urlencode(
{
**{
"sql": sql,
},
**named_parameter_values,
}
)
)
)
async def query_actions():
query_actions = []

View file

@ -4,6 +4,13 @@
Changelog
=========
.. _v1_0_unreleased:
Unreleased
----------
- Fixed a bug where visiting ``/<database>/-/query`` without a ``?sql=`` parameter returned a 500 error. (:issue:`2743`)
.. _v1_0_a30:
1.0a30 (2026-05-24)

View file

@ -387,8 +387,8 @@ def view_actions(datasette, database, view, actor):
@hookimpl
def query_actions(datasette, database, query_name, sql):
# Don't explain an explain
if sql.lower().startswith("explain"):
# Don't explain an explain (or a missing query)
if not sql or sql.lower().startswith("explain"):
return
return [
{

View file

@ -241,6 +241,22 @@ def test_query_page_truncates():
]
@pytest.mark.asyncio
async def test_query_page_with_no_sql(ds_client):
# https://github.com/simonw/datasette/issues/2743
response = await ds_client.get("/fixtures/-/query")
assert response.status_code == 200
assert '<textarea id="sql-editor" name="sql"' in response.text
assert 'class="rows-and-columns"' not in response.text
@pytest.mark.asyncio
async def test_query_csv_with_no_sql_is_400(ds_client):
# https://github.com/simonw/datasette/issues/2743
response = await ds_client.get("/fixtures/-/query.csv")
assert response.status_code == 400
@pytest.mark.asyncio
@pytest.mark.parametrize(
"path,expected_classes",