Merge 'cql3: expr: remove the default constructor' from Avi Kivity
`expression`'s default constructor is dangerous as an it can leak into computations and generate surprising results. Fix that by removing the default constructor. This is made somewhat difficult by the parser generator's reliance on default construction, and we need to expand our workaround (`uninitialized<>`) capabilities to do so. We also remove some incidental uses of default-constructed expressions. Closes #14706 * github.com:scylladb/scylladb: cql3: expr: make expression non-default-constructible cql3: grammar: don't default-construct expressions cql3: grammar: improve uninitialized<> flexibility cql3: grammar: adjust uninitialized<> wrapper test: expr_test: don't invoke expression's default constructor cql3: statement_restrictions: explicitly initialize expressions in index match code cql3: statement_restrictions: explicitly intitialize some expression fields cql3: statement_restrictions: avoid expression's default constructor when classifying restrictions cql3: expr: prepare_expression: avoid default-constructed expression cql3: broadcast_tables: prepare new_value without relying on expression default constructor
This commit is contained in:
133
cql3/Cql.g
133
cql3/Cql.g
@@ -116,14 +116,29 @@ struct uninitialized {
|
||||
uninitialized(uninitialized&&) = default;
|
||||
uninitialized(const T& val) : _val(val) {}
|
||||
uninitialized(T&& val) : _val(std::move(val)) {}
|
||||
uninitialized(std::convertible_to<T> auto&& x) : _val(std::forward<decltype(x)>(x)) {}
|
||||
uninitialized& operator=(const uninitialized&) = default;
|
||||
uninitialized& operator=(uninitialized&&) = default;
|
||||
operator const T&() const & { return check(), *_val; }
|
||||
operator T&&() && { return check(), std::move(*_val); }
|
||||
operator std::optional<T>&&() && { return check(), std::move(_val); }
|
||||
void check() const { if (!_val) { throw std::runtime_error("not intitialized"); } }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrap_uninitialized {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrap_uninitialized<uninitialized<T>> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using unwrap_uninitialized_t = typename unwrap_uninitialized<T>::type;
|
||||
|
||||
using uexpression = uninitialized<expression>;
|
||||
|
||||
}
|
||||
|
||||
@context {
|
||||
@@ -398,8 +413,8 @@ selectStatement returns [std::unique_ptr<raw::select_statement> expr]
|
||||
( K_WHERE w=whereClause { wclause = std::move(w); } )?
|
||||
( K_GROUP K_BY gbcolumns=listOfIdentifiers)?
|
||||
( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] )* )?
|
||||
( K_PER K_PARTITION K_LIMIT rows=intValue { per_partition_limit = rows; } )?
|
||||
( K_LIMIT rows=intValue { limit = rows; } )?
|
||||
( K_PER K_PARTITION K_LIMIT rows=intValue { per_partition_limit = std::move(rows); } )?
|
||||
( K_LIMIT rows=intValue { limit = std::move(rows); } )?
|
||||
( K_ALLOW K_FILTERING { allow_filtering = true; } )?
|
||||
( K_BYPASS K_CACHE { bypass_cache = true; })?
|
||||
( usingTimeoutClause[attrs] )?
|
||||
@@ -418,11 +433,11 @@ selectClause returns [std::vector<shared_ptr<raw_selector>> expr]
|
||||
|
||||
selector returns [shared_ptr<raw_selector> s]
|
||||
@init{ shared_ptr<cql3::column_identifier> alias; }
|
||||
: us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = ::make_shared<raw_selector>(us, alias); }
|
||||
: us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = ::make_shared<raw_selector>(std::move(us), alias); }
|
||||
;
|
||||
|
||||
unaliasedSelector returns [expression s]
|
||||
@init { expression tmp; }
|
||||
unaliasedSelector returns [uexpression s]
|
||||
@init { uexpression tmp; }
|
||||
: ( c=cident { tmp = unresolved_identifier{std::move(c)}; }
|
||||
| K_COUNT '(' countArgument ')' { tmp = make_count_rows_function_expression(); }
|
||||
| K_WRITETIME '(' c=cident ')' { tmp = column_mutation_attribute{column_mutation_attribute::attribute_kind::writetime,
|
||||
@@ -450,7 +465,7 @@ countArgument
|
||||
} }
|
||||
;
|
||||
|
||||
whereClause returns [expression clause]
|
||||
whereClause returns [uexpression clause]
|
||||
@init { std::vector<expression> terms; }
|
||||
: e1=relation { terms.push_back(std::move(e1)); } (K_AND en=relation { terms.push_back(std::move(en)); })*
|
||||
{ clause = conjunction{std::move(terms)}; }
|
||||
@@ -463,7 +478,7 @@ orderByClause[raw::select_statement::parameters::orderings_type& orderings]
|
||||
: c=cident (K_ASC | K_DESC { ordering = raw::select_statement::ordering::descending; })? { orderings.emplace_back(c, ordering); }
|
||||
;
|
||||
|
||||
jsonValue returns [expression value]
|
||||
jsonValue returns [uexpression value]
|
||||
:
|
||||
| s=STRING_LITERAL { $value = untyped_constant{untyped_constant::string, $s.text}; }
|
||||
| m=marker { $value = std::move(m); }
|
||||
@@ -487,7 +502,7 @@ insertStatement returns [std::unique_ptr<raw::modification_statement> expr]
|
||||
: K_INSERT K_INTO cf=columnFamilyName
|
||||
('(' c1=cident { column_names.push_back(c1); } ( ',' cn=cident { column_names.push_back(cn); } )* ')'
|
||||
K_VALUES
|
||||
'(' v1=term { values.push_back(v1); } ( ',' vn=term { values.push_back(vn); } )* ')'
|
||||
'(' v1=term { values.push_back(std::move(v1)); } ( ',' vn=term { values.push_back(std::move(vn)); } )* ')'
|
||||
( K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
|
||||
( usingClause[attrs] )?
|
||||
{
|
||||
@@ -498,7 +513,7 @@ insertStatement returns [std::unique_ptr<raw::modification_statement> expr]
|
||||
if_not_exists);
|
||||
}
|
||||
| K_JSON
|
||||
json_token=jsonValue { json_value = $json_token.value; }
|
||||
json_token=jsonValue { json_value = std::move(json_token); }
|
||||
( K_DEFAULT K_UNSET { default_unset = true; } | K_DEFAULT K_NULL )?
|
||||
( K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
|
||||
( usingClause[attrs] )?
|
||||
@@ -517,9 +532,9 @@ usingClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
;
|
||||
|
||||
usingClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
: K_TIMESTAMP ts=intValue { attrs->timestamp = ts; }
|
||||
| K_TTL t=intValue { attrs->time_to_live = t; }
|
||||
| K_TIMEOUT to=term { attrs->timeout = to; }
|
||||
: K_TIMESTAMP ts=intValue { attrs->timestamp = std::move(ts); }
|
||||
| K_TTL t=intValue { attrs->time_to_live = std::move(t); }
|
||||
| K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
||||
;
|
||||
|
||||
usingTimestampTimeoutClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
@@ -527,12 +542,12 @@ usingTimestampTimeoutClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
;
|
||||
|
||||
usingTimestampTimeoutClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
: K_TIMESTAMP ts=intValue { attrs->timestamp = ts; }
|
||||
| K_TIMEOUT to=term { attrs->timeout = to; }
|
||||
: K_TIMESTAMP ts=intValue { attrs->timestamp = std::move(ts); }
|
||||
| K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
||||
;
|
||||
|
||||
usingTimeoutClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
: K_USING K_TIMEOUT to=term { attrs->timeout = to; }
|
||||
: K_USING K_TIMEOUT to=term { attrs->timeout = std::move(to); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -563,7 +578,7 @@ updateStatement returns [std::unique_ptr<raw::update_statement> expr]
|
||||
}
|
||||
;
|
||||
|
||||
updateConditions returns [expression cond]
|
||||
updateConditions returns [uexpression cond]
|
||||
@init {
|
||||
std::vector<expression> conditions;
|
||||
}
|
||||
@@ -732,7 +747,7 @@ createAggregateStatement returns [std::unique_ptr<cql3::statements::create_aggre
|
||||
K_FINALFUNC final_func = allowedFunctionName { ffunc = final_func; }
|
||||
)?
|
||||
(
|
||||
K_INITCOND init_val = term { ival = init_val; }
|
||||
K_INITCOND init_val = term { ival = std::move(init_val); }
|
||||
)?
|
||||
{ $expr = std::make_unique<cql3::statements::create_aggregate_statement>(std::move(fn), std::move(arg_types), std::move(sfunc), std::move(stype), std::move(rfunc), std::move(ffunc), std::move(ival), or_replace, if_not_exists); }
|
||||
;
|
||||
@@ -852,7 +867,7 @@ cfamOrdering[cql3::statements::cf_properties& expr]
|
||||
createTypeStatement returns [std::unique_ptr<create_type_statement> expr]
|
||||
@init { bool if_not_exists = false; }
|
||||
: K_CREATE K_TYPE (K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
|
||||
tn=userTypeName { $expr = std::make_unique<create_type_statement>(tn, if_not_exists); }
|
||||
tn=userTypeName { $expr = std::make_unique<create_type_statement>(ut_name(std::move(tn)), if_not_exists); }
|
||||
'(' typeColumns[*expr] ( ',' typeColumns[*expr]? )* ')'
|
||||
;
|
||||
|
||||
@@ -1015,10 +1030,10 @@ cfisStatic returns [bool isStaticColumn]
|
||||
*/
|
||||
alterTypeStatement returns [std::unique_ptr<alter_type_statement> expr]
|
||||
: K_ALTER K_TYPE name=userTypeName
|
||||
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(name, false, f, v); }
|
||||
| K_ADD f=ident v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(name, true, f, v); }
|
||||
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(std::move(name), false, f, v); }
|
||||
| K_ADD f=ident v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(std::move(name), true, f, v); }
|
||||
| K_RENAME
|
||||
{ $expr = std::make_unique<alter_type_statement::renames>(name); }
|
||||
{ $expr = std::make_unique<alter_type_statement::renames>(std::move(name)); }
|
||||
renames[{ static_cast<alter_type_statement::renames&>(*$expr) }]
|
||||
)
|
||||
;
|
||||
@@ -1062,7 +1077,7 @@ dropTableStatement returns [std::unique_ptr<drop_table_statement> stmt]
|
||||
*/
|
||||
dropTypeStatement returns [std::unique_ptr<drop_type_statement> stmt]
|
||||
@init { bool if_exists = false; }
|
||||
: K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = std::make_unique<drop_type_statement>(name, if_exists); }
|
||||
: K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = std::make_unique<drop_type_statement>(std::move(name), if_exists); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1105,10 +1120,10 @@ grantStatement returns [std::unique_ptr<grant_statement> stmt]
|
||||
: K_GRANT
|
||||
permissionOrAll
|
||||
K_ON
|
||||
resource
|
||||
r=resource
|
||||
K_TO
|
||||
grantee=userOrRoleName
|
||||
{ $stmt = std::make_unique<grant_statement>($permissionOrAll.perms, $resource.res, std::move(grantee)); }
|
||||
{ $stmt = std::make_unique<grant_statement>($permissionOrAll.perms, std::move(r), std::move(grantee)); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1118,10 +1133,10 @@ revokeStatement returns [std::unique_ptr<revoke_statement> stmt]
|
||||
: K_REVOKE
|
||||
permissionOrAll
|
||||
K_ON
|
||||
resource
|
||||
r=resource
|
||||
K_FROM
|
||||
revokee=userOrRoleName
|
||||
{ $stmt = std::make_unique<revoke_statement>($permissionOrAll.perms, $resource.res, std::move(revokee)); }
|
||||
{ $stmt = std::make_unique<revoke_statement>($permissionOrAll.perms, std::move(r), std::move(revokee)); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1148,8 +1163,8 @@ listPermissionsStatement returns [std::unique_ptr<list_permissions_statement> st
|
||||
}
|
||||
: K_LIST
|
||||
permissionOrAll
|
||||
( K_ON resource { r = $resource.res; } )?
|
||||
( K_OF rn=userOrRoleName { role = sstring(static_cast<cql3::role_name>(rn).to_string()); } )?
|
||||
( K_ON rr=resource { r = std::move(rr); } )?
|
||||
( K_OF rn=userOrRoleName { role = sstring(cql3::role_name(std::move(rn)).to_string()); } )?
|
||||
( K_NORECURSIVE { recursive = false; } )?
|
||||
{ $stmt = std::make_unique<list_permissions_statement>($permissionOrAll.perms, std::move(r), std::move(role), recursive); }
|
||||
;
|
||||
@@ -1179,7 +1194,7 @@ dataResource returns [uninitialized<auth::resource> res]
|
||||
|
||||
roleResource returns [uninitialized<auth::resource> res]
|
||||
: K_ALL K_ROLES { $res = auth::resource(auth::resource_kind::role); }
|
||||
| K_ROLE role = userOrRoleName { $res = auth::make_role_resource(static_cast<const cql3::role_name&>(role).to_string()); }
|
||||
| K_ROLE role = userOrRoleName { $res = auth::make_role_resource(cql3::role_name(std::move(role)).to_string()); }
|
||||
;
|
||||
|
||||
functionResource returns [uninitialized<auth::resource> res]
|
||||
@@ -1236,7 +1251,7 @@ alterUserStatement returns [std::unique_ptr<alter_role_statement> stmt]
|
||||
dropUserStatement returns [std::unique_ptr<drop_role_statement> stmt]
|
||||
@init { bool ifExists = false; }
|
||||
: K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? u=username
|
||||
{ $stmt = std::make_unique<drop_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), ifExists); }
|
||||
{ $stmt = std::make_unique<drop_role_statement>(cql3::role_name(std::move(u), cql3::preserve_role_case::yes), ifExists); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1258,7 +1273,7 @@ createRoleStatement returns [std::unique_ptr<create_role_statement> stmt]
|
||||
}
|
||||
: K_CREATE K_ROLE (K_IF K_NOT K_EXISTS { if_not_exists = true; })? name=userOrRoleName
|
||||
(K_WITH roleOptions[opts])?
|
||||
{ $stmt = std::make_unique<create_role_statement>(name, std::move(opts), if_not_exists); }
|
||||
{ $stmt = std::make_unique<create_role_statement>(std::move(name), std::move(opts), if_not_exists); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1270,7 +1285,7 @@ alterRoleStatement returns [std::unique_ptr<alter_role_statement> stmt]
|
||||
}
|
||||
: K_ALTER K_ROLE name=userOrRoleName
|
||||
(K_WITH roleOptions[opts])?
|
||||
{ $stmt = std::make_unique<alter_role_statement>(name, std::move(opts)); }
|
||||
{ $stmt = std::make_unique<alter_role_statement>(std::move(name), std::move(opts)); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1281,7 +1296,7 @@ dropRoleStatement returns [std::unique_ptr<drop_role_statement> stmt]
|
||||
bool if_exists = false;
|
||||
}
|
||||
: K_DROP K_ROLE (K_IF K_EXISTS { if_exists = true; })? name=userOrRoleName
|
||||
{ $stmt = std::make_unique<drop_role_statement>(name, if_exists); }
|
||||
{ $stmt = std::make_unique<drop_role_statement>(std::move(name), if_exists); }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1435,7 +1450,7 @@ describeStatement returns [std::unique_ptr<cql3::statements::raw::describe_state
|
||||
| K_INDEX idx=columnFamilyName { $stmt = cql3::statements::raw::describe_statement::index(idx); }
|
||||
| K_MATERIALIZED K_VIEW view=columnFamilyName { $stmt = cql3::statements::raw::describe_statement::view(view); }
|
||||
| (K_TYPES) => K_TYPES { $stmt = cql3::statements::raw::describe_statement::types(); }
|
||||
| K_TYPE tn=userTypeName { $stmt = cql3::statements::raw::describe_statement::type(tn); }
|
||||
| K_TYPE tn=userTypeName { $stmt = cql3::statements::raw::describe_statement::type(std::move(tn)); }
|
||||
| (K_FUNCTIONS) => K_FUNCTIONS { $stmt = cql3::statements::raw::describe_statement::functions(); }
|
||||
| K_FUNCTION fn=functionName { $stmt = cql3::statements::raw::describe_statement::function(fn); }
|
||||
| (K_AGGREGATES) => K_AGGREGATES { $stmt = cql3::statements::raw::describe_statement::aggregates(); }
|
||||
@@ -1558,7 +1573,7 @@ mapLiteral returns [collection_constructor map]
|
||||
'}' { $map = collection_constructor{collection_constructor::style_type::map, std::move(m)}; }
|
||||
;
|
||||
|
||||
setOrMapLiteral[expression t] returns [collection_constructor value]
|
||||
setOrMapLiteral[uexpression t] returns [collection_constructor value]
|
||||
@init{ std::vector<expression> e; }
|
||||
: ':' v=term { e.push_back(tuple_constructor{{std::move(t), std::move(v)}}); }
|
||||
( ',' kn=term ':' vn=term { e.push_back(tuple_constructor{{std::move(kn), std::move(vn)}}); } )*
|
||||
@@ -1568,7 +1583,7 @@ setOrMapLiteral[expression t] returns [collection_constructor value]
|
||||
{ $value = collection_constructor{collection_constructor::style_type::set, std::move(e)}; }
|
||||
;
|
||||
|
||||
collectionLiteral returns [expression value]
|
||||
collectionLiteral returns [uexpression value]
|
||||
@init{ std::vector<expression> l; }
|
||||
: '['
|
||||
( t1=term { l.push_back(std::move(t1)); } ( ',' tn=term { l.push_back(std::move(tn)); } )* )?
|
||||
@@ -1579,20 +1594,20 @@ collectionLiteral returns [expression value]
|
||||
| '{' '}' { $value = collection_constructor{collection_constructor::style_type::set, {}}; }
|
||||
;
|
||||
|
||||
usertypeLiteral returns [expression ut]
|
||||
usertypeLiteral returns [uexpression ut]
|
||||
@init{ usertype_constructor::elements_map_type m; }
|
||||
@after{ $ut = usertype_constructor{std::move(m)}; }
|
||||
// We don't allow empty literals because that conflicts with sets/maps and is currently useless since we don't allow empty user types
|
||||
: '{' k1=ident ':' v1=term { m.emplace(std::move(*k1), std::move(v1)); } ( ',' kn=ident ':' vn=term { m.emplace(std::move(*kn), std::move(vn)); } )* '}'
|
||||
;
|
||||
|
||||
tupleLiteral returns [expression tt]
|
||||
tupleLiteral returns [uexpression tt]
|
||||
@init{ std::vector<expression> l; }
|
||||
@after{ $tt = tuple_constructor{std::move(l)}; }
|
||||
: '(' t1=term { l.push_back(std::move(t1)); } ( ',' tn=term { l.push_back(std::move(tn)); } )* ')'
|
||||
;
|
||||
|
||||
value returns [expression value]
|
||||
value returns [uexpression value]
|
||||
: c=constant { $value = std::move(c); }
|
||||
| l=collectionLiteral { $value = std::move(l); }
|
||||
| u=usertypeLiteral { $value = std::move(u); }
|
||||
@@ -1601,12 +1616,12 @@ value returns [expression value]
|
||||
| e=marker { $value = std::move(e); }
|
||||
;
|
||||
|
||||
marker returns [expression value]
|
||||
marker returns [uexpression value]
|
||||
: ':' id=ident { $value = new_bind_variables(id); }
|
||||
| QMARK { $value = new_bind_variables(shared_ptr<cql3::column_identifier>{}); }
|
||||
;
|
||||
|
||||
intValue returns [expression value]
|
||||
intValue returns [uexpression value]
|
||||
:
|
||||
| t=INTEGER { $value = untyped_constant{untyped_constant::integer, $t.text}; }
|
||||
| e=marker { $value = std::move(e); }
|
||||
@@ -1631,7 +1646,7 @@ functionArgs returns [std::vector<expression> a]
|
||||
')'
|
||||
;
|
||||
|
||||
term returns [expression term1]
|
||||
term returns [uexpression term1]
|
||||
: v=value { $term1 = std::move(v); }
|
||||
| f=functionName args=functionArgs { $term1 = function_call{std::move(f), std::move(args)}; }
|
||||
| '(' c=comparatorType ')' t=term { $term1 = cast{.style = cast::cast_style::c, .arg = std::move(t), .type = c}; }
|
||||
@@ -1643,21 +1658,21 @@ columnOperation[operations_type& operations]
|
||||
|
||||
columnOperationDifferentiator[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
||||
: '=' normalColumnOperation[operations, key]
|
||||
| '[' k=term ']' collectionColumnOperation[operations, key, k, false]
|
||||
| '[' k=term ']' collectionColumnOperation[operations, key, std::move(k), false]
|
||||
| '.' field=ident udtColumnOperation[operations, key, field]
|
||||
| '[' K_SCYLLA_TIMEUUID_LIST_INDEX '(' k=term ')' ']' collectionColumnOperation[operations, key, k, true]
|
||||
| '[' K_SCYLLA_TIMEUUID_LIST_INDEX '(' k=term ')' ']' collectionColumnOperation[operations, key, std::move(k), true]
|
||||
;
|
||||
|
||||
normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
||||
: t=term ('+' c=cident )?
|
||||
{
|
||||
if (!c) {
|
||||
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_value>(t));
|
||||
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_value>(std::move(t)));
|
||||
} else {
|
||||
if (*key != *c) {
|
||||
add_recognition_error("Only expressions of the form X = <value> + X are supported.");
|
||||
}
|
||||
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::prepend>(t));
|
||||
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::prepend>(std::move(t)));
|
||||
}
|
||||
}
|
||||
| c=cident sig=('+' | '-') t=term
|
||||
@@ -1667,9 +1682,9 @@ normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_ide
|
||||
}
|
||||
std::unique_ptr<cql3::operation::raw_update> op;
|
||||
if ($sig.text == "+") {
|
||||
op = std::make_unique<cql3::operation::addition>(t);
|
||||
op = std::make_unique<cql3::operation::addition>(std::move(t));
|
||||
} else {
|
||||
op = std::make_unique<cql3::operation::subtraction>(t);
|
||||
op = std::make_unique<cql3::operation::subtraction>(std::move(t));
|
||||
}
|
||||
operations.emplace_back(std::move(key), std::move(op));
|
||||
}
|
||||
@@ -1684,7 +1699,7 @@ normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_ide
|
||||
}
|
||||
| K_SCYLLA_COUNTER_SHARD_LIST '(' t=term ')'
|
||||
{
|
||||
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_counter_value_from_tuple_list>(t));
|
||||
operations.emplace_back(std::move(key), std::make_unique<cql3::operation::set_counter_value_from_tuple_list>(std::move(t)));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1707,33 +1722,33 @@ udtColumnOperation[operations_type& operations,
|
||||
}
|
||||
;
|
||||
|
||||
columnRefExpr returns [expression e]
|
||||
columnRefExpr returns [uexpression e]
|
||||
: column=cident { e = unresolved_identifier{column}; }
|
||||
;
|
||||
|
||||
subscriptExpr returns [expression e]
|
||||
subscriptExpr returns [uexpression e]
|
||||
: col=columnRefExpr { e = std::move(col); }
|
||||
( '[' sub=term ']' { e = subscript{std::move(e), std::move(sub)}; } )?
|
||||
;
|
||||
|
||||
singleColumnInValuesOrMarkerExpr returns [expression e]
|
||||
singleColumnInValuesOrMarkerExpr returns [uexpression e]
|
||||
: values=singleColumnInValues { e = collection_constructor{collection_constructor::style_type::list, std::move(values)}; }
|
||||
| m=marker { e = std::move(m); }
|
||||
;
|
||||
|
||||
columnCondition returns [expression e]
|
||||
columnCondition returns [uexpression e]
|
||||
// Note: we'll reject duplicates later
|
||||
: key=subscriptExpr
|
||||
( op=relationType t=term {
|
||||
e = binary_operator(
|
||||
key,
|
||||
std::move(key),
|
||||
op,
|
||||
t);
|
||||
std::move(t));
|
||||
}
|
||||
| K_IN
|
||||
values=singleColumnInValuesOrMarkerExpr {
|
||||
e = binary_operator(
|
||||
key,
|
||||
std::move(key),
|
||||
oper_t::IN,
|
||||
std::move(values));
|
||||
}
|
||||
@@ -1770,7 +1785,7 @@ relationType returns [oper_t op]
|
||||
| K_LIKE { $op = oper_t::LIKE; }
|
||||
;
|
||||
|
||||
relation returns [expression e]
|
||||
relation returns [uexpression e]
|
||||
@init{ oper_t rt; }
|
||||
: name=cident type=relationType t=term { $e = binary_operator(unresolved_identifier{std::move(name)}, type, std::move(t)); }
|
||||
|
||||
@@ -1888,7 +1903,7 @@ comparator_type [bool internal] returns [shared_ptr<cql3_type::raw> t]
|
||||
: n=native_or_internal_type[internal] { $t = cql3_type::raw::from(n); }
|
||||
| c=collection_type[internal] { $t = c; }
|
||||
| tt=tuple_type[internal] { $t = tt; }
|
||||
| id=userTypeName { $t = cql3::cql3_type::raw::user_type(id); }
|
||||
| id=userTypeName { $t = cql3::cql3_type::raw::user_type(std::move(id)); }
|
||||
| K_FROZEN '<' f=comparator_type[internal] '>'
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -64,8 +64,8 @@ void constants::deleter::execute(mutation& m, const clustering_key_prefix& prefi
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
constants::setter::prepare_for_broadcast_tables(statements::broadcast_tables::prepared_update& query) const {
|
||||
query.new_value = *_e;
|
||||
expr::expression
|
||||
constants::setter::prepare_new_value_for_broadcast_tables() const {
|
||||
return *_e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
|
||||
static void execute(mutation& m, const clustering_key_prefix& prefix, const update_parameters& params, const column_definition& column, cql3::raw_value_view value);
|
||||
|
||||
virtual void prepare_for_broadcast_tables(statements::broadcast_tables::prepared_update& query) const override;
|
||||
virtual expr::expression prepare_new_value_for_broadcast_tables() const override;
|
||||
};
|
||||
|
||||
struct adder final : operation_skip_if_unset {
|
||||
|
||||
@@ -143,7 +143,6 @@ class expression final {
|
||||
struct impl;
|
||||
std::unique_ptr<impl> _v;
|
||||
public:
|
||||
expression(); // FIXME: remove
|
||||
expression(ExpressionElement auto e);
|
||||
|
||||
expression(const expression&);
|
||||
@@ -437,10 +436,6 @@ expression::expression(ExpressionElement auto e)
|
||||
: _v(std::make_unique<impl>(std::move(e))) {
|
||||
}
|
||||
|
||||
inline expression::expression()
|
||||
: expression(conjunction{}) {
|
||||
}
|
||||
|
||||
template <invocable_on_expression Visitor>
|
||||
decltype(auto) visit(Visitor&& visitor, const expression& e) {
|
||||
return std::visit(std::forward<Visitor>(visitor), e._v->v);
|
||||
|
||||
@@ -127,10 +127,8 @@ usertype_constructor_prepare_expression(const usertype_constructor& u, data_dict
|
||||
for (size_t i = 0; i < ut->size(); ++i) {
|
||||
auto&& field = column_identifier(to_bytes(ut->field_name(i)), utf8_type);
|
||||
auto iraw = u.elements.find(field);
|
||||
expression raw;
|
||||
if (iraw == u.elements.end()) {
|
||||
raw = expr::make_untyped_null();
|
||||
} else {
|
||||
expression raw = expr::make_untyped_null();
|
||||
if (iraw != u.elements.end()) {
|
||||
raw = iraw->second;
|
||||
++found_values;
|
||||
}
|
||||
|
||||
@@ -388,8 +388,8 @@ operation::element_deletion::prepare(data_dictionary::database db, const sstring
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
operation::prepare_for_broadcast_tables(statements::broadcast_tables::prepared_update&) const {
|
||||
expr::expression
|
||||
operation::prepare_new_value_for_broadcast_tables() const {
|
||||
// FIXME: implement for every type of `operation`.
|
||||
throw service::broadcast_tables::unsupported_operation_error{};
|
||||
}
|
||||
|
||||
@@ -23,10 +23,6 @@
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
namespace statements::broadcast_tables {
|
||||
struct prepared_update;
|
||||
}
|
||||
|
||||
class update_parameters;
|
||||
|
||||
/**
|
||||
@@ -95,7 +91,7 @@ public:
|
||||
return _unset_guard.is_unset(qo);
|
||||
}
|
||||
|
||||
virtual void prepare_for_broadcast_tables(statements::broadcast_tables::prepared_update&) const;
|
||||
virtual expr::expression prepare_new_value_for_broadcast_tables() const;
|
||||
|
||||
/**
|
||||
* A parsed raw UPDATE operation.
|
||||
|
||||
@@ -120,11 +120,9 @@ static std::vector<expr::expression> extract_partition_range(
|
||||
auto s = &cv;
|
||||
with_current_binary_operator(*this, [&] (const binary_operator& b) {
|
||||
if (s->col->is_partition_key() && (b.op == oper_t::EQ || b.op == oper_t::IN)) {
|
||||
const auto found = single_column.find(s->col);
|
||||
if (found == single_column.end()) {
|
||||
single_column[s->col] = b;
|
||||
} else {
|
||||
found->second = make_conjunction(std::move(found->second), b);
|
||||
const auto [it, inserted] = single_column.try_emplace(s->col, b);
|
||||
if (!inserted) {
|
||||
it->second = make_conjunction(std::move(it->second), b);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -139,11 +137,9 @@ static std::vector<expr::expression> extract_partition_range(
|
||||
|
||||
with_current_binary_operator(*this, [&] (const binary_operator& b) {
|
||||
if (cval.col->is_partition_key() && (b.op == oper_t::EQ || b.op == oper_t::IN)) {
|
||||
const auto found = single_column.find(cval.col);
|
||||
if (found == single_column.end()) {
|
||||
single_column[cval.col] = b;
|
||||
} else {
|
||||
found->second = make_conjunction(std::move(found->second), b);
|
||||
const auto [it, inserted] = single_column.try_emplace(cval.col, b);
|
||||
if (!inserted) {
|
||||
it->second = make_conjunction(std::move(it->second), b);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -247,11 +243,9 @@ static std::vector<expr::expression> extract_clustering_prefix_restrictions(
|
||||
auto s = &cv;
|
||||
with_current_binary_operator(*this, [&] (const binary_operator& b) {
|
||||
if (s->col->is_clustering_key()) {
|
||||
const auto found = single.find(s->col);
|
||||
if (found == single.end()) {
|
||||
single[s->col] = b;
|
||||
} else {
|
||||
found->second = make_conjunction(std::move(found->second), b);
|
||||
const auto [it, inserted] = single.try_emplace(s->col, b);
|
||||
if (!inserted) {
|
||||
it->second = make_conjunction(std::move(it->second), b);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -262,11 +256,9 @@ static std::vector<expr::expression> extract_clustering_prefix_restrictions(
|
||||
|
||||
with_current_binary_operator(*this, [&] (const binary_operator& b) {
|
||||
if (cval.col->is_clustering_key()) {
|
||||
const auto found = single.find(cval.col);
|
||||
if (found == single.end()) {
|
||||
single[cval.col] = b;
|
||||
} else {
|
||||
found->second = make_conjunction(std::move(found->second), b);
|
||||
const auto [it, inserted] = single.try_emplace(cval.col, b);
|
||||
if (!inserted) {
|
||||
it->second = make_conjunction(std::move(it->second), b);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -547,7 +539,7 @@ int statement_restrictions::score(const secondary_index::index& index) const {
|
||||
std::pair<std::optional<secondary_index::index>, expr::expression> statement_restrictions::find_idx(const secondary_index::secondary_index_manager& sim) const {
|
||||
std::optional<secondary_index::index> chosen_index;
|
||||
int chosen_index_score = 0;
|
||||
expr::expression chosen_index_restrictions;
|
||||
expr::expression chosen_index_restrictions = expr::conjunction({});
|
||||
|
||||
for (const auto& index : sim.list_indexes()) {
|
||||
auto cdef = _schema->get_column_definition(to_bytes(index.target_column()));
|
||||
@@ -1869,7 +1861,7 @@ void statement_restrictions::prepare_indexed_global(const schema& idx_tbl_schema
|
||||
|
||||
// If we're here, it means the index cannot be on a partition column: process_partition_key_restrictions()
|
||||
// avoids indexing when _partition_range_is_simple. See _idx_tbl_ck_prefix blurb for its composition.
|
||||
_idx_tbl_ck_prefix = std::vector<expr::expression>(1 + _schema->partition_key_size());
|
||||
_idx_tbl_ck_prefix = std::vector<expr::expression>(1 + _schema->partition_key_size(), expr::conjunction({}));
|
||||
_idx_tbl_ck_prefix->reserve(_idx_tbl_ck_prefix->size() + idx_tbl_schema.clustering_key_size());
|
||||
for (const auto& e : _partition_range_restrictions) {
|
||||
const auto col = expr::as<column_value>(find(e, oper_t::EQ)->lhs).col;
|
||||
|
||||
@@ -40,21 +40,21 @@ private:
|
||||
/**
|
||||
* Restrictions on partitioning columns
|
||||
*/
|
||||
expr::expression _partition_key_restrictions;
|
||||
expr::expression _partition_key_restrictions = expr::conjunction({});
|
||||
|
||||
expr::single_column_restrictions_map _single_column_partition_key_restrictions;
|
||||
|
||||
/**
|
||||
* Restrictions on clustering columns
|
||||
*/
|
||||
expr::expression _clustering_columns_restrictions;
|
||||
expr::expression _clustering_columns_restrictions = expr::conjunction({});
|
||||
|
||||
expr::single_column_restrictions_map _single_column_clustering_key_restrictions;
|
||||
|
||||
/**
|
||||
* Restriction on non-primary key columns (i.e. secondary index restrictions)
|
||||
*/
|
||||
expr::expression _nonprimary_key_restrictions;
|
||||
expr::expression _nonprimary_key_restrictions = expr::conjunction({});
|
||||
|
||||
expr::single_column_restrictions_map _single_column_nonprimary_key_restrictions;
|
||||
|
||||
|
||||
@@ -290,12 +290,13 @@ expr::expression get_key(const cql3::expr::expression& partition_key_restriction
|
||||
}
|
||||
|
||||
static
|
||||
void prepare_new_value(broadcast_tables::prepared_update& query, const std::vector<::shared_ptr<operation>>& operations) {
|
||||
expr::expression
|
||||
prepare_new_value(const std::vector<::shared_ptr<operation>>& operations) {
|
||||
if (operations.size() != 1) {
|
||||
throw service::broadcast_tables::unsupported_operation_error("only one operation is allowed and must be of the form \"value = X\"");
|
||||
}
|
||||
|
||||
operations[0]->prepare_for_broadcast_tables(query);
|
||||
return operations[0]->prepare_new_value_for_broadcast_tables();
|
||||
}
|
||||
|
||||
static
|
||||
@@ -345,11 +346,10 @@ update_statement::prepare_for_broadcast_tables() const {
|
||||
|
||||
broadcast_tables::prepared_update query = {
|
||||
.key = get_key(restrictions().get_partition_key_restrictions()),
|
||||
.new_value = prepare_new_value(_column_operations),
|
||||
.value_condition = get_value_condition(_condition),
|
||||
};
|
||||
|
||||
prepare_new_value(query, _column_operations);
|
||||
|
||||
return ::make_shared<strongly_consistent_modification_statement>(
|
||||
get_bound_terms(),
|
||||
s,
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace util {
|
||||
|
||||
void do_with_parser_impl(const sstring_view& cql, noncopyable_function<void (cql3_parser::CqlParser& p)> func);
|
||||
|
||||
template <typename Func, typename Result = std::result_of_t<Func(cql3_parser::CqlParser&)>>
|
||||
template <typename Func, typename Result = cql3_parser::unwrap_uninitialized_t<std::result_of_t<Func(cql3_parser::CqlParser&)>>>
|
||||
Result do_with_parser(const sstring_view& cql, Func&& f) {
|
||||
std::optional<Result> ret;
|
||||
do_with_parser_impl(cql, [&] (cql3_parser::CqlParser& parser) {
|
||||
|
||||
@@ -2421,7 +2421,7 @@ BOOST_AUTO_TEST_CASE(prepare_usertype_constructor_with_bind_variable) {
|
||||
BOOST_REQUIRE(prepared_constructor->elements.contains(column_identifier("field2", true)));
|
||||
|
||||
bind_variable* prepared_bind_var =
|
||||
as_if<bind_variable>(&prepared_constructor->elements[column_identifier("field2", true)]);
|
||||
as_if<bind_variable>(&prepared_constructor->elements.at(column_identifier("field2", true)));
|
||||
BOOST_REQUIRE(prepared_bind_var != nullptr);
|
||||
|
||||
::lw_shared_ptr<column_specification> bind_var_receiver = prepared_bind_var->receiver;
|
||||
@@ -2466,7 +2466,7 @@ BOOST_AUTO_TEST_CASE(prepare_usertype_constructor_with_bind_variable_and_missing
|
||||
BOOST_REQUIRE(prepared_constructor->elements.contains(column_identifier("field2", true)));
|
||||
|
||||
bind_variable* prepared_bind_var =
|
||||
as_if<bind_variable>(&prepared_constructor->elements[column_identifier("field2", true)]);
|
||||
as_if<bind_variable>(&prepared_constructor->elements.at(column_identifier("field2", true)));
|
||||
BOOST_REQUIRE(prepared_bind_var != nullptr);
|
||||
|
||||
::lw_shared_ptr<column_specification> bind_var_receiver = prepared_bind_var->receiver;
|
||||
|
||||
Reference in New Issue
Block a user