1717from __future__ import annotations
1818
1919import logging
20- import threading
21- import time
2220from typing import Any , TYPE_CHECKING
2321
2422import simplejson as json
@@ -156,22 +154,15 @@ def get_tracking_url(cls, cursor: Cursor) -> str | None:
156154
157155 @classmethod
158156 def handle_cursor (cls , cursor : Cursor , query : Query , session : Session ) -> None :
159- """
160- Handle a trino client cursor.
161-
162- WARNING: if you execute a query, it will block until complete and you
163- will not be able to handle the cursor until complete. Use
164- `execute_with_cursor` instead, to handle this asynchronously.
165- """
166-
167- # Adds the executed query id to the extra payload so the query can be cancelled
168- cancel_query_id = cursor .query_id
169- logger .debug ("Query %d: queryId %s found in cursor" , query .id , cancel_query_id )
170- query .set_extra_json_key (key = QUERY_CANCEL_KEY , value = cancel_query_id )
171-
172157 if tracking_url := cls .get_tracking_url (cursor ):
173158 query .tracking_url = tracking_url
174159
160+ # Adds the executed query id to the extra payload so the query can be cancelled
161+ query .set_extra_json_key (
162+ key = QUERY_CANCEL_KEY ,
163+ value = (cancel_query_id := cursor .stats ["queryId" ]),
164+ )
165+
175166 session .commit ()
176167
177168 # if query cancelation was requested prior to the handle_cursor call, but
@@ -185,51 +176,6 @@ def handle_cursor(cls, cursor: Cursor, query: Query, session: Session) -> None:
185176
186177 super ().handle_cursor (cursor = cursor , query = query , session = session )
187178
188- @classmethod
189- def execute_with_cursor (
190- cls , cursor : Any , sql : str , query : Query , session : Session
191- ) -> None :
192- """
193- Trigger execution of a query and handle the resulting cursor.
194-
195- Trino's client blocks until the query is complete, so we need to run it
196- in another thread and invoke `handle_cursor` to poll for the query ID
197- to appear on the cursor in parallel.
198- """
199- execute_result : dict [str , Any ] = {}
200-
201- def _execute (results : dict [str , Any ]) -> None :
202- logger .debug ("Query %d: Running query: %s" , query .id , sql )
203-
204- # Pass result / exception information back to the parent thread
205- try :
206- cls .execute (cursor , sql )
207- results ["complete" ] = True
208- except Exception as ex : # pylint: disable=broad-except
209- results ["complete" ] = True
210- results ["error" ] = ex
211-
212- execute_thread = threading .Thread (target = _execute , args = (execute_result ,))
213- execute_thread .start ()
214-
215- # Wait for a query ID to be available before handling the cursor, as
216- # it's required by that method; it may never become available on error.
217- while not cursor .query_id and not execute_result .get ("complete" ):
218- time .sleep (0.1 )
219-
220- logger .debug ("Query %d: Handling cursor" , query .id )
221- cls .handle_cursor (cursor , query , session )
222-
223- # Block until the query completes; same behaviour as the client itself
224- logger .debug ("Query %d: Waiting for query to complete" , query .id )
225- while not execute_result .get ("complete" ):
226- time .sleep (0.5 )
227-
228- # Unfortunately we'll mangle the stack trace due to the thread, but
229- # throwing the original exception allows mapping database errors as normal
230- if err := execute_result .get ("error" ):
231- raise err
232-
233179 @classmethod
234180 def prepare_cancel_query (cls , query : Query , session : Session ) -> None :
235181 if QUERY_CANCEL_KEY not in query .extra :
0 commit comments