16
16
from awswrangler import _utils , catalog , exceptions , s3 , typing
17
17
from awswrangler ._config import apply_configs
18
18
from awswrangler ._data_types import cast_pandas_with_athena_types
19
- from awswrangler ._sql_formatter import _process_sql_params
20
19
from awswrangler .athena ._utils import (
21
20
_QUERY_WAIT_POLLING_DELAY ,
21
+ _apply_formatter ,
22
22
_apply_query_metadata ,
23
23
_empty_dataframe_response ,
24
24
_get_query_metadata ,
@@ -287,6 +287,7 @@ def _resolve_query_without_cache_ctas(
287
287
s3_additional_kwargs : Optional [Dict [str , Any ]],
288
288
boto3_session : Optional [boto3 .Session ],
289
289
pyarrow_additional_kwargs : Optional [Dict [str , Any ]] = None ,
290
+ execution_params : Optional [List [str ]] = None ,
290
291
dtype_backend : Literal ["numpy_nullable" , "pyarrow" ] = "numpy_nullable" ,
291
292
) -> Union [pd .DataFrame , Iterator [pd .DataFrame ]]:
292
293
ctas_query_info : Dict [str , Union [str , _QueryMetadata ]] = create_ctas_table (
@@ -304,6 +305,7 @@ def _resolve_query_without_cache_ctas(
304
305
wait = True ,
305
306
athena_query_wait_polling_delay = athena_query_wait_polling_delay ,
306
307
boto3_session = boto3_session ,
308
+ execution_params = execution_params ,
307
309
)
308
310
fully_qualified_name : str = f'"{ ctas_query_info ["ctas_database" ]} "."{ ctas_query_info ["ctas_table" ]} "'
309
311
ctas_query_metadata = cast (_QueryMetadata , ctas_query_info ["ctas_query_metadata" ])
@@ -342,6 +344,7 @@ def _resolve_query_without_cache_unload(
342
344
s3_additional_kwargs : Optional [Dict [str , Any ]],
343
345
boto3_session : Optional [boto3 .Session ],
344
346
pyarrow_additional_kwargs : Optional [Dict [str , Any ]] = None ,
347
+ execution_params : Optional [List [str ]] = None ,
345
348
dtype_backend : Literal ["numpy_nullable" , "pyarrow" ] = "numpy_nullable" ,
346
349
) -> Union [pd .DataFrame , Iterator [pd .DataFrame ]]:
347
350
query_metadata = _unload (
@@ -358,6 +361,7 @@ def _resolve_query_without_cache_unload(
358
361
boto3_session = boto3_session ,
359
362
data_source = data_source ,
360
363
athena_query_wait_polling_delay = athena_query_wait_polling_delay ,
364
+ execution_params = execution_params ,
361
365
)
362
366
if file_format == "PARQUET" :
363
367
return _fetch_parquet_result (
@@ -389,6 +393,7 @@ def _resolve_query_without_cache_regular(
389
393
athena_query_wait_polling_delay : float ,
390
394
s3_additional_kwargs : Optional [Dict [str , Any ]],
391
395
boto3_session : Optional [boto3 .Session ],
396
+ execution_params : Optional [List [str ]] = None ,
392
397
dtype_backend : Literal ["numpy_nullable" , "pyarrow" ] = "numpy_nullable" ,
393
398
) -> Union [pd .DataFrame , Iterator [pd .DataFrame ]]:
394
399
wg_config : _WorkGroupConfig = _get_workgroup_config (session = boto3_session , workgroup = workgroup )
@@ -404,6 +409,7 @@ def _resolve_query_without_cache_regular(
404
409
workgroup = workgroup ,
405
410
encryption = encryption ,
406
411
kms_key = kms_key ,
412
+ execution_params = execution_params ,
407
413
boto3_session = boto3_session ,
408
414
)
409
415
_logger .debug ("Query id: %s" , query_id )
@@ -450,6 +456,7 @@ def _resolve_query_without_cache(
450
456
s3_additional_kwargs : Optional [Dict [str , Any ]],
451
457
boto3_session : Optional [boto3 .Session ],
452
458
pyarrow_additional_kwargs : Optional [Dict [str , Any ]] = None ,
459
+ execution_params : Optional [List [str ]] = None ,
453
460
dtype_backend : Literal ["numpy_nullable" , "pyarrow" ] = "numpy_nullable" ,
454
461
) -> Union [pd .DataFrame , Iterator [pd .DataFrame ]]:
455
462
"""
@@ -483,6 +490,7 @@ def _resolve_query_without_cache(
483
490
s3_additional_kwargs = s3_additional_kwargs ,
484
491
boto3_session = boto3_session ,
485
492
pyarrow_additional_kwargs = pyarrow_additional_kwargs ,
493
+ execution_params = execution_params ,
486
494
dtype_backend = dtype_backend ,
487
495
)
488
496
finally :
@@ -510,6 +518,7 @@ def _resolve_query_without_cache(
510
518
s3_additional_kwargs = s3_additional_kwargs ,
511
519
boto3_session = boto3_session ,
512
520
pyarrow_additional_kwargs = pyarrow_additional_kwargs ,
521
+ execution_params = execution_params ,
513
522
dtype_backend = dtype_backend ,
514
523
)
515
524
return _resolve_query_without_cache_regular (
@@ -527,6 +536,7 @@ def _resolve_query_without_cache(
527
536
athena_query_wait_polling_delay = athena_query_wait_polling_delay ,
528
537
s3_additional_kwargs = s3_additional_kwargs ,
529
538
boto3_session = boto3_session ,
539
+ execution_params = execution_params ,
530
540
dtype_backend = dtype_backend ,
531
541
)
532
542
@@ -545,6 +555,7 @@ def _unload(
545
555
boto3_session : Optional [boto3 .Session ],
546
556
data_source : Optional [str ],
547
557
athena_query_wait_polling_delay : float ,
558
+ execution_params : Optional [List [str ]],
548
559
) -> _QueryMetadata :
549
560
wg_config : _WorkGroupConfig = _get_workgroup_config (session = boto3_session , workgroup = workgroup )
550
561
s3_output : str = _get_s3_output (s3_output = path , wg_config = wg_config , boto3_session = boto3_session )
@@ -576,6 +587,7 @@ def _unload(
576
587
encryption = encryption ,
577
588
kms_key = kms_key ,
578
589
boto3_session = boto3_session ,
590
+ execution_params = execution_params ,
579
591
)
580
592
except botocore .exceptions .ClientError as ex :
581
593
msg : str = str (ex )
@@ -735,7 +747,8 @@ def read_sql_query( # pylint: disable=too-many-arguments,too-many-locals
735
747
athena_cache_settings : Optional [typing .AthenaCacheSettings ] = None ,
736
748
data_source : Optional [str ] = None ,
737
749
athena_query_wait_polling_delay : float = _QUERY_WAIT_POLLING_DELAY ,
738
- params : Optional [Dict [str , Any ]] = None ,
750
+ params : Union [Dict [str , Any ], List [str ], None ] = None ,
751
+ paramstyle : Literal ["qmark" , "named" ] = "named" ,
739
752
dtype_backend : Literal ["numpy_nullable" , "pyarrow" ] = "numpy_nullable" ,
740
753
s3_additional_kwargs : Optional [Dict [str , Any ]] = None ,
741
754
pyarrow_additional_kwargs : Optional [Dict [str , Any ]] = None ,
@@ -905,10 +918,25 @@ def read_sql_query( # pylint: disable=too-many-arguments,too-many-locals
905
918
Data Source / Catalog name. If None, 'AwsDataCatalog' will be used by default.
906
919
athena_query_wait_polling_delay: float, default: 0.25 seconds
907
920
Interval in seconds for how often the function will check if the Athena query has completed.
908
- params: Dict[str, any], optional
909
- Dict of parameters that will be used for constructing the SQL query. Only named parameters are supported.
910
- The dict needs to contain the information in the form {'name': 'value'} and the SQL query needs to contain
911
- `:name`. Note that for varchar columns and similar, you must surround the value in single quotes.
921
+ params: Dict[str, any] | List[str], optional
922
+ Parameters that will be used for constructing the SQL query.
923
+ Only named or question mark parameters are supported.
924
+ The parameter style needs to be specified in the ``paramstyle`` parameter.
925
+
926
+ For ``paramstyle="named"``, this value needs to be a dictionary.
927
+ The dict needs to contain the information in the form ``{'name': 'value'}`` and the SQL query needs to contain
928
+ ``:name``.
929
+ The formatter will be applied client-side in this scenario.
930
+
931
+ For ``paramstyle="qmark"``, this value needs to be a list of strings.
932
+ The formatter will be applied server-side.
933
+ The values are applied sequentially to the parameters in the query in the order in which the parameters occur.
934
+ paramstyle: str, optional
935
+ Determines the style of ``params``.
936
+ Possible values are:
937
+
938
+ - ``named``
939
+ - ``qmark``
912
940
dtype_backend: str, optional
913
941
Which dtype_backend to use, e.g. whether a DataFrame should have NumPy arrays,
914
942
nullable dtypes are used for all dtypes that have a nullable implementation when
@@ -964,15 +992,15 @@ def read_sql_query( # pylint: disable=too-many-arguments,too-many-locals
964
992
raise exceptions .InvalidArgumentCombination ("Only PARQUET file format is supported if unload_approach=True" )
965
993
chunksize = sys .maxsize if ctas_approach is False and chunksize is True else chunksize
966
994
995
+ # Substitute query parameters if applicable
996
+ sql , execution_params = _apply_formatter (sql , params , paramstyle )
997
+
967
998
athena_cache_settings = athena_cache_settings if athena_cache_settings else {}
968
999
max_cache_seconds = athena_cache_settings .get ("max_cache_seconds" , 0 )
969
1000
max_cache_query_inspections = athena_cache_settings .get ("max_cache_query_inspections" , 50 )
970
1001
max_remote_cache_entries = athena_cache_settings .get ("max_remote_cache_entries" , 50 )
971
1002
max_local_cache_entries = athena_cache_settings .get ("max_local_cache_entries" , 100 )
972
1003
973
- # Substitute query parameters
974
- sql = _process_sql_params (sql , params )
975
-
976
1004
max_remote_cache_entries = min (max_remote_cache_entries , max_local_cache_entries )
977
1005
978
1006
_cache_manager .max_cache_size = max_local_cache_entries
@@ -1032,6 +1060,7 @@ def read_sql_query( # pylint: disable=too-many-arguments,too-many-locals
1032
1060
s3_additional_kwargs = s3_additional_kwargs ,
1033
1061
boto3_session = boto3_session ,
1034
1062
pyarrow_additional_kwargs = pyarrow_additional_kwargs ,
1063
+ execution_params = execution_params ,
1035
1064
dtype_backend = dtype_backend ,
1036
1065
)
1037
1066
@@ -1288,7 +1317,8 @@ def unload(
1288
1317
kms_key : Optional [str ] = None ,
1289
1318
boto3_session : Optional [boto3 .Session ] = None ,
1290
1319
data_source : Optional [str ] = None ,
1291
- params : Optional [Dict [str , Any ]] = None ,
1320
+ params : Union [Dict [str , Any ], List [str ], None ] = None ,
1321
+ paramstyle : Literal ["qmark" , "named" ] = "named" ,
1292
1322
athena_query_wait_polling_delay : float = _QUERY_WAIT_POLLING_DELAY ,
1293
1323
) -> _QueryMetadata :
1294
1324
"""Write query results from a SELECT statement to the specified data format using UNLOAD.
@@ -1325,10 +1355,25 @@ def unload(
1325
1355
Boto3 Session. The default boto3 session will be used if boto3_session receive None.
1326
1356
data_source : str, optional
1327
1357
Data Source / Catalog name. If None, 'AwsDataCatalog' will be used by default.
1328
- params: Dict[str, any], optional
1329
- Dict of parameters that will be used for constructing the SQL query. Only named parameters are supported.
1330
- The dict needs to contain the information in the form {'name': 'value'} and the SQL query needs to contain
1331
- `:name`. Note that for varchar columns and similar, you must surround the value in single quotes.
1358
+ params: Dict[str, any] | List[str], optional
1359
+ Parameters that will be used for constructing the SQL query.
1360
+ Only named or question mark parameters are supported.
1361
+ The parameter style needs to be specified in the ``paramstyle`` parameter.
1362
+
1363
+ For ``paramstyle="named"``, this value needs to be a dictionary.
1364
+ The dict needs to contain the information in the form ``{'name': 'value'}`` and the SQL query needs to contain
1365
+ ``:name``.
1366
+ The formatter will be applied client-side in this scenario.
1367
+
1368
+ For ``paramstyle="qmark"``, this value needs to be a list of strings.
1369
+ The formatter will be applied server-side.
1370
+ The values are applied sequentially to the parameters in the query in the order in which the parameters occur.
1371
+ paramstyle: str, optional
1372
+ Determines the style of ``params``.
1373
+ Possible values are:
1374
+
1375
+ - ``named``
1376
+ - ``qmark``
1332
1377
athena_query_wait_polling_delay: float, default: 0.25 seconds
1333
1378
Interval in seconds for how often the function will check if the Athena query has completed.
1334
1379
@@ -1346,8 +1391,8 @@ def unload(
1346
1391
... )
1347
1392
1348
1393
"""
1349
- # Substitute query parameters
1350
- sql = _process_sql_params (sql , params )
1394
+ # Substitute query parameters if applicable
1395
+ sql , execution_params = _apply_formatter (sql , params , paramstyle )
1351
1396
return _unload (
1352
1397
sql = sql ,
1353
1398
path = path ,
@@ -1362,4 +1407,5 @@ def unload(
1362
1407
athena_query_wait_polling_delay = athena_query_wait_polling_delay ,
1363
1408
boto3_session = boto3_session ,
1364
1409
data_source = data_source ,
1410
+ execution_params = execution_params ,
1365
1411
)
0 commit comments