mirror of
https://github.com/scylladb/scylladb.git
synced 2026-06-01 12:36:56 +00:00
types: empty value support for non-container types
Origin supports (https://issues.apache.org/jira/browse/CASSANDRA-5648) "empty" values even for non-container types such as int. Use maybe_empty<> to encapsulate abstract_type::native_type, adding an empty flag if needed.
This commit is contained in:
116
types.cc
116
types.cc
@@ -110,7 +110,11 @@ struct integer_type_impl : simple_type_impl<T> {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
auto v = this->from_value(value);
|
||||
auto v1 = this->from_value(value);
|
||||
if (v1.empty()) {
|
||||
return;
|
||||
}
|
||||
auto v = v1.get();
|
||||
auto u = net::hton(v);
|
||||
out = std::copy_n(reinterpret_cast<const char*>(&u), sizeof(u), out);
|
||||
}
|
||||
@@ -119,7 +123,10 @@ struct integer_type_impl : simple_type_impl<T> {
|
||||
return 0;
|
||||
}
|
||||
auto v = this->from_value(value);
|
||||
return sizeof(v);
|
||||
if (v.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return sizeof(v.get());
|
||||
}
|
||||
virtual data_value deserialize(bytes_view v) const override {
|
||||
auto x = read_simple_opt<T>(v);
|
||||
@@ -206,7 +213,7 @@ struct string_type_impl : public concrete_type<sstring> {
|
||||
return make_null();
|
||||
}
|
||||
// FIXME: validation?
|
||||
return make_value(std::make_unique<sstring>(reinterpret_cast<const char*>(v.begin()), v.size()));
|
||||
return make_value(std::make_unique<native_type>(reinterpret_cast<const char*>(v.begin()), v.size()));
|
||||
}
|
||||
virtual bool less(bytes_view v1, bytes_view v2) const override {
|
||||
return less_unsigned(v1, v2);
|
||||
@@ -277,7 +284,7 @@ struct bytes_type_impl final : public concrete_type<bytes> {
|
||||
if (v.empty()) {
|
||||
return make_null();
|
||||
}
|
||||
return make_value(std::make_unique<bytes>(v.begin(), v.end()));
|
||||
return make_value(std::make_unique<native_type>(v.begin(), v.end()));
|
||||
}
|
||||
virtual bool less(bytes_view v1, bytes_view v2) const override {
|
||||
return less_unsigned(v1, v2);
|
||||
@@ -307,8 +314,10 @@ struct bytes_type_impl final : public concrete_type<bytes> {
|
||||
|
||||
struct boolean_type_impl : public simple_type_impl<bool> {
|
||||
boolean_type_impl() : simple_type_impl<bool>(boolean_type_name) {}
|
||||
void serialize_value(bool value, bytes::iterator& out) const {
|
||||
*out++ = char(value);
|
||||
void serialize_value(maybe_empty<bool> value, bytes::iterator& out) const {
|
||||
if (!value.empty()) {
|
||||
*out++ = char(value);
|
||||
}
|
||||
}
|
||||
virtual void serialize(const void* value, bytes::iterator& out) const override {
|
||||
if (!value) {
|
||||
@@ -320,6 +329,9 @@ struct boolean_type_impl : public simple_type_impl<bool> {
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
if (from_value(value).empty()) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
size_t serialized_size(bool value) const {
|
||||
@@ -371,12 +383,15 @@ struct date_type_impl : public concrete_type<db_clock::time_point> {
|
||||
return;
|
||||
}
|
||||
auto& v = from_value(value);
|
||||
int64_t i = v.time_since_epoch().count();
|
||||
if (v.empty()) {
|
||||
return;
|
||||
}
|
||||
int64_t i = v.get().time_since_epoch().count();
|
||||
i = net::hton(uint64_t(i));
|
||||
out = std::copy_n(reinterpret_cast<const char*>(&i), sizeof(i), out);
|
||||
}
|
||||
virtual size_t serialized_size(const void* value) const override {
|
||||
if (!value) {
|
||||
if (!value || from_value(value).empty()) {
|
||||
return 0;
|
||||
}
|
||||
return 8;
|
||||
@@ -415,11 +430,15 @@ struct timeuuid_type_impl : public concrete_type<utils::UUID> {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
auto& uuid = from_value(value);
|
||||
auto& uuid1 = from_value(value);
|
||||
if (uuid1.empty()) {
|
||||
return;
|
||||
}
|
||||
auto uuid = uuid1.get();
|
||||
out = std::copy_n(uuid.to_bytes().begin(), sizeof(uuid), out);
|
||||
}
|
||||
virtual size_t serialized_size(const void* value) const override {
|
||||
if (!value) {
|
||||
if (!value || from_value(value).empty()) {
|
||||
return 0;
|
||||
}
|
||||
return 16;
|
||||
@@ -489,7 +508,7 @@ struct timeuuid_type_impl : public concrete_type<utils::UUID> {
|
||||
if (v.is_null()) {
|
||||
return "";
|
||||
}
|
||||
return from_value(v).to_sstring();
|
||||
return from_value(v).get().to_sstring();
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const override {
|
||||
return cql3::cql3_type::timeuuid;
|
||||
@@ -518,12 +537,16 @@ struct timestamp_type_impl : simple_type_impl<db_clock::time_point> {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
uint64_t v = from_value(value).time_since_epoch().count();
|
||||
auto&& v1 = from_value(value);
|
||||
if (v1.empty()) {
|
||||
return;
|
||||
}
|
||||
uint64_t v = v1.get().time_since_epoch().count();
|
||||
v = net::hton(v);
|
||||
out = std::copy_n(reinterpret_cast<const char*>(&v), sizeof(v), out);
|
||||
}
|
||||
virtual size_t serialized_size(const void* value) const override {
|
||||
if (!value) {
|
||||
if (!value || from_value(value).empty()) {
|
||||
return 0;
|
||||
}
|
||||
return 8;
|
||||
@@ -644,7 +667,7 @@ struct uuid_type_impl : concrete_type<utils::UUID> {
|
||||
return;
|
||||
}
|
||||
auto& uuid = from_value(value);
|
||||
out = std::copy_n(uuid.to_bytes().begin(), sizeof(uuid), out);
|
||||
out = std::copy_n(uuid.get().to_bytes().begin(), sizeof(uuid.get()), out);
|
||||
}
|
||||
virtual size_t serialized_size(const void* value) const override {
|
||||
if (!value) {
|
||||
@@ -715,7 +738,7 @@ struct uuid_type_impl : concrete_type<utils::UUID> {
|
||||
if (v.is_null()) {
|
||||
return "";
|
||||
}
|
||||
return from_value(v).to_sstring();
|
||||
return from_value(v).get().to_sstring();
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const override {
|
||||
return cql3::cql3_type::uuid;
|
||||
@@ -732,12 +755,16 @@ struct inet_addr_type_impl : concrete_type<net::ipv4_address> {
|
||||
return;
|
||||
}
|
||||
// FIXME: support ipv6
|
||||
auto& ipv4 = from_value(value);
|
||||
auto& ipv4e = from_value(value);
|
||||
if (ipv4e.empty()) {
|
||||
return;
|
||||
}
|
||||
auto& ipv4 = ipv4e.get();
|
||||
uint32_t u = htonl(ipv4.ip);
|
||||
out = std::copy_n(reinterpret_cast<const char*>(&u), sizeof(u), out);
|
||||
}
|
||||
virtual size_t serialized_size(const void* value) const override {
|
||||
if (!value) {
|
||||
if (!value || from_value(value).empty()) {
|
||||
return 0;
|
||||
}
|
||||
return 4;
|
||||
@@ -777,7 +804,7 @@ struct inet_addr_type_impl : concrete_type<net::ipv4_address> {
|
||||
if (s.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
net::ipv4_address ipv4;
|
||||
native_type ipv4;
|
||||
try {
|
||||
ipv4 = net::ipv4_address(s.data());
|
||||
} catch (...) {
|
||||
@@ -793,7 +820,7 @@ struct inet_addr_type_impl : concrete_type<net::ipv4_address> {
|
||||
if (v.is_null()) {
|
||||
return "";
|
||||
}
|
||||
boost::asio::ip::address_v4 ipv4(from_value(v).ip);
|
||||
boost::asio::ip::address_v4 ipv4(from_value(v).get().ip);
|
||||
return ipv4.to_string();
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const override {
|
||||
@@ -950,7 +977,11 @@ public:
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
auto& num = from_value(value);
|
||||
auto& num1 = from_value(value);
|
||||
if (num1.empty()) {
|
||||
return;
|
||||
}
|
||||
auto& num = std::move(num1).get();
|
||||
boost::multiprecision::cpp_int pnum = boost::multiprecision::abs(num);
|
||||
|
||||
std::vector<uint8_t> b;
|
||||
@@ -973,7 +1004,11 @@ public:
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
auto& num = from_value(value);
|
||||
auto& num1 = from_value(value);
|
||||
if (num1.empty()) {
|
||||
return 0;
|
||||
}
|
||||
auto&& num = num1.get();
|
||||
if (!num) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1020,7 +1055,7 @@ public:
|
||||
if (v.is_null()) {
|
||||
return "";
|
||||
}
|
||||
return from_value(v).str();
|
||||
return from_value(v).get().str();
|
||||
}
|
||||
virtual bytes from_string(sstring_view text) const override {
|
||||
if (text.empty()) {
|
||||
@@ -1028,7 +1063,7 @@ public:
|
||||
}
|
||||
try {
|
||||
std::string str(text.begin(), text.end());
|
||||
boost::multiprecision::cpp_int num(str);
|
||||
native_type num(str);
|
||||
bytes b(bytes::initialized_later(), serialized_size(&num));
|
||||
auto out = b.begin();
|
||||
serialize(&num, out);
|
||||
@@ -1050,18 +1085,26 @@ public:
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
auto bd = from_value(value);
|
||||
auto bd1 = from_value(value);
|
||||
if (bd1.empty()) {
|
||||
return;
|
||||
}
|
||||
auto&& bd = std::move(bd1).get();
|
||||
auto u = net::hton(bd.scale());
|
||||
out = std::copy_n(reinterpret_cast<const char*>(&u), sizeof(int32_t), out);
|
||||
auto&& unscaled_value = bd.unscaled_value();
|
||||
varint_type_impl::native_type unscaled_value = bd.unscaled_value();
|
||||
varint_type->serialize(&unscaled_value, out);
|
||||
}
|
||||
virtual size_t serialized_size(const void* value) const override {
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
auto& bd = from_value(value);
|
||||
auto&& unscaled_value = bd.unscaled_value();
|
||||
auto& bd1 = from_value(value);
|
||||
if (bd1.empty()) {
|
||||
return 0;
|
||||
}
|
||||
auto&& bd = std::move(bd1).get();
|
||||
varint_type_impl::native_type unscaled_value = bd.unscaled_value();
|
||||
return sizeof(int32_t) + varint_type->serialized_size(&unscaled_value);
|
||||
}
|
||||
virtual int32_t compare(bytes_view v1, bytes_view v2) const override {
|
||||
@@ -1074,7 +1117,16 @@ public:
|
||||
auto a = from_value(deserialize(v1));
|
||||
auto b = from_value(deserialize(v2));
|
||||
|
||||
return a.compare(b);
|
||||
if (a.empty() && b.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (a.empty() && !b.empty()) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.empty() && b.empty()) {
|
||||
return 1;
|
||||
}
|
||||
return a.get().compare(b.get());
|
||||
}
|
||||
virtual bool less(bytes_view v1, bytes_view v2) const override {
|
||||
return compare(v1, v2) < 0;
|
||||
@@ -1088,23 +1140,23 @@ public:
|
||||
return make_null();
|
||||
}
|
||||
auto scale = read_simple<int32_t>(v);
|
||||
auto unscaled = varint_type->deserialize(v);
|
||||
data_value unscaled = varint_type->deserialize(v);
|
||||
auto real_varint_type = static_cast<const varint_type_impl*>(varint_type.get()); // yuck
|
||||
return make_value(big_decimal(scale, real_varint_type->from_value(unscaled)));
|
||||
return make_value(big_decimal(scale, real_varint_type->from_value(unscaled).get()));
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) const override {
|
||||
auto v = deserialize(b);
|
||||
if (v.is_null()) {
|
||||
return "";
|
||||
}
|
||||
return from_value(v).to_string();
|
||||
return from_value(v).get().to_string();
|
||||
}
|
||||
virtual bytes from_string(sstring_view text) const override {
|
||||
if (text.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
try {
|
||||
big_decimal bd(text);
|
||||
native_type bd(text);
|
||||
bytes b(bytes::initialized_later(), serialized_size(&bd));
|
||||
auto out = b.begin();
|
||||
serialize(&bd, out);
|
||||
|
||||
34
types.hh
34
types.hh
@@ -344,10 +344,10 @@ public:
|
||||
friend class empty_type_impl;
|
||||
template <typename T> friend const T& value_cast(const data_value&);
|
||||
template <typename T> friend T&& value_cast(data_value&&);
|
||||
friend data_value make_tuple_value(data_type, std::vector<data_value>);
|
||||
friend data_value make_set_value(data_type, std::vector<data_value>);
|
||||
friend data_value make_list_value(data_type, std::vector<data_value>);
|
||||
friend data_value make_map_value(data_type, std::vector<std::pair<data_value, data_value>>);
|
||||
friend data_value make_tuple_value(data_type, maybe_empty<std::vector<data_value>>);
|
||||
friend data_value make_set_value(data_type, maybe_empty<std::vector<data_value>>);
|
||||
friend data_value make_list_value(data_type, maybe_empty<std::vector<data_value>>);
|
||||
friend data_value make_map_value(data_type, maybe_empty<std::vector<std::pair<data_value, data_value>>>);
|
||||
friend data_value make_user_value(data_type, std::vector<data_value>);
|
||||
};
|
||||
|
||||
@@ -509,31 +509,33 @@ data_value::serialize(bytes::iterator& out) const {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline
|
||||
data_value
|
||||
data_value::make_new(data_type type, T&& value) {
|
||||
data_value::make_new(data_type type, T&& v) {
|
||||
maybe_empty<std::remove_reference_t<T>> value(std::forward<T>(v));
|
||||
return data_value(type->native_value_clone(&value), type);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& value_cast(const data_value& value) {
|
||||
if (typeid(T) != value.type()->native_typeid()) {
|
||||
if (typeid(maybe_empty<T>) != value.type()->native_typeid()) {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
if (value.is_null()) {
|
||||
throw std::runtime_error("value is null");
|
||||
}
|
||||
return *reinterpret_cast<T*>(value._value);
|
||||
return *reinterpret_cast<maybe_empty<T>*>(value._value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T&& value_cast(data_value&& value) {
|
||||
if (typeid(T) != value.type()->native_typeid()) {
|
||||
if (typeid(maybe_empty<T>) != value.type()->native_typeid()) {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
if (value.is_null()) {
|
||||
throw std::runtime_error("value is null");
|
||||
}
|
||||
return std::move(*reinterpret_cast<T*>(value._value));
|
||||
return std::move(*reinterpret_cast<maybe_empty<T>*>(value._value));
|
||||
}
|
||||
|
||||
// CRTP: implements translation between a native_type (C++ type) to abstract_type
|
||||
@@ -543,7 +545,7 @@ T&& value_cast(data_value&& value) {
|
||||
template <typename NativeType, typename AbstractType = abstract_type>
|
||||
class concrete_type : public AbstractType {
|
||||
public:
|
||||
using native_type = NativeType;
|
||||
using native_type = maybe_empty<NativeType>;
|
||||
using AbstractType::AbstractType;
|
||||
protected:
|
||||
virtual size_t native_value_size() const override {
|
||||
@@ -571,19 +573,19 @@ protected:
|
||||
return typeid(native_type);
|
||||
}
|
||||
protected:
|
||||
data_value make_value(std::unique_ptr<NativeType> value) const {
|
||||
data_value make_value(std::unique_ptr<native_type> value) const {
|
||||
return data_value::make(this->shared_from_this(), std::move(value));
|
||||
}
|
||||
data_value make_value(NativeType value) const {
|
||||
return make_value(std::make_unique<NativeType>(std::move(value)));
|
||||
data_value make_value(native_type value) const {
|
||||
return make_value(std::make_unique<native_type>(std::move(value)));
|
||||
}
|
||||
data_value make_null() const {
|
||||
return data_value::make_null(this->shared_from_this());
|
||||
}
|
||||
const NativeType& from_value(const void* v) const {
|
||||
return *reinterpret_cast<const NativeType*>(v);
|
||||
const native_type& from_value(const void* v) const {
|
||||
return *reinterpret_cast<const native_type*>(v);
|
||||
}
|
||||
const NativeType& from_value(const data_value& v) const {
|
||||
const native_type& from_value(const data_value& v) const {
|
||||
return this->from_value(AbstractType::get_value_ptr(v));
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user