mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-12 19:02:12 +00:00
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:
@@ -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]));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) }),
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
20
types.cc
20
types.cc
@@ -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));
|
||||
}
|
||||
|
||||
3
types.hh
3
types.hh
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user