Merge 'JSON support fixes' from Piotr

"
This series addresses SELECT/INSERT JSON support issues, namely
handling null values properly and parsing decimals from strings.
It also comes with updated cql tests.

Tests: unit (release)
"

Fixes #3666
Fixes #3664
Fixes #3667

* 'json_fixes_3' of https://github.com/psarna/scylla:
  cql3: remove superfluous null conversions in to_json_string
  tests: update JSON cql tests
  cql3: enable parsing decimal JSON values from string
  cql3: add missing return for dead cells
  cql3: simplify parsing optional JSON values
  cql3: add handling null value in to_json
  cql3: provide to_json_string for optional bytes argument

(cherry picked from commit 95677877c2)
This commit is contained in:
Duarte Nunes
2018-08-09 18:05:34 +01:00
committed by Avi Kivity
parent f8cec2f891
commit fd2b02a12c
6 changed files with 23 additions and 22 deletions

View File

@@ -177,7 +177,7 @@ shared_ptr<function>
make_to_json_function(data_type t) {
return make_native_scalar_function<true>("tojson", utf8_type, {t},
[t](cql_serialization_format sf, const std::vector<bytes_opt>& parameters) -> bytes_opt {
return utf8_type->decompose(t->to_json_string(parameters[0].value()));
return utf8_type->decompose(t->to_json_string(parameters[0]));
});
}

View File

@@ -96,12 +96,8 @@ public:
encoded_row.write("\\\"", 2);
}
encoded_row.write("\": ", 3);
if (parameters[i]) {
sstring row_sstring = _selector_types[i]->to_json_string(parameters[i].value());
encoded_row.write(row_sstring.c_str(), row_sstring.size());
} else {
encoded_row.write("null", 4);
}
sstring row_sstring = _selector_types[i]->to_json_string(parameters[i]);
encoded_row.write(row_sstring.c_str(), row_sstring.size());
}
encoded_row.write("}", 1);
return encoded_row.linearize().to_string();

View File

@@ -180,6 +180,7 @@ void
insert_prepared_json_statement::execute_set_value(mutation& m, const clustering_key_prefix& prefix, const update_parameters& params, const column_definition& column, const bytes_opt& value) {
if (!value) {
m.set_cell(prefix, column, std::move(operation::make_dead_cell(params)));
return;
} else if (!column.type->is_collection()) {
constants::setter::execute(m, prefix, params, column, raw_value_view::make_value(bytes_view(*value)));
return;

View File

@@ -2613,6 +2613,7 @@ SEASTAR_TEST_CASE(test_select_json_types) {
" r date,"
" s time,"
" u duration,"
" w int,"
");").get();
e.require_table_exists("ks", "all_types").get();
@@ -2640,7 +2641,7 @@ SEASTAR_TEST_CASE(test_select_json_types) {
" 1y2mo3w4d5h6m7s8ms9us10ns"
");").get();
auto msg = e.execute_cql("SELECT JSON a, b, c, d, e, f, \"G\", \"H\", \"I\", j, k, l, m, n, o, p, q, r, s, u, unixtimestampof(k) FROM all_types WHERE a = 'ascii'").get0();
auto msg = e.execute_cql("SELECT JSON a, b, c, d, e, f, \"G\", \"H\", \"I\", j, k, l, m, n, o, p, q, r, s, u, w, unixtimestampof(k) FROM all_types WHERE a = 'ascii'").get0();
assert_that(msg).is_rows().with_rows({
{
utf8_type->decompose(
@@ -2664,6 +2665,7 @@ SEASTAR_TEST_CASE(test_select_json_types) {
"\"r\": \"1970-01-02\", "
"\"s\": 00:00:00.000000001, "
"\"u\": \"1y2mo25d5h6m7s8ms9us10ns\", "
"\"w\": null, "
"\"unixtimestampof(k)\": 1261009589805}"
)
}
@@ -2671,7 +2673,7 @@ SEASTAR_TEST_CASE(test_select_json_types) {
msg = e.execute_cql("SELECT toJson(a), toJson(b), toJson(c), toJson(d), toJson(e), toJson(f),"
"toJson(\"G\"), toJson(\"H\"), toJson(\"I\"), toJson(j), toJson(k), toJson(l), toJson(m), toJson(n),"
"toJson(o), toJson(p), toJson(q), toJson(r), toJson(s), toJson(u),"
"toJson(o), toJson(p), toJson(q), toJson(r), toJson(s), toJson(u), toJson(w),"
"toJson(unixtimestampof(k)), toJson(toJson(toJson(p))) FROM all_types WHERE a = 'ascii'").get0();
assert_that(msg).is_rows().with_rows({
{
@@ -2695,6 +2697,7 @@ SEASTAR_TEST_CASE(test_select_json_types) {
utf8_type->decompose("\"1970-01-02\""),
utf8_type->decompose("00:00:00.000000001"),
utf8_type->decompose("\"1y2mo25d5h6m7s8ms9us10ns\""),
utf8_type->decompose("null"),
utf8_type->decompose("1261009589805"),
utf8_type->decompose("\"\\\"3\\\"\"")
}
@@ -2838,13 +2841,15 @@ SEASTAR_TEST_CASE(test_insert_json_types) {
e.execute_cql("UPDATE all_types SET b = fromJson('42') WHERE a = fromJson('\"ascii\"');").get();
e.execute_cql("UPDATE all_types SET \"I\" = fromJson('\"zażółć gęślą jaźń\"') WHERE a = fromJson('\"ascii\"');").get();
e.execute_cql("UPDATE all_types SET o = fromJson('\"3.45\"') WHERE a = fromJson('\"ascii\"');").get();
msg = e.execute_cql("SELECT a, b, \"I\" FROM all_types WHERE a = 'ascii'").get0();
msg = e.execute_cql("SELECT a, b, \"I\", o FROM all_types WHERE a = 'ascii'").get0();
assert_that(msg).is_rows().with_rows({
{
ascii_type->decompose(sstring("ascii")),
long_type->decompose(42l),
utf8_type->decompose(sstring("zażółć gęślą jaźń")),
decimal_type->decompose(big_decimal { 2, boost::multiprecision::cpp_int(345) }),
}
});
});

View File

@@ -236,9 +236,6 @@ struct integer_type_impl : simple_type_impl<T> {
return to_sstring(compose_value(b));
}
virtual sstring to_json_string(const bytes& b) const override {
if (b.empty()) {
return "null";
}
return to_sstring(compose_value(b));
}
virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const override {
@@ -506,9 +503,6 @@ struct boolean_type_impl : public simple_type_impl<bool> {
return boolean_to_string(*b.begin());
}
virtual sstring to_json_string(const bytes& b) const override {
if (b.empty()) {
return "null";
}
return to_string(b);
}
virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const override {
@@ -1412,7 +1406,7 @@ struct floating_type_impl : public simple_type_impl<T> {
virtual sstring to_json_string(const bytes& b) const override {
auto v = deserialize(b);
if (v.is_null()) {
return "null";
throw exceptions::invalid_request_exception("Cannot create JSON string - deserialization error");
}
T d = this->from_value(v);
if (std::isnan(d) || std::isinf(d)) {
@@ -1540,7 +1534,7 @@ public:
virtual sstring to_json_string(const bytes& b) const override {
auto v = deserialize(b);
if (v.is_null()) {
return "null";
throw exceptions::invalid_request_exception("Cannot create JSON string - deserialization error");
}
return from_value(v).get().str();
return to_string(b);
@@ -1648,13 +1642,15 @@ public:
virtual sstring to_json_string(const bytes& b) const override {
auto v = deserialize(b);
if (v.is_null()) {
return "null";
throw exceptions::invalid_request_exception("Cannot create JSON string - deserialization error");
}
return from_value(v).get().to_string();
}
virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const override {
if (!value.isNumeric()) {
throw marshal_exception(sprint("%s must be represented as numeric in JSON", value.toStyledString()));
if (value.isString()) {
return from_string(value.asString());
} else if (!value.isNumeric()) {
throw marshal_exception(sprint("%s must be represented as numeric or string in JSON", value.toStyledString()));
}
return from_string(json::to_sstring(value));
@@ -1871,7 +1867,7 @@ public:
virtual sstring to_json_string(const bytes& b) const override {
auto v = deserialize(b);
if (v.is_null()) {
return "null";
throw exceptions::invalid_request_exception("Cannot create JSON string - deserialization error");
}
return quote_json_string(to_string(b));
}

View File

@@ -551,6 +551,9 @@ public:
virtual sstring to_string(const bytes& b) const = 0;
virtual bytes from_string(sstring_view text) const = 0;
virtual sstring to_json_string(const bytes& b) const = 0;
sstring to_json_string(const bytes_opt& b) const {
return b ? to_json_string(*b) : "null";
}
virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const = 0;
virtual bool is_counter() const { return false; }
virtual bool is_collection() const { return false; }