cql3: expr: prepare_expr: support subscripted lists

Infer the type of a list index as int32_type.

The error message when a non-subscriptable type is provided is
changed, so the corresponding test is changed too.
This commit is contained in:
Avi Kivity
2022-05-23 20:59:03 +03:00
parent 8d667e374b
commit 35e0474410
2 changed files with 23 additions and 5 deletions

View File

@@ -128,6 +128,14 @@ map_key_spec_of(const column_specification& column) {
dynamic_cast<const map_type_impl&>(column.type->without_reversed()).get_keys_type());
}
static
lw_shared_ptr<column_specification>
list_key_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("index({})", *column.name), true),
int32_type);
}
static
lw_shared_ptr<column_specification>
map_value_spec_of(const column_specification& column) {
@@ -982,13 +990,19 @@ static expression prepare_binop_lhs(const expression& lhs, data_dictionary::data
}, sub.val);
const abstract_type& sub_col_type = sub_col->column_specification->type->without_reversed();
if (!sub_col_type.is_map()) {
throw exceptions::invalid_request_exception(format("Column {} is not a map, cannot be used as a map", sub_col->name_as_text()));
lw_shared_ptr<column_specification> subscript_column_spec;
if (sub_col_type.is_map()) {
subscript_column_spec = map_key_spec_of(*sub_col->column_specification);
} else if (sub_col_type.is_list()) {
subscript_column_spec = list_key_spec_of(*sub_col->column_specification);
} else {
throw exceptions::invalid_request_exception(format("Column {} is not a map/list, cannot be subscripted", sub_col->name_as_text()));
}
return subscript {
.val = column_value(sub_col),
.sub = prepare_expression(sub.sub, db, schema.ks_name(), map_key_spec_of(*sub_col->column_specification))
.sub = prepare_expression(sub.sub, db, schema.ks_name(), std::move(subscript_column_spec))
};
},
[](const auto& e) -> expression {
@@ -1005,7 +1019,11 @@ static lw_shared_ptr<column_specification> get_lhs_receiver(const expression& pr
},
[](const subscript& col_val) -> lw_shared_ptr<column_specification> {
const column_value& sub_col = get_subscripted_column(col_val);
return map_value_spec_of(*sub_col.col->column_specification);
if (sub_col.col->type->is_map()) {
return map_value_spec_of(*sub_col.col->column_specification);
} else {
return list_value_spec_of(*sub_col.col->column_specification);
}
},
[&](const tuple_constructor& tup) -> lw_shared_ptr<column_specification> {
std::ostringstream tuple_name;

View File

@@ -194,7 +194,7 @@ def test_filtering_with_subscript(cql, test_keyspace, cassandra_bug):
# expression - because there will be no rows to filter.
# A subscript is not allowed on a non-map column (in this case, a set)
with pytest.raises(InvalidRequest, match='cannot be used as a map'):
with pytest.raises(InvalidRequest, match='cannot be subscripted'):
cql.execute(f"SELECT p FROM {table} WHERE s[2] = 3 ALLOW FILTERING")
# A wrong type is passed for the subscript is not allowed
with pytest.raises(InvalidRequest, match=re.escape('key(m1)')):