11from __future__ import annotations
22
33import logging
4- import re
54import time
65from abc import ABCMeta , abstractmethod
76from functools import wraps
3534 UPDATE_PARAMETERS_HEADER ,
3635 BaseCursor ,
3736 CursorState ,
38- QueryStatus ,
3937 Statistics ,
4038 _parse_update_endpoint ,
4139 _parse_update_parameters ,
4543)
4644from firebolt .common .constants import ENGINE_STATUS_RUNNING_LIST
4745from firebolt .utils .exception import (
48- AsyncExecutionUnavailableError ,
4946 EngineNotRunningError ,
5047 FireboltDatabaseError ,
5148 FireboltEngineError ,
5754if TYPE_CHECKING :
5855 from firebolt .async_db .connection import Connection
5956
60- from firebolt .utils .util import Timer , _print_error_body
57+ from firebolt .utils .util import _print_error_body
6158
6259logger = logging .getLogger (__name__ )
6360
@@ -126,12 +123,6 @@ async def _raise_if_error(self, resp: Response) -> None:
126123 async def _validate_set_parameter (self , parameter : SetParameter ) -> None :
127124 """Validate parameter by executing simple query with it."""
128125 _raise_if_internal_set_parameter (parameter )
129- if parameter .name == "async_execution" :
130- raise AsyncExecutionUnavailableError (
131- "It is not possible to set async_execution using a SET command. "
132- "Instead, pass it as an argument to the execute() or "
133- "executemany() function."
134- )
135126 resp = await self ._api_request ("select 1" , {parameter .name : parameter .value })
136127 # Handle invalid set parameter
137128 if resp .status_code == codes .BAD_REQUEST :
@@ -170,7 +161,6 @@ async def _do_execute(
170161 raw_query : str ,
171162 parameters : Sequence [Sequence [ParameterType ]],
172163 skip_parsing : bool = False ,
173- async_execution : Optional [bool ] = False ,
174164 ) -> None :
175165 self ._reset ()
176166 # Allow users to manually skip parsing for performance improvement.
@@ -180,13 +170,7 @@ async def _do_execute(
180170 try :
181171 for query in queries :
182172 start_time = time .time ()
183- # Our CREATE EXTERNAL TABLE queries currently require credentials,
184- # so we will skip logging those queries.
185- # https://docs.firebolt.io/sql-reference/commands/create-external-table.html
186- if isinstance (query , SetParameter ) or not re .search (
187- "aws_key_id|credentials" , query , flags = re .IGNORECASE
188- ):
189- logger .debug (f"Running query: { query } " )
173+ Cursor ._log_query (query )
190174
191175 # Define type for mypy
192176 row_set : Tuple [
@@ -197,35 +181,6 @@ async def _do_execute(
197181 ] = (- 1 , None , None , None )
198182 if isinstance (query , SetParameter ):
199183 await self ._validate_set_parameter (query )
200- elif async_execution :
201- self ._validate_server_side_async_settings (
202- parameters ,
203- queries ,
204- skip_parsing ,
205- async_execution ,
206- )
207-
208- with Timer (
209- f"[PERFORMANCE] Running query { query [:50 ]} "
210- f"{ '... ' if len (query ) > 50 else '' } "
211- ):
212- response = await self ._api_request (
213- query ,
214- {
215- "async_execution" : 1 ,
216- "output_format" : JSON_OUTPUT_FORMAT ,
217- },
218- )
219-
220- await self ._raise_if_error (response )
221- if response .headers .get ("content-length" , "" ) == "0" :
222- raise OperationalError ("No response to asynchronous query." )
223- resp = response .json ()
224- if "query_id" not in resp or resp ["query_id" ] == "" :
225- raise OperationalError (
226- "Invalid response to asynchronous query: missing query_id."
227- )
228- self ._query_id = resp ["query_id" ]
229184 else :
230185 resp = await self ._api_request (
231186 query , {"output_format" : JSON_OUTPUT_FORMAT }
@@ -253,7 +208,6 @@ async def execute(
253208 query : str ,
254209 parameters : Optional [Sequence [ParameterType ]] = None ,
255210 skip_parsing : bool = False ,
256- async_execution : Optional [bool ] = False ,
257211 ) -> Union [int , str ]:
258212 """Prepare and execute a database query.
259213
@@ -277,21 +231,19 @@ async def execute(
277231 skip_parsing (bool): Flag to disable query parsing. This will
278232 disable parameterized, multi-statement and SET queries,
279233 while improving performance
280- async_execution (bool): flag to determine if query should be asynchronous
281234
282235 Returns:
283236 int: Query row count.
284237 """
285238 params_list = [parameters ] if parameters else []
286- await self ._do_execute (query , params_list , skip_parsing , async_execution )
287- return self .query_id if async_execution else self . rowcount
239+ await self ._do_execute (query , params_list , skip_parsing )
240+ return self .rowcount
288241
289242 @check_not_closed
290243 async def executemany (
291244 self ,
292245 query : str ,
293246 parameters_seq : Sequence [Sequence [ParameterType ]],
294- async_execution : Optional [bool ] = False ,
295247 ) -> Union [int , str ]:
296248 """Prepare and execute a database query.
297249
@@ -316,46 +268,12 @@ async def executemany(
316268 substitution parameter sets. Used to replace '?' placeholders inside a
317269 query with actual values from each set in a sequence. Resulting queries
318270 for each subset are executed sequentially.
319- async_execution (bool): flag to determine if query should be asynchronous
320271
321272 Returns:
322- int|str: Query row count for synchronous execution of queries,
323- query ID string for asynchronous execution.
273+ int: Query row count.
324274 """
325- await self ._do_execute (query , parameters_seq , async_execution = async_execution )
326- if async_execution :
327- return self .query_id
328- else :
329- return self .rowcount
330-
331- @check_not_closed
332- async def get_status (self , query_id : str ) -> QueryStatus :
333- """Get status of a server-side async query. Return the state of the query."""
334- try :
335- resp = await self ._api_request (
336- # output_format must be empty for status to work correctly.
337- # And set parameters will cause 400 errors.
338- parameters = {"query_id" : query_id },
339- path = "status" ,
340- use_set_parameters = False ,
341- )
342- if resp .status_code == codes .BAD_REQUEST :
343- raise OperationalError (
344- f"Asynchronous query { query_id } status check failed: "
345- f"{ resp .status_code } ."
346- )
347- resp_json = resp .json ()
348- if "status" not in resp_json :
349- raise OperationalError (
350- "Invalid response to asynchronous query: missing status."
351- )
352- except Exception :
353- self ._state = CursorState .ERROR
354- raise
355- # Remember that query_id might be empty.
356- if resp_json ["status" ] == "" :
357- return QueryStatus .NOT_READY
358- return QueryStatus [resp_json ["status" ]]
275+ await self ._do_execute (query , parameters_seq )
276+ return self .rowcount
359277
360278 @abstractmethod
361279 async def is_db_available (self , database : str ) -> bool :
@@ -389,15 +307,6 @@ async def fetchall(self) -> List[List[ColType]]:
389307 async def nextset (self ) -> None :
390308 return super ().nextset ()
391309
392- @check_not_closed
393- async def cancel (self , query_id : str ) -> None :
394- """Cancel a server-side async query."""
395- await self ._api_request (
396- parameters = {"query_id" : query_id },
397- path = "cancel" ,
398- use_set_parameters = False ,
399- )
400-
401310 # Iteration support
402311 @check_not_closed
403312 @check_query_executed
@@ -557,7 +466,7 @@ def __init__(
557466 async def _api_request (
558467 self ,
559468 query : Optional [str ] = "" ,
560- parameters : Optional [dict [str , Any ]] = {} ,
469+ parameters : Optional [dict [str , Any ]] = None ,
561470 path : Optional [str ] = "" ,
562471 use_set_parameters : Optional [bool ] = True ,
563472 ) -> Response :
0 commit comments