blob: 17ed9a43d3434b7c9fc5ec88e4ee8b2607a88ab3 [file] [log] [blame]
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/*
* This header file defines miscellaneous utility classes.
*
* @author Tian Xia <tianx@fb.com>
*
* this file is copied from
* https://github.com/facebook/mysql-5.6/blob/fb-mysql-5.6.35/fbson/FbsonUtil.h
* and modified by Doris
*/
#ifndef JSONB_JSONBUTIL_H
#define JSONB_JSONBUTIL_H
#include "common/status.h"
#include "jsonb_document.h"
#include "jsonb_stream.h"
namespace doris {
#define OUT_BUF_SIZE 1024
/*
* JsonbToJson converts an JsonbValue object to a JSON string.
*/
class JsonbToJson {
public:
JsonbToJson() : os_(buffer_, OUT_BUF_SIZE) {}
// get json string
std::string to_json_string(const char* data, size_t size) {
const JsonbDocument* pdoc;
THROW_IF_ERROR(doris::JsonbDocument::checkAndCreateDocument(data, size, &pdoc));
return to_json_string(pdoc->getValue());
}
std::string to_json_string(const JsonbValue* val) {
os_.clear();
os_.seekp(0);
if (val) {
intern_json(val);
}
os_.put(0);
std::string json_string {os_.getBuffer()};
return json_string;
}
static std::string jsonb_to_json_string(const char* data, size_t size) {
JsonbToJson jsonb_to_json;
return jsonb_to_json.to_json_string(data, size);
}
private:
// recursively convert JsonbValue
void intern_json(const JsonbValue* val) {
switch (val->type) {
case JsonbType::T_Null: {
os_.write("null", 4);
break;
}
case JsonbType::T_True: {
os_.write("true", 4);
break;
}
case JsonbType::T_False: {
os_.write("false", 5);
break;
}
case JsonbType::T_Int8: {
os_.write(val->unpack<JsonbInt8Val>()->val());
break;
}
case JsonbType::T_Int16: {
os_.write(val->unpack<JsonbInt16Val>()->val());
break;
}
case JsonbType::T_Int32: {
os_.write(val->unpack<JsonbInt32Val>()->val());
break;
}
case JsonbType::T_Int64: {
os_.write(val->unpack<JsonbInt64Val>()->val());
break;
}
case JsonbType::T_Double: {
os_.write(val->unpack<JsonbDoubleVal>()->val());
break;
}
case JsonbType::T_Float: {
os_.write(val->unpack<JsonbFloatVal>()->val());
break;
}
case JsonbType::T_Int128: {
os_.write(val->unpack<JsonbInt128Val>()->val());
break;
}
case JsonbType::T_String: {
string_to_json(val->unpack<JsonbStringVal>()->getBlob(),
val->unpack<JsonbStringVal>()->length());
break;
}
case JsonbType::T_Binary: {
os_.write("\"<BINARY>", 9);
os_.write(val->unpack<JsonbBinaryVal>()->getBlob(),
val->unpack<JsonbBinaryVal>()->getBlobLen());
os_.write("<BINARY>\"", 9);
break;
}
case JsonbType::T_Object: {
object_to_json(val->unpack<ObjectVal>());
break;
}
case JsonbType::T_Array: {
array_to_json(val->unpack<ArrayVal>());
break;
}
case JsonbType::T_Decimal32: {
const auto* decimal_val = val->unpack<JsonbDecimal32>();
decimal_to_json(vectorized::Decimal32 {decimal_val->val()}, decimal_val->precision,
decimal_val->scale);
break;
}
case JsonbType::T_Decimal64: {
const auto* decimal_val = val->unpack<JsonbDecimal64>();
decimal_to_json(vectorized::Decimal64 {decimal_val->val()}, decimal_val->precision,
decimal_val->scale);
break;
}
case JsonbType::T_Decimal128: {
const auto* decimal_val = val->unpack<JsonbDecimal128>();
decimal_to_json(vectorized::Decimal128V3 {decimal_val->val()}, decimal_val->precision,
decimal_val->scale);
break;
}
case JsonbType::T_Decimal256: {
const auto* decimal_val = val->unpack<JsonbDecimal256>();
decimal_to_json(vectorized::Decimal256 {decimal_val->val()}, decimal_val->precision,
decimal_val->scale);
break;
}
default:
break;
}
}
void string_to_json(const char* str, size_t len) {
os_.put('"');
if (nullptr == str) {
os_.put('"');
return;
}
char char_buffer[16];
for (const char* ptr = str; ptr != str + len && *ptr; ++ptr) {
if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\') {
os_.put(*ptr);
} else {
os_.put('\\');
unsigned char token;
switch (token = *ptr) {
case '\\':
os_.put('\\');
break;
case '\"':
os_.put('\"');
break;
case '\b':
os_.put('b');
break;
case '\f':
os_.put('f');
break;
case '\n':
os_.put('n');
break;
case '\r':
os_.put('r');
break;
case '\t':
os_.put('t');
break;
default: {
int char_num = snprintf(char_buffer, sizeof(char_buffer), "u%04x", token);
os_.write(char_buffer, char_num);
break;
}
}
}
}
os_.put('"');
}
// convert object
void object_to_json(const ObjectVal* val) {
os_.put('{');
auto iter = val->begin();
auto iter_fence = val->end();
while (iter < iter_fence) {
// write key
if (iter->klen()) {
string_to_json(iter->getKeyStr(), iter->klen());
} else {
// NOTE: we use sMaxKeyId to represent an empty key. see jsonb_writer.h
if (iter->getKeyId() == JsonbKeyValue::sMaxKeyId) {
string_to_json(nullptr, 0);
} else {
os_.write(iter->getKeyId());
}
}
os_.put(':');
// convert value
intern_json(iter->value());
++iter;
if (iter != iter_fence) {
os_.put(',');
}
}
assert(iter == iter_fence);
os_.put('}');
}
// convert array to json
void array_to_json(const ArrayVal* val) {
os_.put('[');
auto iter = val->begin();
auto iter_fence = val->end();
while (iter != iter_fence) {
// convert value
intern_json((const JsonbValue*)iter);
++iter;
if (iter != iter_fence) {
os_.put(',');
}
}
assert(iter == iter_fence);
os_.put(']');
}
template <JsonbDecimalType T>
void decimal_to_json(const T& value, const uint32_t precision, const uint32_t scale);
JsonbOutStream os_;
char buffer_[OUT_BUF_SIZE];
};
} // namespace doris
#endif // JSONB_JSONBUTIL_H