/* * Copyright (C) 2015 Cloudius Systems, Ltd. */ #include #include "cql3/cql3_type.hh" #include "types.hh" #include "core/print.hh" template struct simple_type_traits { static T read_nonempty(bytes_view v) { return read_simple_exactly(v); } }; template<> struct simple_type_traits { static bool read_nonempty(bytes_view v) { return read_simple_exactly(v) != 0; } }; template<> struct simple_type_traits { static db_clock::time_point read_nonempty(bytes_view v) { return db_clock::time_point(db_clock::duration(read_simple_exactly(v))); } }; template struct simple_type_impl : abstract_type { simple_type_impl(sstring name) : abstract_type(std::move(name)) {} virtual int32_t compare(bytes_view v1, bytes_view v2) override { if (v1.empty()) { return v2.empty() ? 0 : -1; } if (v2.empty()) { return 1; } T a = simple_type_traits::read_nonempty(v1); T b = simple_type_traits::read_nonempty(v2); return a == b ? 0 : a < b ? -1 : 1; } virtual bool less(bytes_view v1, bytes_view v2) override { return compare(v1, v2) < 0; } virtual bool is_byte_order_equal() const override { return true; } virtual size_t hash(bytes_view v) override { return std::hash()(v); } }; struct int32_type_impl : simple_type_impl { int32_type_impl() : simple_type_impl("int32") {} virtual void serialize(const boost::any& value, std::ostream& out) override { auto v = boost::any_cast(value); auto u = net::hton(uint32_t(v)); out.write(reinterpret_cast(&u), sizeof(u)); } virtual object_opt deserialize(bytes_view v) override { return read_simple_opt(v); } int32_t compose_value(const bytes& b) { if (b.size() != 4) { throw marshal_exception(); } return (int32_t)net::ntoh(*reinterpret_cast(b.begin())); } bytes decompose_value(int32_t v) { bytes b(bytes::initialized_later(), sizeof(v)); *reinterpret_cast(b.begin()) = (int32_t)net::hton((uint32_t)v); return b; } int32_t parse_int(sstring_view s) { try { return boost::lexical_cast(s.begin(), s.size()); } catch (const boost::bad_lexical_cast& e) { throw marshal_exception(sprint("Invalid number format '%s'", s)); } } virtual bytes from_string(sstring_view s) override { return decompose_value(parse_int(s)); } virtual sstring to_string(const bytes& b) override { if (b.empty()) { return {}; } return to_sstring(compose_value(b)); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::int_; } }; struct long_type_impl : simple_type_impl { long_type_impl() : simple_type_impl("long") {} virtual void serialize(const boost::any& value, std::ostream& out) override { auto v = boost::any_cast(value); auto u = net::hton(uint64_t(v)); out.write(reinterpret_cast(&u), sizeof(u)); } virtual object_opt deserialize(bytes_view v) override { return read_simple_opt(v); } virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::bigint; } }; struct string_type_impl : public abstract_type { string_type_impl(sstring name, shared_ptr cql3_type) : abstract_type(name), _cql3_type(cql3_type) {} virtual void serialize(const boost::any& value, std::ostream& out) override { auto& v = boost::any_cast(value); out.write(v.c_str(), v.size()); } virtual object_opt deserialize(bytes_view v) override { // FIXME: validation? return boost::any(sstring(v.begin(), v.end())); } virtual bool less(bytes_view v1, bytes_view v2) override { return less_unsigned(v1, v2); } virtual bool is_byte_order_equal() const override { return true; } virtual bool is_byte_order_comparable() const override { return true; } virtual size_t hash(bytes_view v) override { return std::hash()(v); } virtual bytes from_string(sstring_view s) override { return to_bytes(s); } virtual sstring to_string(const bytes& b) override { return sstring(b); } virtual ::shared_ptr as_cql3_type() override { return _cql3_type; } shared_ptr _cql3_type; }; struct bytes_type_impl final : public abstract_type { bytes_type_impl() : abstract_type("bytes") {} virtual void serialize(const boost::any& value, std::ostream& out) override { auto& v = boost::any_cast(value); out.write(v.c_str(), v.size()); } virtual object_opt deserialize(bytes_view v) override { return boost::any(bytes(v.begin(), v.end())); } virtual bool less(bytes_view v1, bytes_view v2) override { return less_unsigned(v1, v2); } virtual bool is_byte_order_equal() const override { return true; } virtual bool is_byte_order_comparable() const override { return true; } virtual size_t hash(bytes_view v) override { return std::hash()(v); } virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::blob; } }; struct boolean_type_impl : public simple_type_impl { boolean_type_impl() : simple_type_impl("boolean") {} virtual void serialize(const boost::any& value, std::ostream& out) override { auto v = boost::any_cast(value); char c = v; out.put(c); } virtual object_opt deserialize(bytes_view v) override { if (v.empty()) { return {}; } if (v.size() != 1) { throw marshal_exception(); } return boost::any(*v.begin() != 0); } virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::boolean; } }; struct date_type_impl : public abstract_type { date_type_impl() : abstract_type("date") {} virtual void serialize(const boost::any& value, std::ostream& out) override { auto v = boost::any_cast(value); int64_t i = v.time_since_epoch().count(); i = net::hton(uint64_t(i)); out.write(reinterpret_cast(&i), 8); } virtual object_opt deserialize(bytes_view v) override { if (v.empty()) { return {}; } auto tmp = read_simple_exactly(v); return boost::any(db_clock::time_point(db_clock::duration(tmp))); } virtual bool less(bytes_view b1, bytes_view b2) override { return compare_unsigned(b1, b2); } virtual bool is_byte_order_comparable() const override { return true; } virtual size_t hash(bytes_view v) override { return std::hash()(v); } virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::timestamp; } }; struct timeuuid_type_impl : public abstract_type { timeuuid_type_impl() : abstract_type("timeuuid") {} virtual void serialize(const boost::any& value, std::ostream& out) override { // FIXME: optimize auto& uuid = boost::any_cast(value); out.write(to_bytes(uuid).begin(), 16); } virtual object_opt deserialize(bytes_view v) override { uint64_t msb, lsb; if (v.empty()) { return {}; } msb = read_simple(v); lsb = read_simple(v); if (!v.empty()) { throw marshal_exception(); } return boost::any(utils::UUID(msb, lsb)); } virtual bool less(bytes_view b1, bytes_view b2) override { if (b1.empty()) { return b2.empty() ? false : true; } if (b2.empty()) { return false; } auto r = compare_bytes(b1, b2); if (r != 0) { return r < 0; } else { return std::lexicographical_compare(b1.begin(), b1.end(), b2.begin(), b2.end()); } } virtual bool is_byte_order_equal() const override { return true; } virtual size_t hash(bytes_view v) override { return std::hash()(v); } virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::timeuuid; } private: static int compare_bytes(bytes_view o1, bytes_view o2) { auto compare_pos = [&] (unsigned pos, int mask, int ifequal) { int d = (o1[pos] & mask) - (o2[pos] & mask); return d ? d : ifequal; }; return compare_pos(6, 0xf, compare_pos(7, 0xff, compare_pos(4, 0xff, compare_pos(5, 0xff, compare_pos(0, 0xff, compare_pos(1, 0xff, compare_pos(2, 0xff, compare_pos(3, 0xff, 0)))))))); } friend class uuid_type_impl; }; struct timestamp_type_impl : simple_type_impl { timestamp_type_impl() : simple_type_impl("timestamp") {} virtual void serialize(const boost::any& value, std::ostream& out) override { uint64_t v = boost::any_cast(value).time_since_epoch().count(); v = net::hton(v); out.write(reinterpret_cast(&v), 8); } virtual object_opt deserialize(bytes_view in) override { if (in.empty()) { return {}; } auto v = read_simple_exactly(in); return boost::any(db_clock::time_point(db_clock::duration(v))); } // FIXME: isCompatibleWith(timestampuuid) virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::timestamp; } }; struct uuid_type_impl : abstract_type { uuid_type_impl() : abstract_type("uuid") {} virtual void serialize(const boost::any& value, std::ostream& out) override { // FIXME: optimize auto& uuid = boost::any_cast(value); out.write(to_bytes(uuid).begin(), 16); } virtual object_opt deserialize(bytes_view v) override { if (v.empty()) { return {}; } auto msb = read_simple(v); auto lsb = read_simple(v); if (!v.empty()) { throw marshal_exception(); } return boost::any(utils::UUID(msb, lsb)); } virtual bool less(bytes_view b1, bytes_view b2) override { if (b1.size() < 16) { return b2.size() < 16 ? false : true; } if (b2.size() < 16) { return false; } auto v1 = (b1[6] >> 4) & 0x0f; auto v2 = (b2[6] >> 4) & 0x0f; if (v1 != v2) { return v1 < v2; } if (v1 == 1) { auto c1 = timeuuid_type_impl::compare_bytes(b1, b2); auto c2 = timeuuid_type_impl::compare_bytes(b2, b1); // Require strict ordering if (c1 != c2) { return c1; } } return less_unsigned(b1, b2); } // FIXME: isCompatibleWith(uuid) virtual bool is_byte_order_equal() const override { return true; } virtual size_t hash(bytes_view v) override { return std::hash()(v); } virtual bytes from_string(sstring_view s) override { throw std::runtime_error("not implemented"); } virtual sstring to_string(const bytes& b) override { throw std::runtime_error("not implemented"); } virtual ::shared_ptr as_cql3_type() override { return cql3::native_cql3_type::uuid; } }; std::ostream& operator<<(std::ostream& os, const bytes& b) { return os << to_hex(b); } thread_local shared_ptr int32_type(make_shared()); thread_local shared_ptr long_type(make_shared()); thread_local shared_ptr ascii_type(make_shared("ascii", cql3::native_cql3_type::ascii)); thread_local shared_ptr bytes_type(make_shared()); thread_local shared_ptr utf8_type(make_shared("utf8", cql3::native_cql3_type::text)); thread_local shared_ptr boolean_type(make_shared()); thread_local shared_ptr date_type(make_shared()); thread_local shared_ptr timeuuid_type(make_shared()); thread_local shared_ptr timestamp_type(make_shared()); thread_local shared_ptr uuid_type(make_shared());