diff --git a/cql3/expr/expression.cc b/cql3/expr/expression.cc index 51a9f9b73c..3f0c61913d 100644 --- a/cql3/expr/expression.cc +++ b/cql3/expr/expression.cc @@ -1717,19 +1717,6 @@ cql3::raw_value do_evaluate(const conjunction& conj, const evaluation_inputs& in static cql3::raw_value do_evaluate(const field_selection& field_select, const evaluation_inputs& inputs) { - const user_type_impl* udt_type = dynamic_cast(&type_of(field_select.structure)->without_reversed()); - if (udt_type == nullptr) { - on_internal_error(expr_logger, "evaluate(field_selection): type is not a user defined type"); - } - - const sstring& selected_field_name = field_select.field->text(); - std::optional selected_field_idx = udt_type->idx_of_field(to_bytes_view(selected_field_name)); - if (!selected_field_idx.has_value()) { - throw exceptions::invalid_request_exception( - format("Unknown field '{}' in expression {}, user type {} doesn't have a field with this name.", - selected_field_name, field_select, udt_type->get_name_as_string())); - } - cql3::raw_value udt_value = evaluate(field_select.structure, inputs); if (udt_value.is_null()) { // `.field` should evaluate to NULL. @@ -1739,7 +1726,7 @@ cql3::raw_value do_evaluate(const field_selection& field_select, const evaluatio cql3::raw_value field_value = udt_value.view().with_value( [&](const FragmentedView auto& udt_serialized_bytes) -> cql3::raw_value { // std::optional read_field - auto read_field = read_nth_user_type_field(udt_serialized_bytes, *selected_field_idx); + auto read_field = read_nth_user_type_field(udt_serialized_bytes, field_select.field_idx); if (read_field.has_value()) { return cql3::raw_value::make_value(managed_bytes(*read_field)); diff --git a/test/boost/expr_test.cc b/test/boost/expr_test.cc index e1dc8284c7..3d894ffc0f 100644 --- a/test/boost/expr_test.cc +++ b/test/boost/expr_test.cc @@ -3248,6 +3248,9 @@ BOOST_AUTO_TEST_CASE(evaluate_conjunction_of_conjunctions_with_invalid) { } BOOST_AUTO_TEST_CASE(evaluate_field_selection) { + auto schema = make_simple_test_schema(); + auto [db, db_data] = make_data_dictionary_database(schema); + // The user defined type has 5 fields: // CREATE TYPE test_ks.my_type ( // int_field int, @@ -3278,19 +3281,25 @@ BOOST_AUTO_TEST_CASE(evaluate_field_selection) { .structure = value, .field = make_shared(selected_field, true), .type = field_type}; }; + + auto prepare_and_evaluate = [&,db = db] (const expression& e, const evaluation_inputs& inputs) { + auto prepared = prepare_expression(e, db, "", schema.get(), nullptr); + return evaluate(prepared, inputs); + }; + // Evaluate the fields, check that field values are correct - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(udt_value, "int_field", int32_type), evaluation_inputs{}), make_int_raw(123)); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(udt_value, "float_field", float_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(udt_value, "int_field", int32_type), evaluation_inputs{}), make_int_raw(123)); + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(udt_value, "float_field", float_type), evaluation_inputs{}), cql3::raw_value::make_null()); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(udt_value, "text_field", utf8_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(udt_value, "text_field", utf8_type), evaluation_inputs{}), make_text_raw("abcdef")); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(udt_value, "bigint_field", long_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(udt_value, "bigint_field", long_type), evaluation_inputs{}), make_empty_raw()); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(udt_value, "int_field2", int32_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(udt_value, "int_field2", int32_type), evaluation_inputs{}), make_int_raw(1337)); // Evaluate a nonexistent field, should throw an exception - BOOST_REQUIRE_THROW(evaluate(make_field_selection(udt_value, "field_testing", int32_type), evaluation_inputs{}), + BOOST_REQUIRE_THROW(prepare_and_evaluate(make_field_selection(udt_value, "field_testing", int32_type), evaluation_inputs{}), exceptions::invalid_request_exception); // Create a UDT value with values for the first 3 fields. @@ -3302,21 +3311,21 @@ BOOST_AUTO_TEST_CASE(evaluate_field_selection) { constant(make_tuple_raw({make_int_raw(123), cql3::raw_value::make_null(), make_text_raw("")}), udt_type); // Evaluate the first 3 fields, check that the value is correct - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(short_udt_value, "int_field", int32_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(short_udt_value, "int_field", int32_type), evaluation_inputs{}), make_int_raw(123)); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(short_udt_value, "float_field", float_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(short_udt_value, "float_field", float_type), evaluation_inputs{}), cql3::raw_value::make_null()); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(short_udt_value, "text_field", utf8_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(short_udt_value, "text_field", utf8_type), evaluation_inputs{}), make_text_raw("")); // The serialized value doesn't contain any data for the 4th or 5th field, so they should be NULL. - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(short_udt_value, "bigint_field", long_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(short_udt_value, "bigint_field", long_type), evaluation_inputs{}), cql3::raw_value::make_null()); - BOOST_REQUIRE_EQUAL(evaluate(make_field_selection(short_udt_value, "int_field2", int32_type), evaluation_inputs{}), + BOOST_REQUIRE_EQUAL(prepare_and_evaluate(make_field_selection(short_udt_value, "int_field2", int32_type), evaluation_inputs{}), cql3::raw_value::make_null()); // Evaluate a nonexistent field, should throw an exception - BOOST_REQUIRE_THROW(evaluate(make_field_selection(short_udt_value, "field_testing", int32_type), evaluation_inputs{}), + BOOST_REQUIRE_THROW(prepare_and_evaluate(make_field_selection(short_udt_value, "field_testing", int32_type), evaluation_inputs{}), exceptions::invalid_request_exception); }