Skip to content

Commit c06add2

Browse files
authored
[Tables] Fix single quote char handling in keys (Azure#20386)
* Fixed doubling of single quote char * Updated test coverage * Fix existing quote test * Fixed python 2 tests
1 parent e572c97 commit c06add2

25 files changed

+6645
-243
lines changed

sdk/tables/azure-data-tables/azure/data/tables/_serialize.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ def _get_match_headers(etag, match_condition):
3232
raise ValueError("Unsupported match condition: {}".format(match_condition))
3333

3434

35+
def _prepare_key(keyvalue):
36+
"""Duplicate the single quote char to escape."""
37+
return keyvalue.replace("'", "''")
38+
39+
3540
def _parameter_filter_substitution(parameters, query_filter):
3641
# type: (Dict[str, str], str) -> str
3742
"""Replace user defined parameter in filter
@@ -62,7 +67,7 @@ def _parameter_filter_substitution(parameters, query_filter):
6267
v = v[2:-1]
6368
filter_strings[index] = "X'{}'".format(v)
6469
else:
65-
filter_strings[index] = "'{}'".format(val.replace("'", "''"))
70+
filter_strings[index] = "'{}'".format(_prepare_key(val))
6671
return ' '.join(filter_strings)
6772
return query_filter
6873

sdk/tables/azure-data-tables/azure/data/tables/_table_batch.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from ._common_conversion import _transform_patch_to_cosmos_post
1919
from ._models import UpdateMode
20-
from ._serialize import _get_match_headers, _add_entity_properties
20+
from ._serialize import _get_match_headers, _add_entity_properties, _prepare_key
2121
from ._entity import TableEntity
2222

2323
if TYPE_CHECKING:
@@ -258,9 +258,10 @@ def update(
258258
match_condition=match_condition or MatchConditions.Unconditionally,
259259
)
260260

261-
partition_key = temp["PartitionKey"]
262-
row_key = temp["RowKey"]
261+
partition_key = _prepare_key(temp["PartitionKey"])
262+
row_key = _prepare_key(temp["RowKey"])
263263
temp = _add_entity_properties(temp)
264+
264265
if mode == UpdateMode.REPLACE:
265266
self._batch_update_entity(
266267
table=self.table_name,
@@ -525,8 +526,8 @@ def delete(
525526
"""
526527
self._verify_partition_key(entity)
527528
temp = entity.copy() # type: ignore
528-
partition_key = temp["PartitionKey"]
529-
row_key = temp["RowKey"]
529+
partition_key = _prepare_key(temp["PartitionKey"])
530+
row_key = _prepare_key(temp["RowKey"])
530531

531532
match_condition = kwargs.pop("match_condition", None)
532533
etag = kwargs.pop("etag", None)
@@ -666,8 +667,8 @@ def upsert(
666667
self._verify_partition_key(entity)
667668
temp = entity.copy() # type: ignore
668669

669-
partition_key = temp["PartitionKey"]
670-
row_key = temp["RowKey"]
670+
partition_key = _prepare_key(temp["PartitionKey"])
671+
row_key = _prepare_key(temp["RowKey"])
671672
temp = _add_entity_properties(temp)
672673

673674
if mode == UpdateMode.MERGE:

sdk/tables/azure-data-tables/azure/data/tables/_table_client.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
TableProperties,
3131
QueryOptions
3232
)
33-
from ._serialize import _get_match_headers, _add_entity_properties
33+
from ._serialize import _get_match_headers, _add_entity_properties, _prepare_key
3434
from ._base_client import parse_connection_str, TablesBaseClient
3535
from ._serialize import serialize_iso, _parameter_filter_substitution
3636
from ._deserialize import deserialize_iso, _return_headers_and_deserialized
@@ -364,8 +364,8 @@ def delete_entity(self, *args, **kwargs):
364364
try:
365365
self._client.table.delete_entity(
366366
table=self.table_name,
367-
partition_key=partition_key,
368-
row_key=row_key,
367+
partition_key=_prepare_key(partition_key),
368+
row_key=_prepare_key(row_key),
369369
if_match=if_match,
370370
**kwargs
371371
)
@@ -459,18 +459,17 @@ def update_entity(
459459
etag=etag,
460460
match_condition=match_condition or MatchConditions.Unconditionally,
461461
)
462-
462+
entity = _add_entity_properties(entity)
463463
partition_key = entity["PartitionKey"]
464464
row_key = entity["RowKey"]
465-
entity = _add_entity_properties(entity)
466465
try:
467466
metadata = None
468467
content = None
469468
if mode == UpdateMode.REPLACE:
470469
metadata, content = self._client.table.update_entity( # type: ignore
471470
table=self.table_name,
472-
partition_key=partition_key,
473-
row_key=row_key,
471+
partition_key=_prepare_key(partition_key),
472+
row_key=_prepare_key(row_key),
474473
table_entity_properties=entity, # type: ignore
475474
if_match=if_match,
476475
cls=kwargs.pop("cls", _return_headers_and_deserialized),
@@ -479,8 +478,8 @@ def update_entity(
479478
elif mode == UpdateMode.MERGE:
480479
metadata, content = self._client.table.merge_entity( # type: ignore
481480
table=self.table_name,
482-
partition_key=partition_key,
483-
row_key=row_key,
481+
partition_key=_prepare_key(partition_key),
482+
row_key=_prepare_key(row_key),
484483
if_match=if_match,
485484
table_entity_properties=entity, # type: ignore
486485
cls=kwargs.pop("cls", _return_headers_and_deserialized),
@@ -611,8 +610,8 @@ def get_entity(
611610
try:
612611
entity = self._client.table.query_entity_with_partition_and_row_key(
613612
table=self.table_name,
614-
partition_key=partition_key,
615-
row_key=row_key,
613+
partition_key=_prepare_key(partition_key),
614+
row_key=_prepare_key(row_key),
616615
query_options=QueryOptions(select=user_select),
617616
**kwargs
618617
)
@@ -647,27 +646,26 @@ def upsert_entity(
647646
:dedent: 16
648647
:caption: Update/merge or insert an entity into a table
649648
"""
650-
649+
entity = _add_entity_properties(entity)
651650
partition_key = entity["PartitionKey"]
652651
row_key = entity["RowKey"]
653-
entity = _add_entity_properties(entity)
654652
try:
655653
metadata = None
656654
content = None
657655
if mode == UpdateMode.MERGE:
658656
metadata, content = self._client.table.merge_entity( # type: ignore
659657
table=self.table_name,
660-
partition_key=partition_key,
661-
row_key=row_key,
658+
partition_key=_prepare_key(partition_key),
659+
row_key=_prepare_key(row_key),
662660
table_entity_properties=entity, # type: ignore
663661
cls=kwargs.pop("cls", _return_headers_and_deserialized),
664662
**kwargs
665663
)
666664
elif mode == UpdateMode.REPLACE:
667665
metadata, content = self._client.table.update_entity( # type: ignore
668666
table=self.table_name,
669-
partition_key=partition_key,
670-
row_key=row_key,
667+
partition_key=_prepare_key(partition_key),
668+
row_key=_prepare_key(row_key),
671669
table_entity_properties=entity, # type: ignore
672670
cls=kwargs.pop("cls", _return_headers_and_deserialized),
673671
**kwargs

sdk/tables/azure-data-tables/azure/data/tables/aio/_table_batch_async.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .._entity import TableEntity
1414
from .._table_batch import EntityType
1515
from .._serialize import (
16+
_prepare_key,
1617
_get_match_headers,
1718
_add_entity_properties,
1819
)
@@ -230,8 +231,8 @@ def update(
230231
match_condition=match_condition or MatchConditions.Unconditionally,
231232
)
232233

233-
partition_key = temp["PartitionKey"]
234-
row_key = temp["RowKey"]
234+
partition_key = _prepare_key(temp["PartitionKey"])
235+
row_key = _prepare_key(temp["RowKey"])
235236
temp = _add_entity_properties(temp)
236237
if mode == UpdateMode.REPLACE:
237238
self._batch_update_entity(
@@ -490,8 +491,8 @@ def delete(
490491
"""
491492
self._verify_partition_key(entity)
492493
temp = entity.copy() # type: ignore
493-
partition_key = temp["PartitionKey"]
494-
row_key = temp["RowKey"]
494+
partition_key = _prepare_key(temp["PartitionKey"])
495+
row_key = _prepare_key(temp["RowKey"])
495496

496497
match_condition = kwargs.pop("match_condition", None)
497498
etag = kwargs.pop("etag", None)
@@ -629,8 +630,8 @@ def upsert(
629630
self._verify_partition_key(entity)
630631
temp = entity.copy() # type: ignore
631632

632-
partition_key = temp["PartitionKey"]
633-
row_key = temp["RowKey"]
633+
partition_key = _prepare_key(temp["PartitionKey"])
634+
row_key = _prepare_key(temp["RowKey"])
634635
temp = _add_entity_properties(temp)
635636

636637
if mode == UpdateMode.MERGE:

sdk/tables/azure-data-tables/azure/data/tables/aio/_table_client_async.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from .._entity import TableEntity
2323
from .._generated.models import SignedIdentifier, TableProperties, QueryOptions
2424
from .._models import TableAccessPolicy, TableItem
25-
from .._serialize import serialize_iso, _parameter_filter_substitution
25+
from .._serialize import serialize_iso, _parameter_filter_substitution, _prepare_key
2626
from .._deserialize import deserialize_iso, _return_headers_and_deserialized
2727
from .._error import (
2828
_process_table_error,
@@ -346,8 +346,8 @@ async def delete_entity(self, *args: Union[TableEntity, str], **kwargs: Any) ->
346346
try:
347347
await self._client.table.delete_entity(
348348
table=self.table_name,
349-
partition_key=partition_key,
350-
row_key=row_key,
349+
partition_key=_prepare_key(partition_key),
350+
row_key=_prepare_key(row_key),
351351
if_match=if_match,
352352
**kwargs
353353
)
@@ -451,8 +451,8 @@ async def update_entity(
451451
if mode == UpdateMode.REPLACE:
452452
metadata, content = await self._client.table.update_entity( # type: ignore
453453
table=self.table_name,
454-
partition_key=partition_key,
455-
row_key=row_key,
454+
partition_key=_prepare_key(partition_key),
455+
row_key=_prepare_key(row_key),
456456
table_entity_properties=entity, # type: ignore
457457
if_match=if_match,
458458
cls=kwargs.pop("cls", _return_headers_and_deserialized),
@@ -461,8 +461,8 @@ async def update_entity(
461461
elif mode == UpdateMode.MERGE:
462462
metadata, content = await self._client.table.merge_entity( # type: ignore
463463
table=self.table_name,
464-
partition_key=partition_key,
465-
row_key=row_key,
464+
partition_key=_prepare_key(partition_key),
465+
row_key=_prepare_key(row_key),
466466
if_match=if_match,
467467
cls=kwargs.pop("cls", _return_headers_and_deserialized),
468468
table_entity_properties=entity, # type: ignore
@@ -588,8 +588,8 @@ async def get_entity(
588588
try:
589589
entity = await self._client.table.query_entity_with_partition_and_row_key(
590590
table=self.table_name,
591-
partition_key=partition_key,
592-
row_key=row_key,
591+
partition_key=_prepare_key(partition_key),
592+
row_key=_prepare_key(row_key),
593593
query_options=QueryOptions(select=user_select),
594594
**kwargs
595595
)
@@ -635,17 +635,17 @@ async def upsert_entity(
635635
if mode == UpdateMode.MERGE:
636636
metadata, content = await self._client.table.merge_entity( # type: ignore
637637
table=self.table_name,
638-
partition_key=partition_key,
639-
row_key=row_key,
638+
partition_key=_prepare_key(partition_key),
639+
row_key=_prepare_key(row_key),
640640
table_entity_properties=entity, # type: ignore
641641
cls=kwargs.pop("cls", _return_headers_and_deserialized),
642642
**kwargs
643643
)
644644
elif mode == UpdateMode.REPLACE:
645645
metadata, content = await self._client.table.update_entity( # type: ignore
646646
table=self.table_name,
647-
partition_key=partition_key,
648-
row_key=row_key,
647+
partition_key=_prepare_key(partition_key),
648+
row_key=_prepare_key(row_key),
649649
table_entity_properties=entity, # type: ignore
650650
cls=kwargs.pop("cls", _return_headers_and_deserialized),
651651
**kwargs

0 commit comments

Comments
 (0)