mirror of
https://github.com/scylladb/scylladb.git
synced 2026-06-04 05:53:13 +00:00
alternator: clean up parsing of attribute-path components
Before this patch, we read either an attribute name like "name" or a reference to one "#name", as one type of token - NAME. However, while attribute paths indeed can use either one, in some other contexts - such as a function name - only "name" is allowed, so we need to distinguish between two types of tokens: NAME and NAMEREF. While separating those, I noticed that we incorrectly allowed a "#" followed by *zero* alphanumeric characters to be considered a NAMEREF, which it shouldn't. In other words, NAMEREF should have ALNUM+, not ALNUM*. Same for VALREF, which can't be just a ":" with nothing after it. So this patch fixes these mistakes, and adds tests for them. Signed-off-by: Nadav Har'El <nyh@scylladb.com>
This commit is contained in:
@@ -140,6 +140,14 @@ def test_update_expression_name_token(test_table_s):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET #hi-there = :val1', ExpressionAttributeValues={':val1': 7}, ExpressionAttributeNames={'#hi-there': silly_name})
|
||||
with pytest.raises(ClientError, match='ValidationException'):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET #!hi = :val1', ExpressionAttributeValues={':val1': 7}, ExpressionAttributeNames={'#!hi': silly_name})
|
||||
# Just a "#" is not enough as a token. Interestingly, DynamoDB will
|
||||
# find the bad name in ExpressionAttributeNames before it actually tries
|
||||
# to parse UpdateExpression, but we can verify the parse fails too by
|
||||
# using a valid but irrelevant name in ExpressionAttributeNames:
|
||||
with pytest.raises(ClientError, match='ValidationException'):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET # = :val1', ExpressionAttributeValues={':val1': 7}, ExpressionAttributeNames={'#': silly_name})
|
||||
with pytest.raises(ClientError, match='ValidationException'):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET # = :val1', ExpressionAttributeValues={':val1': 7}, ExpressionAttributeNames={'#a': silly_name})
|
||||
|
||||
# There is also the value references, ":reference", for the right-hand
|
||||
# side of an assignment. These have similar naming rules like "#reference".
|
||||
@@ -153,6 +161,11 @@ def test_update_expression_name_token(test_table_s):
|
||||
assert test_table_s.get_item(Key={'p': p}, ConsistentRead=True)['Item']['a'] == 11
|
||||
with pytest.raises(ClientError, match='ValidationException'):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET a = :hi!there', ExpressionAttributeValues={':hi!there': 12})
|
||||
# Just a ":" is not enough as a token.
|
||||
with pytest.raises(ClientError, match='ValidationException'):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET a = :', ExpressionAttributeValues={':': 7})
|
||||
with pytest.raises(ClientError, match='ValidationException'):
|
||||
test_table_s.update_item(Key={'p': p}, UpdateExpression='SET a = :', ExpressionAttributeValues={':a': 7})
|
||||
# Trying to use a :reference on the left-hand side of an assignment will
|
||||
# not work. In DynamoDB, it's a different type of token (and generates
|
||||
# syntax error).
|
||||
|
||||
@@ -132,18 +132,20 @@ fragment ALPHA: 'A'..'Z' | 'a'..'z';
|
||||
fragment DIGIT: '0'..'9';
|
||||
fragment ALNUM: ALPHA | DIGIT | '_';
|
||||
INTEGER: DIGIT+;
|
||||
NAME: (ALPHA | '#') ALNUM*;
|
||||
VALREF: ':' ALNUM*;
|
||||
NAME: ALPHA ALNUM*;
|
||||
NAMEREF: '#' ALNUM+;
|
||||
VALREF: ':' ALNUM+;
|
||||
|
||||
/*
|
||||
* Parsing phase - parsing the string of tokens generated by the lexical
|
||||
* analyzer defined above.
|
||||
*/
|
||||
|
||||
path_component: NAME | NAMEREF;
|
||||
path returns [parsed::path p]:
|
||||
root=NAME { $p.set_root($root.text); }
|
||||
( '.' name=NAME { $p.add_dot($name.text); }
|
||||
| '[' INTEGER ']' { $p.add_index(std::stoi($INTEGER.text)); }
|
||||
root=path_component { $p.set_root($root.text); }
|
||||
( '.' name=path_component { $p.add_dot($name.text); }
|
||||
| '[' INTEGER ']' { $p.add_index(std::stoi($INTEGER.text)); }
|
||||
)*;
|
||||
|
||||
// FIXME: set action supports additional types of rhs besides VALREF.
|
||||
|
||||
Reference in New Issue
Block a user