Skip to content

Commit

Permalink
[BugFix] try to parse it when casting string to json (#7835)
Browse files Browse the repository at this point in the history
(cherry picked from commit 0edb37a)
  • Loading branch information
mofeiatwork authored and mergify[bot] committed Jun 29, 2022
1 parent e27e2aa commit bb668cd
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
7 changes: 6 additions & 1 deletion be/src/exprs/vectorized/cast_expr.cpp
Expand Up @@ -111,7 +111,12 @@ static ColumnPtr cast_to_json_fn(ColumnPtr& column) {
} else if constexpr (pt_is_boolean<FromType>) {
value = JsonValue::from_bool(viewer.value(row));
} else if constexpr (pt_is_binary<FromType>) {
value = JsonValue::from_string(viewer.value(row));
auto maybe = JsonValue::parse_json_or_string(viewer.value(row));
if (maybe.ok()) {
value = maybe.value();
} else {
overflow = true;
}
} else {
CHECK(false) << "not supported type " << FromType;
}
Expand Down
30 changes: 30 additions & 0 deletions be/src/util/json.cpp
Expand Up @@ -2,6 +2,8 @@

#include "util/json.h"

#include <algorithm>
#include <cctype>
#include <string>
#include <vector>

Expand All @@ -17,6 +19,34 @@

namespace starrocks {

static bool is_json_start_char(char ch) {
return ch == '{' || ch == '[' || ch == '"' || std::isdigit(ch);
}

StatusOr<JsonValue> JsonValue::parse_json_or_string(const Slice& src) {
try {
if (src.empty()) {
return JsonValue(noneJsonSlice());
}
// Check the first character for its type
auto end = src.get_data() + src.get_size();
auto iter = std::find_if_not(src.get_data(), end, std::iswspace);
if (iter != end && is_json_start_char(*iter)) {
// Parse it as an object or array
auto b = vpack::Parser::fromJson(src.get_data(), src.get_size());
JsonValue res;
res.assign(*b);
return res;
} else {
// Consider it as a sub-type string
return from_string(src);
}
} catch (const vpack::Exception& e) {
return fromVPackException(e);
}
return Status::OK();
}

Status JsonValue::parse(const Slice& src, JsonValue* out) {
try {
if (src.empty()) {
Expand Down
3 changes: 2 additions & 1 deletion be/src/util/json.h
Expand Up @@ -83,8 +83,9 @@ class JsonValue {

////////////////// parsing //////////////////////
static Status parse(const Slice& src, JsonValue* out);

static StatusOr<JsonValue> parse(const Slice& src);
// Try to parse it as JSON object, otherwise consider it as a string
static StatusOr<JsonValue> parse_json_or_string(const Slice& src);

////////////////// serialization //////////////////////
size_t serialize(uint8_t* dst) const;
Expand Down
14 changes: 10 additions & 4 deletions be/test/exprs/vectorized/cast_expr_test.cpp
Expand Up @@ -1522,11 +1522,17 @@ TEST_F(VectorizedCastExprTest, sqlToJson) {

// string
{
std::string str = "star";
EXPECT_EQ(R"("star")", evaluateCastToJson<TYPE_CHAR>(cast_expr, str));
EXPECT_EQ(R"("star")", evaluateCastToJson<TYPE_VARCHAR>(cast_expr, str));
EXPECT_EQ(R"("star")", evaluateCastToJson<TYPE_CHAR>(cast_expr, "star"));
EXPECT_EQ(R"(" star")", evaluateCastToJson<TYPE_VARCHAR>(cast_expr, " star"));

str = "上海";
EXPECT_EQ(R"(1)", evaluateCastToJson<TYPE_CHAR>(cast_expr, " 1"));
EXPECT_EQ(R"("1")", evaluateCastToJson<TYPE_CHAR>(cast_expr, "\"1\""));
EXPECT_EQ(R"({})", evaluateCastToJson<TYPE_CHAR>(cast_expr, "{}"));
EXPECT_EQ(R"({})", evaluateCastToJson<TYPE_CHAR>(cast_expr, " {}"));
EXPECT_EQ(R"({"star": "rocks"})", evaluateCastToJson<TYPE_CHAR>(cast_expr, R"({"star": "rocks"})"));
EXPECT_EQ(R"([])", evaluateCastToJson<TYPE_CHAR>(cast_expr, "[]"));

std::string str = "上海";
EXPECT_EQ(R"("上海")", evaluateCastToJson<TYPE_CHAR>(cast_expr, str));
EXPECT_EQ(R"("上海")", evaluateCastToJson<TYPE_VARCHAR>(cast_expr, str));
}
Expand Down

0 comments on commit bb668cd

Please sign in to comment.