From 8f8de3f342bde6bcd8c00bd4ce2fda2e76990b5d Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Thu, 2 Jun 2022 22:03:56 +0000 Subject: [PATCH] DynamoDB - error when ending an UpdateExpression with a comma (#5189) --- moto/dynamodb/parsing/expressions.py | 3 +++ .../exceptions/test_dynamodb_exceptions.py | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/moto/dynamodb/parsing/expressions.py b/moto/dynamodb/parsing/expressions.py index 98354438f..b3d2562cc 100644 --- a/moto/dynamodb/parsing/expressions.py +++ b/moto/dynamodb/parsing/expressions.py @@ -555,6 +555,9 @@ class UpdateExpressionActionsParser(ExpressionParser, NestableExpressionParserMi self.skip_white_space() if self.get_next_token_type() == Token.COMMA: self.goto_next_significant_token() + if self.is_at_end(): + # The expression should not end with a comma + self.raise_unexpected_token() else: break diff --git a/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py b/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py index 6aabc3d7d..81122363b 100644 --- a/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py +++ b/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py @@ -599,3 +599,29 @@ def test_put_item_empty_set(): err["Message"].should.equal( "One or more parameter values were invalid: An number set may not be empty" ) + + +@mock_dynamodb +def test_update_expression_with_trailing_comma(): + resource = boto3.resource(service_name="dynamodb", region_name="us-east-1") + table = resource.create_table( + TableName="test-table", + KeySchema=[{"AttributeName": "pk", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "pk", "AttributeType": "S"}], + ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 1}, + ) + table.put_item(Item={"pk": "key", "attr2": 2}) + + with pytest.raises(ClientError) as exc: + table.update_item( + Key={"pk": "key", "sk": "sk"}, + # Trailing comma should be invalid + UpdateExpression="SET #attr1 = :val1, #attr2 = :val2,", + ExpressionAttributeNames={"#attr1": "attr1", "#attr2": "attr2"}, + ExpressionAttributeValues={":val1": 3, ":val2": 4}, + ) + err = exc.value.response["Error"] + err["Code"].should.equal("ValidationException") + err["Message"].should.equal( + 'Invalid UpdateExpression: Syntax error; token: "", near: ","' + )