cql3: expr: avoid redoing prepare work when evaluating field_selection
prepare_expression() already validates the types and computes the index of the field; no need to redo that work when evaluating the expression. The tests are adjusted to also prepare the expression. Closes #14562
This commit is contained in:
@@ -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<const user_type_impl*>(&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<std::size_t> 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()) {
|
||||
// `<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<FragmentedView> 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));
|
||||
|
||||
@@ -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<column_identifier_raw>(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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user