diff --git a/types.cc b/types.cc index 18e5f440cb..161b314f15 100644 --- a/types.cc +++ b/types.cc @@ -256,10 +256,6 @@ struct int32_type_impl : integer_type_impl { struct long_type_impl : integer_type_impl { long_type_impl() : integer_type_impl{kind::long_kind, long_type_name, 8} { } - - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override { - return &other == this || &other == date_type.get() || &other == timestamp_type.get(); - } }; struct string_type_impl : public concrete_type { @@ -352,9 +348,6 @@ struct bytes_type_impl final : public concrete_type { v.remove_prefix(2); return bytes_type->from_string(v); } - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override { - return true; - } }; struct boolean_type_impl : public simple_type_impl { @@ -450,9 +443,6 @@ public: } return from_string(value.asString()); } - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override { - return &other == this || &other == timestamp_type.get() || &other == long_type.get(); - } friend abstract_type; }; @@ -675,9 +665,6 @@ public: } return from_string(value.asString()); } - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override { - return &other == this || &other == date_type.get() || &other == long_type.get(); - } friend abstract_type; }; logging::logger timestamp_type_impl::_logger(timestamp_type_name); @@ -883,9 +870,6 @@ struct uuid_type_impl : concrete_type { virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const override { return from_string(value.asString()); } - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override { - return &other == this || &other == timeuuid_type.get(); - } }; using inet_address = seastar::net::inet_address; @@ -1152,9 +1136,6 @@ public: throw marshal_exception(format("unable to make int from '{}'", text)); } } - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override { - return &other == this || int32_type->is_value_compatible_with(other) || long_type->is_value_compatible_with(other); - } friend class decimal_type_impl; }; @@ -1650,20 +1631,16 @@ static bool is_compatible_with_aux(const collection_type_impl& t, const abstract return t.value_comparator()->is_value_compatible_with(*cprev.value_comparator()); } -bool -collection_type_impl::is_value_compatible_with_internal(const abstract_type& previous) const { - // for multi-cell collections, compatibility and value-compatibility are the same - if (is_multi_cell() || previous.is_multi_cell()) { - return is_compatible_with(previous); - } - if (!previous.is_collection()) { +static bool is_value_compatible_with_internal_aux(const collection_type_impl& t, const abstract_type& previous) { + if (t.get_kind() != previous.get_kind()) { return false; } auto& cprev = static_cast(previous); - if (get_kind() != cprev.get_kind()) { - return false; + // for multi-cell collections, compatibility and value-compatibility are the same + if (t.is_multi_cell() || cprev.is_multi_cell()) { + return t.is_compatible_with(previous); } - return is_value_compatible_with_frozen(cprev); + return t.is_value_compatible_with_frozen(cprev); } bytes @@ -1837,6 +1814,9 @@ struct is_byte_order_equal_visitor { bool abstract_type::is_byte_order_equal() const { return visit(*this, is_byte_order_equal_visitor{}); } +static bool +check_compatibility(const tuple_type_impl &t, const abstract_type& previous, bool (abstract_type::*predicate)(const abstract_type&) const); + bool abstract_type::is_compatible_with(const abstract_type& previous) const { if (this == &previous) { return true; @@ -1884,7 +1864,7 @@ bool abstract_type::is_compatible_with(const abstract_type& previous) const { return false; } bool operator()(const tuple_type_impl& t) { - return t.check_compatibility(previous, &abstract_type::is_compatible_with); + return check_compatibility(t, previous, &abstract_type::is_compatible_with); } bool operator()(const collection_type_impl& t) { return is_compatible_with_aux(t, previous); } bool operator()(const abstract_type& t) { return false; } @@ -2757,10 +2737,12 @@ list_type_impl::is_compatible_with_frozen(const collection_type_impl& previous) } +static bool is_value_compatible_with_internal(const abstract_type& t, const abstract_type& other); + bool list_type_impl::is_value_compatible_with_frozen(const collection_type_impl& previous) const { auto& lp = dynamic_cast(previous); - return _elements->is_value_compatible_with_internal(*lp._elements); + return is_value_compatible_with_internal(*_elements, *lp._elements); } void list_type_impl::validate(bytes_view v, cql_serialization_format sf) const { @@ -3549,22 +3531,51 @@ bytes user_type_impl::from_json_object(const Json::Value& value, cql_serializati return build_value(std::move(raw_tuple)); } -bool -tuple_type_impl::is_value_compatible_with_internal(const abstract_type& previous) const { - return check_compatibility(previous, &abstract_type::is_value_compatible_with); -} - -bool -tuple_type_impl::check_compatibility(const abstract_type& previous, bool (abstract_type::*predicate)(const abstract_type&) const) const { +static bool +check_compatibility(const tuple_type_impl &t, const abstract_type& previous, bool (abstract_type::*predicate)(const abstract_type&) const) { auto* x = dynamic_cast(&previous); if (!x) { return false; } auto c = std::mismatch( - _types.begin(), _types.end(), - x->_types.begin(), x->_types.end(), + t.all_types().begin(), t.all_types().end(), + x->all_types().begin(), x->all_types().end(), [predicate] (data_type a, data_type b) { return ((*a).*predicate)(*b); }); - return c.second == x->_types.end(); // this allowed to be longer + return c.second == x->all_types().end(); // this allowed to be longer +} + +static bool is_date_long_or_timestamp(const abstract_type& t) { + auto k = t.get_kind(); + return k == abstract_type::kind::long_kind || k == abstract_type::kind::date || k == abstract_type::kind::timestamp; +} + +// Needed to handle ReversedType in value-compatibility checks. +static bool is_value_compatible_with_internal(const abstract_type& t, const abstract_type& other) { + struct visitor { + const abstract_type& other; + bool operator()(const abstract_type& t) { return t.is_compatible_with(other); } + bool operator()(const long_type_impl& t) { return is_date_long_or_timestamp(other); } + bool operator()(const date_type_impl& t) { return is_date_long_or_timestamp(other); } + bool operator()(const timestamp_type_impl& t) { return is_date_long_or_timestamp(other); } + bool operator()(const uuid_type_impl&) { + return other.get_kind() == abstract_type::kind::uuid || other.get_kind() == abstract_type::kind::timeuuid; + } + bool operator()(const varint_type_impl& t) { + return other == t || int32_type->is_value_compatible_with(other) || + long_type->is_value_compatible_with(other); + } + bool operator()(const tuple_type_impl& t) { + return check_compatibility(t, other, &abstract_type::is_value_compatible_with); + } + bool operator()(const collection_type_impl& t) { return is_value_compatible_with_internal_aux(t, other); } + bool operator()(const bytes_type_impl& t) { return true; } + bool operator()(const reversed_type_impl& t) { return t.underlying_type()->is_value_compatible_with(other); } + }; + return visit(t, visitor{other}); +} + +bool abstract_type::is_value_compatible_with(const abstract_type& other) const { + return is_value_compatible_with_internal(*this, *other.underlying_type()); } size_t diff --git a/types.hh b/types.hh index ac94e5e8d6..0540d59905 100644 --- a/types.hh +++ b/types.hh @@ -548,23 +548,13 @@ public: * * Note that a type should be compatible with at least itself. */ - bool is_value_compatible_with(const abstract_type& other) const { - return is_value_compatible_with_internal(*other.underlying_type()); - } + bool is_value_compatible_with(const abstract_type& other) const; bool references_user_type(const sstring& keyspace, const bytes& name) const; std::optional update_user_type(const shared_ptr updated) const; bool references_duration() const; std::optional value_length_if_fixed() const { return _value_length_if_fixed; } -protected: - /** - * Needed to handle ReversedType in value-compatibility checks. Subclasses should implement this instead of - * is_value_compatible_with(). - */ - virtual bool is_value_compatible_with_internal(const abstract_type& other) const { - return is_compatible_with(other); - } public: bytes decompose(const data_value& value) const { if (!value._value) { @@ -902,10 +892,6 @@ class reversed_type_impl : public abstract_type { t->value_length_if_fixed(), t->imr_state().type_info()) , _underlying_type(t) {} -protected: - virtual bool is_value_compatible_with_internal(const abstract_type& other) const { - return _underlying_type->is_value_compatible_with(*(other.underlying_type())); - } public: virtual void validate(bytes_view v, cql_serialization_format sf) const override { _underlying_type->validate(v, sf); diff --git a/types/collection.hh b/types/collection.hh index e74f73f96b..f0ed33e492 100644 --- a/types/collection.hh +++ b/types/collection.hh @@ -62,7 +62,6 @@ public: std::vector enforce_limit(std::vector, int version) const; virtual std::vector serialized_values(std::vector cells) const = 0; bytes serialize_for_native_protocol(std::vector cells, int version) const; - virtual bool is_value_compatible_with_internal(const abstract_type& other) const override; virtual bool is_compatible_with_frozen(const collection_type_impl& previous) const = 0; virtual bool is_value_compatible_with_frozen(const collection_type_impl& previous) const = 0; template diff --git a/types/tuple.hh b/types/tuple.hh index 1b7d5f851a..a0d1567aba 100644 --- a/types/tuple.hh +++ b/types/tuple.hh @@ -131,9 +131,7 @@ public: virtual bytes from_string(sstring_view s) const override; virtual sstring to_json_string(bytes_view bv) const override; virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const override; - virtual bool is_value_compatible_with_internal(const abstract_type& previous) const override; private: - bool check_compatibility(const abstract_type& previous, bool (abstract_type::*predicate)(const abstract_type&) const) const; static sstring make_name(const std::vector& types); friend abstract_type; };