Merge branch 'dev/pdziepak/types-from-string/v2'
This commit is contained in:
@@ -353,7 +353,7 @@ boost_test_lib = [
|
||||
]
|
||||
|
||||
defines = []
|
||||
libs = '-laio -lboost_program_options -lboost_system -lboost_filesystem -lstdc++ -lm -lboost_unit_test_framework -lboost_thread -lcryptopp -lrt -lyaml-cpp'
|
||||
libs = '-laio -lboost_program_options -lboost_system -lboost_filesystem -lstdc++ -lm -lboost_unit_test_framework -lboost_thread -lcryptopp -lrt -lyaml-cpp -lboost_date_time'
|
||||
hwloc_libs = '-lhwloc -lnuma -lpciaccess -lxml2 -lz'
|
||||
urchin_libs = '-llz4 -lsnappy -lz'
|
||||
|
||||
|
||||
@@ -1327,9 +1327,7 @@ native_type returns [shared_ptr<cql3_type> t]
|
||||
#endif
|
||||
| K_DOUBLE { $t = cql3_type::double_; }
|
||||
| K_FLOAT { $t = cql3_type::float_; }
|
||||
#if 0
|
||||
| K_INET { $t = CQL3Type.Native.INET;}
|
||||
#endif
|
||||
| K_INET { $t = cql3_type::inet; }
|
||||
| K_INT { $t = cql3_type::int_; }
|
||||
| K_TEXT { $t = cql3_type::text; }
|
||||
| K_TIMESTAMP { $t = cql3_type::timestamp; }
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
|
||||
try {
|
||||
data_type_for<int64_t>()->validate(*tval);
|
||||
} catch (exceptions::marshal_exception e) {
|
||||
} catch (marshal_exception e) {
|
||||
throw exceptions::invalid_request_exception("Invalid timestamp value");
|
||||
}
|
||||
return boost::any_cast<int64_t>(data_type_for<int64_t>()->deserialize(*tval));
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
try {
|
||||
data_type_for<int32_t>()->validate(*tval);
|
||||
}
|
||||
catch (exceptions::marshal_exception e) {
|
||||
catch (marshal_exception e) {
|
||||
throw exceptions::invalid_request_exception("Invalid TTL value");
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ constants::literal::parsed_value(data_type validator)
|
||||
return long_type->from_string(_text);
|
||||
}
|
||||
return validator->from_string(_text);
|
||||
} catch (const exceptions::marshal_exception& e) {
|
||||
} catch (const marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
_receiver->type->validate(value.value());
|
||||
}
|
||||
return value;
|
||||
} catch (const exceptions::marshal_exception& e) {
|
||||
} catch (const marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,27 +32,6 @@
|
||||
|
||||
namespace exceptions {
|
||||
|
||||
class invalid_request_exception : public std::logic_error {
|
||||
public:
|
||||
invalid_request_exception(std::string cause)
|
||||
: logic_error(cause)
|
||||
{ }
|
||||
};
|
||||
|
||||
class keyspace_not_defined_exception : public invalid_request_exception {
|
||||
public:
|
||||
keyspace_not_defined_exception(std::string cause)
|
||||
: invalid_request_exception(cause)
|
||||
{ }
|
||||
};
|
||||
|
||||
class marshal_exception : public std::logic_error {
|
||||
public:
|
||||
marshal_exception(std::string cause)
|
||||
: logic_error(cause)
|
||||
{ }
|
||||
};
|
||||
|
||||
enum class exception_code : int32_t {
|
||||
SERVER_ERROR = 0x0000,
|
||||
PROTOCOL_ERROR = 0x000A,
|
||||
@@ -101,6 +80,20 @@ public:
|
||||
using cassandra_exception::cassandra_exception;
|
||||
};
|
||||
|
||||
class invalid_request_exception : public request_validation_exception {
|
||||
public:
|
||||
invalid_request_exception(sstring cause)
|
||||
: request_validation_exception(exception_code::INVALID, cause)
|
||||
{ }
|
||||
};
|
||||
|
||||
class keyspace_not_defined_exception : public invalid_request_exception {
|
||||
public:
|
||||
keyspace_not_defined_exception(std::string cause)
|
||||
: invalid_request_exception(cause)
|
||||
{ }
|
||||
};
|
||||
|
||||
class prepared_query_not_found_exception : public request_validation_exception {
|
||||
public:
|
||||
prepared_query_not_found_exception(bytes id)
|
||||
|
||||
@@ -998,3 +998,67 @@ SEASTAR_TEST_CASE(test_ttl) {
|
||||
});
|
||||
}
|
||||
|
||||
SEASTAR_TEST_CASE(test_types) {
|
||||
return do_with_cql_env([] (cql_test_env& e) {
|
||||
return make_ready_future<>().then([&e] {
|
||||
return e.execute_cql(
|
||||
"CREATE TABLE all_types ("
|
||||
" a ascii PRIMARY KEY,"
|
||||
" b bigint,"
|
||||
" c blob,"
|
||||
" d boolean,"
|
||||
" e double,"
|
||||
" f float,"
|
||||
" g inet,"
|
||||
" h int,"
|
||||
" i text,"
|
||||
" j timestamp,"
|
||||
" k timeuuid,"
|
||||
" l uuid,"
|
||||
" m varchar,"
|
||||
");").discard_result();
|
||||
}).then([&e] {
|
||||
e.require_table_exists("ks", "all_types");
|
||||
return e.execute_cql(
|
||||
"INSERT INTO all_types (a, b, c, d, e, f, g, h, i, j, k, l, m) VALUES ("
|
||||
" 'ascii',"
|
||||
" 123456789,"
|
||||
" 0xdeadbeef,"
|
||||
" true,"
|
||||
" 3.14,"
|
||||
" 3.14,"
|
||||
" '127.0.0.1',"
|
||||
" 3,"
|
||||
" 'zażółć gęślą jaźń',"
|
||||
" '2001-10-18 14:15:55.134+0000',"
|
||||
" d2177dd0-eaa2-11de-a572-001b779c76e3,"
|
||||
" d2177dd0-eaa2-11de-a572-001b779c76e3,"
|
||||
" 'varchar'"
|
||||
");").discard_result();
|
||||
}).then([&e] {
|
||||
return e.execute_cql("SELECT * FROM all_types WHERE a = 'ascii'");
|
||||
}).then([&e] (auto msg) {
|
||||
struct tm t = { 0 };
|
||||
t.tm_year = 2001 - 1900;
|
||||
t.tm_mon = 10 - 1;
|
||||
t.tm_mday = 18;
|
||||
t.tm_hour = 14;
|
||||
t.tm_min = 15;
|
||||
t.tm_sec = 55;
|
||||
auto tp = db_clock::from_time_t(timegm(&t)) + std::chrono::milliseconds(134);
|
||||
assert_that(msg).is_rows().with_rows({
|
||||
{
|
||||
ascii_type->decompose(sstring("ascii")), long_type->decompose(123456789l),
|
||||
from_hex("deadbeef"), boolean_type->decompose(true),
|
||||
double_type->decompose(3.14), float_type->decompose(3.14f),
|
||||
inet_addr_type->decompose(net::ipv4_address("127.0.0.1")),
|
||||
int32_type->decompose(3), utf8_type->decompose(sstring("zażółć gęślą jaźń")),
|
||||
timestamp_type->decompose(tp),
|
||||
timeuuid_type->decompose(utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"))),
|
||||
uuid_type->decompose(utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"))),
|
||||
utf8_type->decompose(sstring("varchar"))
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,9 +6,24 @@
|
||||
#define BOOST_TEST_MODULE core
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <utils/UUID_gen.hh>
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
#include <net/ip.hh>
|
||||
#include "types.hh"
|
||||
#include "compound.hh"
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
void test_parsing_fails(const shared_ptr<const abstract_type>& type, sstring str)
|
||||
{
|
||||
try {
|
||||
type->from_string(str);
|
||||
BOOST_FAIL(sprint("Parsing of '%s' should have failed", str));
|
||||
} catch (const marshal_exception& e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_bytes_type_string_conversions) {
|
||||
BOOST_REQUIRE(bytes_type->equal(bytes_type->from_string("616263646566"), bytes_type->decompose(bytes{"abcdef"})));
|
||||
}
|
||||
@@ -35,23 +50,104 @@ BOOST_AUTO_TEST_CASE(test_int32_type_string_conversions) {
|
||||
BOOST_REQUIRE(int32_type->equal(int32_type->from_string("2147483647"), int32_type->decompose((int32_t)2147483647)));
|
||||
BOOST_REQUIRE_EQUAL(int32_type->to_string(int32_type->decompose((int32_t)-2147483647)), "-2147483647");
|
||||
|
||||
auto test_parsing_fails = [] (sstring text) {
|
||||
try {
|
||||
int32_type->from_string(text);
|
||||
BOOST_FAIL(sprint("Parsing of '%s' should have failed", text));
|
||||
} catch (const marshal_exception& e) {
|
||||
// expected
|
||||
}
|
||||
};
|
||||
|
||||
test_parsing_fails("asd");
|
||||
test_parsing_fails("-2147483649");
|
||||
test_parsing_fails("2147483648");
|
||||
test_parsing_fails("2147483648123");
|
||||
test_parsing_fails(int32_type, "asd");
|
||||
test_parsing_fails(int32_type, "-2147483649");
|
||||
test_parsing_fails(int32_type, "2147483648");
|
||||
test_parsing_fails(int32_type, "2147483648123");
|
||||
|
||||
BOOST_REQUIRE_EQUAL(int32_type->to_string(bytes()), "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_timeuuid_type_string_conversions) {
|
||||
auto now = utils::UUID_gen::get_time_UUID();
|
||||
BOOST_REQUIRE(timeuuid_type->equal(timeuuid_type->from_string(now.to_sstring()), timeuuid_type->decompose(now)));
|
||||
auto uuid = utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"));
|
||||
BOOST_REQUIRE(timeuuid_type->equal(timeuuid_type->from_string("D2177dD0-EAa2-11de-a572-001B779C76e3"), timeuuid_type->decompose(uuid)));
|
||||
|
||||
test_parsing_fails(timeuuid_type, "something");
|
||||
test_parsing_fails(timeuuid_type, "D2177dD0-EAa2-11de-a572-001B779C76e3a");
|
||||
test_parsing_fails(timeuuid_type, "D2177dD0-EAa2-11de-a572001-B779C76e3");
|
||||
test_parsing_fails(timeuuid_type, "D2177dD0EAa211dea572001B779C76e3");
|
||||
test_parsing_fails(timeuuid_type, utils::make_random_uuid().to_sstring());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_uuid_type_string_conversions) {
|
||||
auto now = utils::UUID_gen::get_time_UUID();
|
||||
BOOST_REQUIRE(uuid_type->equal(uuid_type->from_string(now.to_sstring()), uuid_type->decompose(now)));
|
||||
auto random = utils::make_random_uuid();
|
||||
BOOST_REQUIRE(uuid_type->equal(uuid_type->from_string(random.to_sstring()), uuid_type->decompose(random)));
|
||||
auto uuid = utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"));
|
||||
BOOST_REQUIRE(uuid_type->equal(uuid_type->from_string("D2177dD0-EAa2-11de-a572-001B779C76e3"), uuid_type->decompose(uuid)));
|
||||
|
||||
test_parsing_fails(uuid_type, "something");
|
||||
test_parsing_fails(uuid_type, "D2177dD0-EAa2-11de-a572-001B779C76e3a");
|
||||
test_parsing_fails(uuid_type, "D2177dD0-EAa2-11de-a572001-B779C76e3");
|
||||
test_parsing_fails(uuid_type, "D2177dD0EAa211dea572001B779C76e3");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_inet_type_string_conversions) {
|
||||
net::ipv4_address addr("127.0.0.1");
|
||||
BOOST_REQUIRE(inet_addr_type->equal(inet_addr_type->from_string("127.0.0.1"), inet_addr_type->decompose(addr)));
|
||||
|
||||
test_parsing_fails(inet_addr_type, "something");
|
||||
test_parsing_fails(inet_addr_type, "300.127.127.127");
|
||||
test_parsing_fails(inet_addr_type, "127-127.127.127");
|
||||
test_parsing_fails(inet_addr_type, "127.127.127.127.127");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_timestamp_type_string_conversions) {
|
||||
timestamp_type->from_string("now");
|
||||
db_clock::time_point tp(db_clock::duration(1435881600000));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("1435881600000"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03+0000"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03-00"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03 00:00+0000"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03 01:00:00+0000"), timestamp_type->decompose(tp + 1h)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03 01:02:03.123+0000"), timestamp_type->decompose(tp + 123ms + 1h + 2min + 3s)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03 12:30:00+1230"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03 12:00:00+12"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03 12:30:00+12:30"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-02 23:00-0100"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03T00:00+0000"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03T01:00:00+0000"), timestamp_type->decompose(tp + 1h)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03T00:00:00.123+0000"), timestamp_type->decompose(tp + 123ms)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-03T12:30:00+1230"), timestamp_type->decompose(tp)));
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string("2015-07-02T23:00-0100"), timestamp_type->decompose(tp)));
|
||||
|
||||
auto now = time(nullptr);
|
||||
auto local_now = *localtime(&now);
|
||||
char buf[100];
|
||||
db_clock::time_point now_tp(db_clock::duration(now * 1000));
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S%z", &local_now);
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string(buf), timestamp_type->decompose(now_tp)));
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &local_now);
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string(buf), timestamp_type->decompose(now_tp)));
|
||||
|
||||
struct tm dst = { 0 };
|
||||
dst.tm_isdst = -1;
|
||||
dst.tm_year = 2015 - 1900;
|
||||
dst.tm_mon = 1 - 1;
|
||||
dst.tm_mday = 2;
|
||||
dst.tm_hour = 3;
|
||||
dst.tm_min = 4;
|
||||
dst.tm_sec = 5;
|
||||
auto dst_jan = db_clock::from_time_t(mktime(&dst));
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &dst);
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string(buf), timestamp_type->decompose(dst_jan)));
|
||||
|
||||
dst.tm_isdst = -1;
|
||||
dst.tm_mon = 6 - 1;
|
||||
auto dst_jun = db_clock::from_time_t(mktime(&dst));
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &dst);
|
||||
BOOST_REQUIRE(timestamp_type->equal(timestamp_type->from_string(buf), timestamp_type->decompose(dst_jun)));
|
||||
|
||||
test_parsing_fails(timestamp_type, "something");
|
||||
test_parsing_fails(timestamp_type, "2001-99-01");
|
||||
test_parsing_fails(timestamp_type, "2001-01-01 12:00:00.0a");
|
||||
test_parsing_fails(timestamp_type, "2001-01-01 12:00p0000");
|
||||
test_parsing_fails(timestamp_type, "2001-01-01 12:00+1200a");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_boolean_type_string_conversions) {
|
||||
BOOST_REQUIRE(boolean_type->equal(boolean_type->from_string(""), boolean_type->decompose(false)));
|
||||
BOOST_REQUIRE(boolean_type->equal(boolean_type->from_string("false"), boolean_type->decompose(false)));
|
||||
|
||||
@@ -358,6 +358,8 @@ future<> cql_server::connection::process_request() {
|
||||
}).then_wrapped([stream = f.stream, this] (future<> f) {
|
||||
try {
|
||||
f.get();
|
||||
} catch (const exceptions::cassandra_exception& ex) {
|
||||
write_error(stream, ex.code(), ex.what());
|
||||
} catch (std::exception& ex) {
|
||||
write_error(stream, exceptions::exception_code::SERVER_ERROR, ex.what());
|
||||
} catch (...) {
|
||||
|
||||
164
types.cc
164
types.cc
@@ -13,9 +13,12 @@
|
||||
#include "combine.hh"
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/range/numeric.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/c_local_time_adjustor.hpp>
|
||||
|
||||
template<typename T>
|
||||
struct simple_type_traits {
|
||||
@@ -337,10 +340,25 @@ struct timeuuid_type_impl : public abstract_type {
|
||||
return std::hash<bytes_view>()(v);
|
||||
}
|
||||
virtual bytes from_string(sstring_view s) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
if (s.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
static const std::regex re("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$");
|
||||
if (!std::regex_match(s.data(), re)) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
utils::UUID v(s);
|
||||
if (v.version() != 1) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
return v.to_bytes();
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
auto v = deserialize(b);
|
||||
if (v.empty()) {
|
||||
return "";
|
||||
}
|
||||
return boost::any_cast<const utils::UUID&>(v).to_sstring();
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const override {
|
||||
return cql3::cql3_type::timeuuid;
|
||||
@@ -381,8 +399,90 @@ struct timestamp_type_impl : simple_type_impl<db_clock::time_point> {
|
||||
return boost::any(db_clock::time_point(db_clock::duration(v)));
|
||||
}
|
||||
// FIXME: isCompatibleWith(timestampuuid)
|
||||
boost::posix_time::ptime get_time(const std::string& s) const {
|
||||
// Apparently, the code below doesn't leak the input facet.
|
||||
// std::locale::facet has some internal, custom reference counting
|
||||
// and deletes the object when it's no longer used.
|
||||
auto tif = new boost::posix_time::time_input_facet("%Y-%m-%d %H:%M:%S%F");
|
||||
std::istringstream ss(s);
|
||||
ss.imbue(std::locale(ss.getloc(), tif));
|
||||
boost::posix_time::ptime t;
|
||||
ss >> t;
|
||||
if (ss.fail() || ss.peek() != std::istringstream::traits_type::eof()) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
boost::posix_time::time_duration get_utc_offset(const std::string& s) const {
|
||||
static constexpr const char* formats[] = {
|
||||
"%H:%M",
|
||||
"%H%M",
|
||||
};
|
||||
for (auto&& f : formats) {
|
||||
auto tif = new boost::posix_time::time_input_facet(f);
|
||||
std::istringstream ss(s);
|
||||
ss.imbue(std::locale(ss.getloc(), tif));
|
||||
auto sign = ss.get();
|
||||
boost::posix_time::ptime p;
|
||||
ss >> p;
|
||||
if (ss.good() && ss.peek() == std::istringstream::traits_type::eof()) {
|
||||
return p.time_of_day() * (sign == '-' ? -1 : 1);
|
||||
}
|
||||
}
|
||||
throw marshal_exception();
|
||||
}
|
||||
int64_t timestamp_from_string(sstring_view s) const {
|
||||
std::string str;
|
||||
str.resize(s.size());
|
||||
std::transform(s.begin(), s.end(), str.begin(), ::tolower);
|
||||
if (str == "now") {
|
||||
return db_clock::now().time_since_epoch().count();
|
||||
}
|
||||
|
||||
char* end;
|
||||
auto v = std::strtoll(s.begin(), &end, 10);
|
||||
if (end == s.begin() + s.size()) {
|
||||
return v;
|
||||
}
|
||||
|
||||
std::regex date_re("^\\d{4}-\\d{2}-\\d{2}([ t]\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?)?");
|
||||
std::smatch dsm;
|
||||
if (!std::regex_search(str, dsm, date_re)) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
auto t = get_time(dsm.str());
|
||||
|
||||
auto tz = dsm.suffix().str();
|
||||
std::regex tz_re("([\\+-]\\d{2}:?(\\d{2})?)");
|
||||
std::smatch tsm;
|
||||
if (std::regex_match(tz, tsm, tz_re)) {
|
||||
t -= get_utc_offset(tsm.str());
|
||||
} else if (tz.empty()) {
|
||||
typedef boost::date_time::c_local_adjustor<boost::posix_time::ptime> local_tz;
|
||||
// local_tz::local_to_utc(), where are you?
|
||||
auto t1 = local_tz::utc_to_local(t);
|
||||
auto tz_offset = t1 - t;
|
||||
auto t2 = local_tz::utc_to_local(t - tz_offset);
|
||||
auto dst_offset = t2 - t;
|
||||
t -= tz_offset + dst_offset;
|
||||
} else {
|
||||
throw marshal_exception();
|
||||
}
|
||||
return (t - boost::posix_time::from_time_t(0)).total_milliseconds();
|
||||
}
|
||||
virtual bytes from_string(sstring_view s) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
if (s.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
int64_t ts;
|
||||
try {
|
||||
ts = timestamp_from_string(s);
|
||||
} catch (...) {
|
||||
throw marshal_exception(sprint("unable to parse date '%s'", s));
|
||||
}
|
||||
bytes b(bytes::initialized_later(), sizeof(int64_t));
|
||||
*unaligned_cast<int64_t*>(b.begin()) = net::hton(ts);
|
||||
return b;
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
@@ -447,10 +547,22 @@ struct uuid_type_impl : abstract_type {
|
||||
return std::hash<bytes_view>()(v);
|
||||
}
|
||||
virtual bytes from_string(sstring_view s) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
if (s.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
static const std::regex re("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$");
|
||||
if (!std::regex_match(s.data(), re)) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
utils::UUID v(s);
|
||||
return v.to_bytes();
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
auto v = deserialize(b);
|
||||
if (v.empty()) {
|
||||
return "";
|
||||
}
|
||||
return boost::any_cast<const utils::UUID&>(v).to_sstring();
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const override {
|
||||
return cql3::cql3_type::uuid;
|
||||
@@ -497,10 +609,28 @@ struct inet_addr_type_impl : abstract_type {
|
||||
return std::hash<bytes_view>()(v);
|
||||
}
|
||||
virtual bytes from_string(sstring_view s) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
// FIXME: support host names
|
||||
if (s.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
net::ipv4_address ipv4;
|
||||
try {
|
||||
ipv4 = net::ipv4_address(s.data());
|
||||
} catch (...) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
bytes b(bytes::initialized_later(), sizeof(uint32_t));
|
||||
auto out = b.begin();
|
||||
serialize(boost::any(ipv4), out);
|
||||
return b;
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
auto v = deserialize(b);
|
||||
if (v.empty()) {
|
||||
return "";
|
||||
}
|
||||
boost::asio::ip::address_v4 ipv4(boost::any_cast<const net::ipv4_address&>(v).ip);
|
||||
return ipv4.to_string();
|
||||
}
|
||||
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const override {
|
||||
return cql3::cql3_type::inet;
|
||||
@@ -573,10 +703,26 @@ struct floating_type_impl : public simple_type_impl<T> {
|
||||
return boost::any(x.d);
|
||||
}
|
||||
virtual bytes from_string(sstring_view s) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
if (s.empty()) {
|
||||
return bytes();
|
||||
}
|
||||
try {
|
||||
auto d = boost::lexical_cast<T>(s.begin(), s.size());
|
||||
bytes b(bytes::initialized_later(), sizeof(T));
|
||||
auto out = b.begin();
|
||||
serialize(boost::any(d), out);
|
||||
return b;
|
||||
}
|
||||
catch(const boost::bad_lexical_cast& e) {
|
||||
throw marshal_exception(sprint("Invalid number format '%s'", s));
|
||||
}
|
||||
}
|
||||
virtual sstring to_string(const bytes& b) const override {
|
||||
throw std::runtime_error("not implemented");
|
||||
auto v = deserialize(b);
|
||||
if (v.empty()) {
|
||||
return "";
|
||||
}
|
||||
return to_sstring(boost::any_cast<T>(v));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
UUID() : most_sig_bits(0), least_sig_bits(0) {}
|
||||
UUID(int64_t most_sig_bits, int64_t least_sig_bits)
|
||||
: most_sig_bits(most_sig_bits), least_sig_bits(least_sig_bits) {}
|
||||
explicit UUID(const sstring& uuid_string);
|
||||
explicit UUID(const sstring& uuid_string) : UUID(sstring_view(uuid_string)) { }
|
||||
explicit UUID(sstring_view uuid_string);
|
||||
|
||||
int64_t get_most_significant_bits() const {
|
||||
return most_sig_bits;
|
||||
|
||||
@@ -40,11 +40,13 @@ std::ostream& operator<<(std::ostream& out, const UUID& uuid) {
|
||||
return out << uuid.to_sstring();
|
||||
}
|
||||
|
||||
UUID::UUID(const sstring& uuid) {
|
||||
auto uuid_string = uuid;
|
||||
UUID::UUID(sstring_view uuid) {
|
||||
sstring uuid_string(uuid.begin(), uuid.end());
|
||||
boost::erase_all(uuid_string, "-");
|
||||
auto size = uuid_string.size() / 2;
|
||||
assert(size == 16);
|
||||
if (size != 16) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
sstring most = sstring(uuid_string.begin(), uuid_string.begin() + size);
|
||||
sstring least = sstring(uuid_string.begin() + size, uuid_string.end());
|
||||
int base = 16;
|
||||
|
||||
Reference in New Issue
Block a user