fix formatting to json of Map type with integer keys

This commit is contained in:
Anton Popov 2021-07-05 03:35:27 +03:00
parent eca877ff39
commit 139482b5c9
5 changed files with 54 additions and 9 deletions

View File

@ -81,7 +81,7 @@ void SerializationMap::deserializeBinary(IColumn & column, ReadBuffer & istr) co
template <typename Writer> template <typename Writer>
void SerializationMap::serializeTextImpl(const IColumn & column, size_t row_num, WriteBuffer & ostr, Writer && writer) const void SerializationMap::serializeTextImpl(const IColumn & column, size_t row_num, bool quote_key, WriteBuffer & ostr, Writer && writer) const
{ {
const auto & column_map = assert_cast<const ColumnMap &>(column); const auto & column_map = assert_cast<const ColumnMap &>(column);
@ -97,7 +97,16 @@ void SerializationMap::serializeTextImpl(const IColumn & column, size_t row_num,
{ {
if (i != offset) if (i != offset)
writeChar(',', ostr); writeChar(',', ostr);
writer(key, nested_tuple.getColumn(0), i);
if (quote_key)
{
writeChar('"', ostr);
writer(key, nested_tuple.getColumn(0), i);
writeChar('"', ostr);
}
else
writer(key, nested_tuple.getColumn(0), i);
writeChar(':', ostr); writeChar(':', ostr);
writer(value, nested_tuple.getColumn(1), i); writer(value, nested_tuple.getColumn(1), i);
} }
@ -161,7 +170,7 @@ void SerializationMap::deserializeTextImpl(IColumn & column, ReadBuffer & istr,
void SerializationMap::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const void SerializationMap::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const
{ {
serializeTextImpl(column, row_num, ostr, serializeTextImpl(column, row_num, /*quote_key=*/ false, ostr,
[&](const SerializationPtr & subcolumn_serialization, const IColumn & subcolumn, size_t pos) [&](const SerializationPtr & subcolumn_serialization, const IColumn & subcolumn, size_t pos)
{ {
subcolumn_serialization->serializeTextQuoted(subcolumn, pos, ostr, settings); subcolumn_serialization->serializeTextQuoted(subcolumn, pos, ostr, settings);
@ -170,7 +179,6 @@ void SerializationMap::serializeText(const IColumn & column, size_t row_num, Wri
void SerializationMap::deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const void SerializationMap::deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const
{ {
deserializeTextImpl(column, istr, deserializeTextImpl(column, istr,
[&](const SerializationPtr & subcolumn_serialization, IColumn & subcolumn) [&](const SerializationPtr & subcolumn_serialization, IColumn & subcolumn)
{ {
@ -178,10 +186,13 @@ void SerializationMap::deserializeText(IColumn & column, ReadBuffer & istr, cons
}); });
} }
void SerializationMap::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const void SerializationMap::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const
{ {
serializeTextImpl(column, row_num, ostr, /// We need to double-quote integer keys to produce valid JSON.
const auto & column_key = assert_cast<const ColumnMap &>(column).getNestedData().getColumn(0);
bool quote_key = !WhichDataType(column_key.getDataType()).isStringOrFixedString();
serializeTextImpl(column, row_num, quote_key, ostr,
[&](const SerializationPtr & subcolumn_serialization, const IColumn & subcolumn, size_t pos) [&](const SerializationPtr & subcolumn_serialization, const IColumn & subcolumn, size_t pos)
{ {
subcolumn_serialization->serializeTextJSON(subcolumn, pos, ostr, settings); subcolumn_serialization->serializeTextJSON(subcolumn, pos, ostr, settings);

View File

@ -61,7 +61,7 @@ public:
private: private:
template <typename Writer> template <typename Writer>
void serializeTextImpl(const IColumn & column, size_t row_num, WriteBuffer & ostr, Writer && writer) const; void serializeTextImpl(const IColumn & column, size_t row_num, bool quote_key, WriteBuffer & ostr, Writer && writer) const;
template <typename Reader> template <typename Reader>
void deserializeTextImpl(IColumn & column, ReadBuffer & istr, Reader && reader) const; void deserializeTextImpl(IColumn & column, ReadBuffer & istr, Reader && reader) const;

View File

@ -2,6 +2,7 @@
#include <DataTypes/DataTypeString.h> #include <DataTypes/DataTypeString.h>
#include <Functions/FunctionFactory.h> #include <Functions/FunctionFactory.h>
#include <Functions/IFunction.h> #include <Functions/IFunction.h>
#include <Formats/FormatFactory.h>
#include <IO/WriteBufferFromVector.h> #include <IO/WriteBufferFromVector.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
@ -13,7 +14,9 @@ namespace
{ {
public: public:
static constexpr auto name = "toJSONString"; static constexpr auto name = "toJSONString";
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionToJSONString>(); } static FunctionPtr create(ContextPtr context) { return std::make_shared<FunctionToJSONString>(context); }
FunctionToJSONString(ContextPtr context) : format_settings(getFormatSettings(context)) {}
String getName() const override { return name; } String getName() const override { return name; }
@ -35,7 +38,7 @@ namespace
WriteBufferFromVector<ColumnString::Chars> json(data_to); WriteBufferFromVector<ColumnString::Chars> json(data_to);
for (size_t i = 0; i < input_rows_count; ++i) for (size_t i = 0; i < input_rows_count; ++i)
{ {
serializer->serializeTextJSON(*arguments[0].column, i, json, FormatSettings()); serializer->serializeTextJSON(*arguments[0].column, i, json, format_settings);
writeChar(0, json); writeChar(0, json);
offsets_to[i] = json.count(); offsets_to[i] = json.count();
} }
@ -43,6 +46,10 @@ namespace
json.finalize(); json.finalize();
return res; return res;
} }
private:
/// Affects only subset of part of settings related to json.
FormatSettings format_settings;
}; };
} }

View File

@ -0,0 +1,8 @@
{"m":{"1":2,"3":4}}
{1:2,3:4} {"1":2,"3":4} 1
{"m":{"key1":"1","key2":"2"}}
{'key1':1,'key2':2} {"key1":"1","key2":"2"} 1
{"m":{"key1":1,"key2":2}}
{'key1':1,'key2':2} {"key1":1,"key2":2} 1
{"m1":{"k1":"1","k2":"2"},"m2":{"1":2,"2":3}}
{"m1":{"k1":1,"k2":2},"m2":{"1":2,"2":3}}

View File

@ -0,0 +1,19 @@
SELECT map(1, 2, 3, 4) AS m FORMAT JSONEachRow;
SELECT map(1, 2, 3, 4) AS m, toJSONString(m) AS s, isValidJSON(s);
SELECT map('key1', number, 'key2', number * 2) AS m FROM numbers(1, 1) FORMAT JSONEachRow;
SELECT map('key1', number, 'key2', number * 2) AS m, toJSONString(m) AS s, isValidJSON(s) FROM numbers(1, 1);
SELECT map('key1', number, 'key2', number * 2) AS m FROM numbers(1, 1)
FORMAT JSONEachRow
SETTINGS output_format_json_quote_64bit_integers = 0;
SELECT map('key1', number, 'key2', number * 2) AS m, toJSONString(m) AS s, isValidJSON(s) FROM numbers(1, 1)
SETTINGS output_format_json_quote_64bit_integers = 0;
CREATE TEMPORARY TABLE map_json (m1 Map(String, UInt64), m2 Map(UInt32, UInt32));
INSERT INTO map_json FORMAT JSONEachRow {"m1" : {"k1" : 1, "k2" : 2}, "m2" : {"1" : 2, "2" : 3}};
SELECT m1, m2 FROM map_json FORMAT JSONEachRow;
SELECT m1, m2 FROM map_json FORMAT JSONEachRow SETTINGS output_format_json_quote_64bit_integers = 0;