Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BugFix] try to parse it when casting string to json (backport #7835) #7863

Merged
merged 1 commit into from Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion be/src/exprs/vectorized/cast_expr.cpp
Expand Up @@ -114,7 +114,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 @@ -81,8 +81,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