You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2026/10/10 19:35:06 UTC
(superset) 02/02: fix(sqllab): commit the recomputed row limit before async dispatch
This is an automated email from the ASF dual-hosted git repository.
sadpandajoe pushed a commit to branch fix-sqllab-async-limit-race
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 29374482b199355962866ff267612362618f3084
Author: Joe Li <jo...@preset.io>
AuthorDate: Sat Oct 10 19:31:06 2026 +0000
fix(sqllab): commit the recomputed row limit before async dispatch
ExecuteSqlCommand recomputes query.limit as min(the query's own SQL
LIMIT, the row-limit dropdown) and updates it in place, but never
commits before ASynchronousSqlJsonExecutor hands the query off to a
Celery worker via .delay(). @transaction() on run() only commits after
the whole method returns, which can be after an idle worker has
already re-fetched the query on its own connection. Under READ
COMMITTED, that worker then sees the row's limit as it was at creation
time -- the raw dropdown value -- instead of the smaller value just
computed from the query's own LIMIT, so the dropdown silently wins
whenever it is the larger of the two. Same mechanism as #40070.
---
superset/commands/sql_lab/execute.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/superset/commands/sql_lab/execute.py b/superset/commands/sql_lab/execute.py
index 99ed73fdef7..e2ada480438 100644
--- a/superset/commands/sql_lab/execute.py
+++ b/superset/commands/sql_lab/execute.py
@@ -164,6 +164,18 @@ class ExecuteSqlCommand(BaseCommand):
self._query_dao.update(
query, {"limit": self._execution_context.query.limit}
)
+ # Commit now, before dispatch. The async executor below hands off to
+ # a Celery worker that re-fetches this query on its own connection
+ # (`get_query` in superset/sql_lab.py); under READ COMMITTED that
+ # worker only sees the limit recomputed just above once it is
+ # committed. `@transaction()` on `run()` only commits after this
+ # whole method returns, which is too late: `.delay()` can hand the
+ # task to an already-idle worker before that commit lands, so the
+ # worker reads back the row's limit as it was at creation time (the
+ # raw dropdown value from `create_query()`) instead of the smaller
+ # value just computed from the query's own SQL LIMIT. Same race and
+ # fix as apache/superset#40070.
+ db.session.commit() # pylint: disable=consider-using-transaction
return self._sql_json_executor.execute(
self._execution_context, rendered_query, self._log_params
)