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 <[email protected]> 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 )
