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