diff --git a/cql3/functions/functions.cc b/cql3/functions/functions.cc index 1960f51fc0..64e3f54164 100644 --- a/cql3/functions/functions.cc +++ b/cql3/functions/functions.cc @@ -177,7 +177,7 @@ shared_ptr make_to_json_function(data_type t) { return make_native_scalar_function("tojson", utf8_type, {t}, [t](cql_serialization_format sf, const std::vector& parameters) -> bytes_opt { - return utf8_type->decompose(t->to_json_string(parameters[0].value())); + return utf8_type->decompose(t->to_json_string(parameters[0])); }); } diff --git a/cql3/statements/select_statement.cc b/cql3/statements/select_statement.cc index 3fe357c3cd..66a875cf8c 100644 --- a/cql3/statements/select_statement.cc +++ b/cql3/statements/select_statement.cc @@ -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(); diff --git a/cql3/statements/update_statement.cc b/cql3/statements/update_statement.cc index b1a3f16a8d..bfab9655e2 100644 --- a/cql3/statements/update_statement.cc +++ b/cql3/statements/update_statement.cc @@ -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; diff --git a/tests/cql_query_test.cc b/tests/cql_query_test.cc index ea90f6f25a..c42d4be84e 100644 --- a/tests/cql_query_test.cc +++ b/tests/cql_query_test.cc @@ -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) }), } }); }); diff --git a/types.cc b/types.cc index 9ebcf7c426..7683ee8897 100644 --- a/types.cc +++ b/types.cc @@ -236,9 +236,6 @@ struct integer_type_impl : simple_type_impl { 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 { 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 { 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)); } diff --git a/types.hh b/types.hh index 5a8bb64389..c425a44fe3 100644 --- a/types.hh +++ b/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; }