diff --git a/cql3/expr/prepare_expr.cc b/cql3/expr/prepare_expr.cc index 5409376d0b..8510c8ad06 100644 --- a/cql3/expr/prepare_expr.cc +++ b/cql3/expr/prepare_expr.cc @@ -128,6 +128,14 @@ map_key_spec_of(const column_specification& column) { dynamic_cast(column.type->without_reversed()).get_keys_type()); } +static +lw_shared_ptr +list_key_spec_of(const column_specification& column) { + return make_lw_shared(column.ks_name, column.cf_name, + ::make_shared(format("index({})", *column.name), true), + int32_type); +} + static lw_shared_ptr 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 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 get_lhs_receiver(const expression& pr }, [](const subscript& col_val) -> lw_shared_ptr { 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 { std::ostringstream tuple_name; diff --git a/test/cql-pytest/test_filtering.py b/test/cql-pytest/test_filtering.py index d3371df266..b43b0d5fe9 100644 --- a/test/cql-pytest/test_filtering.py +++ b/test/cql-pytest/test_filtering.py @@ -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)')):