I3eka commented on code in PR #45561:
URL: https://github.com/apache/superset/pull/45561#discussion_r4384232656


##########
superset/sql/execution/executor.py:
##########
@@ -680,16 +683,24 @@ def execute(
                 QueryStatus.TIMED_OUT,
                 "Query exceeded the timeout limit",
                 start_time,
+                query=query,
             )
         except SupersetSecurityException as ex:
-            return self._create_error_result(QueryStatus.FAILED, str(ex), 
start_time)
-        except (OAuth2RedirectError, OAuth2Error):
+            return self._create_error_result(
+                QueryStatus.FAILED, str(ex), start_time, query=query
+            )
+        except (OAuth2RedirectError, OAuth2Error) as ex:
             # Let OAuth2 exceptions propagate so callers (MCP, API) can
             # handle them with context-appropriate responses.
+            self._create_error_result(
+                QueryStatus.FAILED, str(ex), start_time, query=query
+            )
             raise

Review Comment:
   Rechecked on c8c079654469 after merging Apache master 1220ec01ef85. 
`_create_error_result` catches metadata persistence failures and suppresses 
recovery rollback failures. The OAuth handlers still re-raise the original 
exception object; the regression covers both commit and rollback failures. No 
further code change is needed for this case.



##########
superset/sql/execution/executor.py:
##########
@@ -1008,14 +1020,24 @@ def _create_error_result(
         :param start_time: Start time for calculating execution duration
         :param partial_results: Optional list of StatementResult from 
successful
             statements before the failure
+        :param query: Persisted audit record, if execution reached that stage
         :returns: QueryResult with error status
         """
         from superset_core.queries.types import QueryResult as QueryResultType
 
+        if query is not None:
+            # A failed metadata flush must be rolled back before recording 
failure.
+            db.session.rollback()  # pylint: disable=consider-using-transaction
+            query.status = status.value

Review Comment:
   Rechecked on c8c079654469. Failure finalization uses 
`commit_query_unless_stopped`, whose conditional write preserves an accepted 
Stop. The regression commits Stop through a second SQLAlchemy session between 
the read and failure write, then verifies status, end time and cancellation 
metadata even after a later caller commit. It passes.



##########
superset/sql/execution/executor.py:
##########
@@ -577,6 +579,7 @@ def execute(
 
         opts: QueryOptionsType = options or QueryOptionsType()
         start_time = time.time()
+        query: Query | None = None

Review Comment:
   This is a false positive on c8c079654469: the module already has `from 
__future__ import annotations`, and a function-local variable annotation does 
not evaluate `Query` at runtime. A fresh-process import succeeds with no 
`Query` binding in the module globals. The executor tests also pass without 
adding a runtime import.



##########
superset/sql/execution/executor.py:
##########
@@ -1166,7 +1203,7 @@ def _create_query_record(
         catalog: str | None,
         schema: str | None,
         status: QueryStatus,
-    ) -> Any:
+    ) -> Query:

Review Comment:
   This is covered by the existing `from __future__ import annotations`. On 
c8c079654469, a fresh-process check confirms that 
`_create_query_record.__annotations__["return"]` is the string `"Query"`, while 
`Query` is absent from module globals. No additional import or quoting is 
required.



##########
superset/sql/execution/executor.py:
##########
@@ -1008,14 +1020,39 @@ def _create_error_result(
         :param start_time: Start time for calculating execution duration
         :param partial_results: Optional list of StatementResult from 
successful
             statements before the failure
+        :param query: Persisted audit record, if execution reached that stage
         :returns: QueryResult with error status
         """
-        from superset_core.queries.types import QueryResult as QueryResultType
+        from superset_core.queries.types import (
+            QueryResult as QueryResultType,
+            QueryStatus,
+        )
+
+        from superset.sql.execution.utils import commit_query_unless_stopped
+
+        query_id = None
+        if query is not None:
+            try:
+                # A failed metadata flush must be rolled back before recording 
failure.
+                db.session.rollback()  # pylint: 
disable=consider-using-transaction
+                query_id = query.id

Review Comment:
   Rechecked on c8c079654469. The initial rollback runs only when 
`db.session.is_active` is false. Real-session regressions cover both a healthy 
transaction with unrelated pending changes and a failed flush requiring 
rollback; they pass. The exception handler still attempts rollback if 
finalization itself fails.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to