You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2023/11/08 12:59:21 UTC

(superset) 04/04: fix: trino cursor (#25897)

This is an automated email from the ASF dual-hosted git repository.

michaelsmolina pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/superset.git

commit d265bd2ffcaed2bb5f2ba7dd139afeb9c5654645
Author: Beto Dealmeida <ro...@dealmeida.net>
AuthorDate: Wed Nov 8 07:38:38 2023 -0500

    fix: trino cursor (#25897)
    
    (cherry picked from commit cdb18e04ffa7d50120a26af990d1ce35b2bd8b5e)
---
 superset/db_engine_specs/trino.py | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/superset/db_engine_specs/trino.py b/superset/db_engine_specs/trino.py
index f758f1fadd..19c11939c4 100644
--- a/superset/db_engine_specs/trino.py
+++ b/superset/db_engine_specs/trino.py
@@ -187,7 +187,7 @@ class TrinoEngineSpec(PrestoBaseEngineSpec):
 
     @classmethod
     def execute_with_cursor(
-        cls, cursor: Any, sql: str, query: Query, session: Session
+        cls, cursor: Cursor, sql: str, query: Query, session: Session
     ) -> None:
         """
         Trigger execution of a query and handle the resulting cursor.
@@ -196,34 +196,40 @@ class TrinoEngineSpec(PrestoBaseEngineSpec):
         in another thread and invoke `handle_cursor` to poll for the query ID
         to appear on the cursor in parallel.
         """
+        # Fetch the query ID beforehand, since it might fail inside the thread due to
+        # how the SQLAlchemy session is handled.
+        query_id = query.id
+
         execute_result: dict[str, Any] = {}
+        execute_event = threading.Event()
 
-        def _execute(results: dict[str, Any]) -> None:
-            logger.debug("Query %d: Running query: %s", query.id, sql)
+        def _execute(results: dict[str, Any], event: threading.Event) -> None:
+            logger.debug("Query %d: Running query: %s", query_id, sql)
 
-            # Pass result / exception information back to the parent thread
             try:
                 cls.execute(cursor, sql)
-                results["complete"] = True
             except Exception as ex:  # pylint: disable=broad-except
-                results["complete"] = True
                 results["error"] = ex
+            finally:
+                event.set()
 
-        execute_thread = threading.Thread(target=_execute, args=(execute_result,))
+        execute_thread = threading.Thread(
+            target=_execute,
+            args=(execute_result, execute_event),
+        )
         execute_thread.start()
 
         # Wait for a query ID to be available before handling the cursor, as
         # it's required by that method; it may never become available on error.
-        while not cursor.query_id and not execute_result.get("complete"):
+        while not cursor.query_id and not execute_event.is_set():
             time.sleep(0.1)
 
-        logger.debug("Query %d: Handling cursor", query.id)
+        logger.debug("Query %d: Handling cursor", query_id)
         cls.handle_cursor(cursor, query, session)
 
         # Block until the query completes; same behaviour as the client itself
-        logger.debug("Query %d: Waiting for query to complete", query.id)
-        while not execute_result.get("complete"):
-            time.sleep(0.5)
+        logger.debug("Query %d: Waiting for query to complete", query_id)
+        execute_event.wait()
 
         # Unfortunately we'll mangle the stack trace due to the thread, but
         # throwing the original exception allows mapping database errors as normal
@@ -237,7 +243,7 @@ class TrinoEngineSpec(PrestoBaseEngineSpec):
             session.commit()
 
     @classmethod
-    def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool:
+    def cancel_query(cls, cursor: Cursor, query: Query, cancel_query_id: str) -> bool:
         """
         Cancel query in the underlying database.