2011-10-10 06:10:49 +00:00
|
|
|
#pragma once
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <limits>
|
|
|
|
#include <algorithm>
|
2017-07-14 15:08:01 +00:00
|
|
|
#include <iterator>
|
2010-06-04 18:25:25 +00:00
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
#include <common/DateLUT.h>
|
2017-01-21 04:24:28 +00:00
|
|
|
#include <common/LocalDate.h>
|
|
|
|
#include <common/LocalDateTime.h>
|
2018-11-25 00:08:50 +00:00
|
|
|
#include <common/find_symbols.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
#include <common/StringRef.h>
|
2020-09-14 11:56:43 +00:00
|
|
|
#include <common/wide_integer_to_string.h>
|
2011-05-05 19:10:17 +00:00
|
|
|
|
2019-09-26 15:12:40 +00:00
|
|
|
#include <Core/DecimalFunctions.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Core/Types.h>
|
2017-07-04 10:42:53 +00:00
|
|
|
#include <Core/UUID.h>
|
2020-08-19 11:52:17 +00:00
|
|
|
#include <Core/BigInt.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/Exception.h>
|
2018-01-15 19:07:47 +00:00
|
|
|
#include <Common/StringUtils/StringUtils.h>
|
2017-06-15 09:12:32 +00:00
|
|
|
#include <Common/UInt128.h>
|
2010-06-04 18:25:25 +00:00
|
|
|
|
2019-11-20 14:48:01 +00:00
|
|
|
#include <IO/CompressionMethod.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/WriteBuffer.h>
|
|
|
|
#include <IO/WriteIntText.h>
|
|
|
|
#include <IO/VarInt.h>
|
|
|
|
#include <IO/DoubleConverter.h>
|
2017-07-31 21:39:24 +00:00
|
|
|
#include <IO/WriteBufferFromString.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
|
2020-12-17 15:46:26 +00:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
|
|
|
#pragma clang diagnostic ignored "-Wsign-compare"
|
|
|
|
#endif
|
2020-12-16 21:52:04 +00:00
|
|
|
#include <dragonbox/dragonbox_to_chars.h>
|
2020-12-17 15:46:26 +00:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#endif
|
2020-01-06 03:22:11 +00:00
|
|
|
|
2018-08-06 10:02:26 +00:00
|
|
|
#include <Formats/FormatSettings.h>
|
2010-06-04 18:25:25 +00:00
|
|
|
|
2020-01-06 03:22:11 +00:00
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER;
|
2017-07-06 14:42:27 +00:00
|
|
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 11:56:43 +00:00
|
|
|
template <typename T>
|
|
|
|
inline std::string bigintToString(const T & x)
|
|
|
|
{
|
|
|
|
return to_string(x);
|
|
|
|
}
|
|
|
|
|
2017-05-23 20:04:42 +00:00
|
|
|
/// Helper functions for formatted and binary output.
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
|
|
inline void writeChar(char x, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
buf.nextIfAtEnd();
|
|
|
|
*buf.position() = x;
|
|
|
|
++buf.position();
|
2010-06-04 18:25:25 +00:00
|
|
|
}
|
|
|
|
|
2019-07-19 18:43:52 +00:00
|
|
|
/// Write the same character n times.
|
2019-07-01 05:58:31 +00:00
|
|
|
inline void writeChar(char c, size_t n, WriteBuffer & buf)
|
|
|
|
{
|
2019-07-14 22:53:30 +00:00
|
|
|
while (n)
|
|
|
|
{
|
2019-07-01 05:58:31 +00:00
|
|
|
buf.nextIfAtEnd();
|
|
|
|
size_t count = std::min(n, buf.available());
|
|
|
|
memset(buf.position(), c, count);
|
|
|
|
n -= count;
|
2019-07-14 08:22:55 +00:00
|
|
|
buf.position() += count;
|
2019-07-01 05:58:31 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-04 18:25:25 +00:00
|
|
|
|
2017-05-23 20:04:42 +00:00
|
|
|
/// Write POD-type in native format. It's recommended to use only with packed (dense) data types.
|
2011-07-04 18:22:37 +00:00
|
|
|
template <typename T>
|
2012-02-26 01:52:43 +00:00
|
|
|
inline void writePODBinary(const T & x, WriteBuffer & buf)
|
2011-07-04 18:22:37 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
buf.write(reinterpret_cast<const char *>(&x), sizeof(x));
|
2011-07-04 18:22:37 +00:00
|
|
|
}
|
|
|
|
|
2011-08-09 17:24:17 +00:00
|
|
|
template <typename T>
|
2011-12-02 19:18:04 +00:00
|
|
|
inline void writeIntBinary(const T & x, WriteBuffer & buf)
|
2011-08-09 17:24:17 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writePODBinary(x, buf);
|
2011-08-09 17:24:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2011-12-02 19:18:04 +00:00
|
|
|
inline void writeFloatBinary(const T & x, WriteBuffer & buf)
|
2011-08-09 17:24:17 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writePODBinary(x, buf);
|
2011-08-09 17:24:17 +00:00
|
|
|
}
|
|
|
|
|
2011-07-04 18:22:37 +00:00
|
|
|
|
2013-10-10 23:06:51 +00:00
|
|
|
inline void writeStringBinary(const std::string & s, WriteBuffer & buf)
|
2011-08-19 18:31:14 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeVarUInt(s.size(), buf);
|
|
|
|
buf.write(s.data(), s.size());
|
2011-08-19 18:31:14 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 16:32:37 +00:00
|
|
|
inline void writeStringBinary(const StringRef & s, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
writeVarUInt(s.size, buf);
|
|
|
|
buf.write(s.data, s.size);
|
|
|
|
}
|
|
|
|
|
2014-02-17 23:56:45 +00:00
|
|
|
inline void writeStringBinary(const char * s, WriteBuffer & buf)
|
|
|
|
{
|
2020-07-12 16:32:37 +00:00
|
|
|
writeStringBinary(StringRef{s}, buf);
|
2014-02-17 23:56:45 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 16:32:37 +00:00
|
|
|
inline void writeStringBinary(const std::string_view & s, WriteBuffer & buf)
|
2016-02-24 09:30:29 +00:00
|
|
|
{
|
2020-07-12 16:32:37 +00:00
|
|
|
writeStringBinary(StringRef{s}, buf);
|
2016-02-24 09:30:29 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:52:17 +00:00
|
|
|
template <typename T>
|
|
|
|
void writeBigIntBinary(const T & x, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
static const constexpr size_t bytesize = BigInt<T>::size;
|
|
|
|
char bytes[bytesize];
|
|
|
|
|
|
|
|
BigInt<T>::serialize(x, bytes);
|
|
|
|
|
|
|
|
buf.write(bytes, bytesize);
|
|
|
|
}
|
2011-08-19 18:31:14 +00:00
|
|
|
|
2013-10-10 20:33:08 +00:00
|
|
|
template <typename T>
|
2013-10-10 23:06:51 +00:00
|
|
|
void writeVectorBinary(const std::vector<T> & v, WriteBuffer & buf)
|
2013-10-10 20:33:08 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeVarUInt(v.size(), buf);
|
2013-10-10 20:33:08 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
|
|
|
|
writeBinary(*it, buf);
|
2013-10-10 20:33:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
inline void writeBoolText(bool x, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar(x ? '1' : '0', buf);
|
2011-11-21 10:09:22 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 02:38:09 +00:00
|
|
|
|
|
|
|
struct DecomposedFloat64
|
|
|
|
{
|
|
|
|
DecomposedFloat64(double x)
|
|
|
|
{
|
|
|
|
memcpy(&x_uint, &x, sizeof(x));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t x_uint;
|
|
|
|
|
|
|
|
bool sign() const
|
|
|
|
{
|
|
|
|
return x_uint >> 63;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t exponent() const
|
|
|
|
{
|
|
|
|
return (x_uint >> 52) & 0x7FF;
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t normalized_exponent() const
|
|
|
|
{
|
|
|
|
return int16_t(exponent()) - 1023;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t mantissa() const
|
|
|
|
{
|
|
|
|
return x_uint & 0x5affffffffffffful;
|
|
|
|
}
|
|
|
|
|
2020-01-07 03:22:28 +00:00
|
|
|
/// NOTE Probably floating point instructions can be better.
|
2020-01-07 02:38:09 +00:00
|
|
|
bool is_inside_int64() const
|
|
|
|
{
|
|
|
|
return x_uint == 0
|
|
|
|
|| (normalized_exponent() >= 0 && normalized_exponent() <= 52
|
2020-01-07 03:05:55 +00:00
|
|
|
&& ((mantissa() & ((1ULL << (52 - normalized_exponent())) - 1)) == 0));
|
2020-01-07 02:38:09 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DecomposedFloat32
|
|
|
|
{
|
|
|
|
DecomposedFloat32(float x)
|
|
|
|
{
|
|
|
|
memcpy(&x_uint, &x, sizeof(x));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t x_uint;
|
|
|
|
|
|
|
|
bool sign() const
|
|
|
|
{
|
|
|
|
return x_uint >> 31;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t exponent() const
|
|
|
|
{
|
|
|
|
return (x_uint >> 23) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t normalized_exponent() const
|
|
|
|
{
|
|
|
|
return int16_t(exponent()) - 127;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t mantissa() const
|
|
|
|
{
|
|
|
|
return x_uint & 0x7fffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_inside_int32() const
|
|
|
|
{
|
|
|
|
return x_uint == 0
|
|
|
|
|| (normalized_exponent() >= 0 && normalized_exponent() <= 23
|
2020-01-07 03:05:55 +00:00
|
|
|
&& ((mantissa() & ((1ULL << (23 - normalized_exponent())) - 1)) == 0));
|
2020-01-07 02:38:09 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-07-17 12:32:31 +00:00
|
|
|
template <typename T>
|
2020-01-06 03:22:11 +00:00
|
|
|
inline size_t writeFloatTextFastPath(T x, char * buffer)
|
2018-07-17 12:32:31 +00:00
|
|
|
{
|
2020-01-06 03:22:11 +00:00
|
|
|
int result = 0;
|
2020-01-06 10:34:33 +00:00
|
|
|
|
2018-07-17 12:32:31 +00:00
|
|
|
if constexpr (std::is_same_v<T, double>)
|
2020-01-07 02:38:09 +00:00
|
|
|
{
|
2020-01-07 03:22:28 +00:00
|
|
|
/// The library Ryu has low performance on integers.
|
|
|
|
/// This workaround improves performance 6..10 times.
|
|
|
|
|
2020-01-07 02:38:09 +00:00
|
|
|
if (DecomposedFloat64(x).is_inside_int64())
|
|
|
|
result = itoa(Int64(x), buffer) - buffer;
|
|
|
|
else
|
2020-12-05 21:32:03 +00:00
|
|
|
result = jkj::dragonbox::to_chars_n(x, buffer) - buffer;
|
2020-01-07 02:38:09 +00:00
|
|
|
}
|
2018-07-17 12:32:31 +00:00
|
|
|
else
|
2020-01-07 02:38:09 +00:00
|
|
|
{
|
|
|
|
if (DecomposedFloat32(x).is_inside_int32())
|
|
|
|
result = itoa(Int32(x), buffer) - buffer;
|
|
|
|
else
|
2020-12-05 21:32:03 +00:00
|
|
|
result = jkj::dragonbox::to_chars_n(x, buffer) - buffer;
|
2020-01-07 02:38:09 +00:00
|
|
|
}
|
2018-07-17 12:32:31 +00:00
|
|
|
|
2020-01-06 03:22:11 +00:00
|
|
|
if (result <= 0)
|
2018-07-17 12:32:31 +00:00
|
|
|
throw Exception("Cannot print floating point number", ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER);
|
2020-01-06 03:22:11 +00:00
|
|
|
return result;
|
2018-07-17 12:32:31 +00:00
|
|
|
}
|
2011-11-21 10:09:22 +00:00
|
|
|
|
2018-01-11 20:02:04 +00:00
|
|
|
template <typename T>
|
|
|
|
inline void writeFloatText(T x, WriteBuffer & buf)
|
2010-06-04 18:25:25 +00:00
|
|
|
{
|
2018-01-11 20:02:04 +00:00
|
|
|
static_assert(std::is_same_v<T, double> || std::is_same_v<T, float>, "Argument for writeFloatText must be float or double");
|
2015-07-16 20:02:36 +00:00
|
|
|
|
2018-01-11 20:02:04 +00:00
|
|
|
using Converter = DoubleConverter<false>;
|
2018-07-17 12:32:31 +00:00
|
|
|
if (likely(buf.available() >= Converter::MAX_REPRESENTATION_LENGTH))
|
|
|
|
{
|
2020-01-06 03:22:11 +00:00
|
|
|
buf.position() += writeFloatTextFastPath(x, buf.position());
|
2018-07-17 12:32:31 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-07-16 20:02:36 +00:00
|
|
|
|
2018-01-11 20:02:04 +00:00
|
|
|
Converter::BufferType buffer;
|
2020-01-06 03:22:11 +00:00
|
|
|
size_t result = writeFloatTextFastPath(x, buffer);
|
|
|
|
buf.write(buffer, result);
|
2010-06-04 18:25:25 +00:00
|
|
|
}
|
|
|
|
|
2011-08-09 17:24:17 +00:00
|
|
|
|
2013-05-15 22:58:57 +00:00
|
|
|
inline void writeString(const char * data, size_t size, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
buf.write(data, size);
|
2013-05-15 22:58:57 +00:00
|
|
|
}
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
inline void writeString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeString(ref.data, ref.size, buf);
|
2015-12-30 11:53:12 +00:00
|
|
|
}
|
|
|
|
|
2013-05-15 22:58:57 +00:00
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/** Writes a C-string without creating a temporary object. If the string is a literal, then `strlen` is executed at the compilation stage.
|
|
|
|
* Use when the string is a literal.
|
2013-05-20 09:33:45 +00:00
|
|
|
*/
|
|
|
|
#define writeCString(s, buf) \
|
2017-04-01 07:20:54 +00:00
|
|
|
(buf).write((s), strlen(s))
|
2013-05-20 09:33:45 +00:00
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/** Writes a string for use in the JSON format:
|
2017-08-08 20:57:23 +00:00
|
|
|
* - the string is written in double quotes
|
|
|
|
* - slash character '/' is escaped for compatibility with JavaScript
|
2017-05-28 14:29:40 +00:00
|
|
|
* - bytes from the range 0x00-0x1F except `\b', '\f', '\n', '\r', '\t' are escaped as \u00XX
|
|
|
|
* - code points U+2028 and U+2029 (byte sequences in UTF-8: e2 80 a8, e2 80 a9) are escaped as \u2028 and \u2029
|
2017-08-08 20:57:23 +00:00
|
|
|
* - it is assumed that string is in UTF-8, the invalid UTF-8 is not processed
|
|
|
|
* - all other non-ASCII characters remain as is
|
2013-05-20 09:33:45 +00:00
|
|
|
*/
|
2018-08-07 17:04:39 +00:00
|
|
|
inline void writeJSONString(const char * begin, const char * end, WriteBuffer & buf, const FormatSettings & settings)
|
2013-05-16 12:52:09 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('"', buf);
|
|
|
|
for (const char * it = begin; it != end; ++it)
|
|
|
|
{
|
|
|
|
switch (*it)
|
|
|
|
{
|
|
|
|
case '\b':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('b', buf);
|
|
|
|
break;
|
|
|
|
case '\f':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('f', buf);
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('n', buf);
|
|
|
|
break;
|
|
|
|
case '\r':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('r', buf);
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('t', buf);
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('\\', buf);
|
|
|
|
break;
|
|
|
|
case '/':
|
2018-08-06 14:12:50 +00:00
|
|
|
if (settings.json.escape_forward_slashes)
|
2018-08-06 10:02:26 +00:00
|
|
|
writeChar('\\', buf);
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('/', buf);
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('"', buf);
|
|
|
|
break;
|
|
|
|
default:
|
2017-08-08 20:57:23 +00:00
|
|
|
UInt8 c = *it;
|
2017-09-08 02:29:47 +00:00
|
|
|
if (c <= 0x1F)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-08-08 20:57:23 +00:00
|
|
|
/// Escaping of ASCII control characters.
|
|
|
|
|
|
|
|
UInt8 higher_half = c >> 4;
|
|
|
|
UInt8 lower_half = c & 0xF;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
writeCString("\\u00", buf);
|
|
|
|
writeChar('0' + higher_half, buf);
|
|
|
|
|
2017-09-08 02:29:47 +00:00
|
|
|
if (lower_half <= 9)
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('0' + lower_half, buf);
|
|
|
|
else
|
|
|
|
writeChar('A' + lower_half - 10, buf);
|
|
|
|
}
|
2017-08-08 21:07:14 +00:00
|
|
|
else if (end - it >= 3 && it[0] == '\xE2' && it[1] == '\x80' && (it[2] == '\xA8' || it[2] == '\xA9'))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-08-08 20:57:23 +00:00
|
|
|
/// This is for compatibility with JavaScript, because unescaped line separators are prohibited in string literals,
|
|
|
|
/// and these code points are alternative line separators.
|
|
|
|
|
2017-08-08 21:07:14 +00:00
|
|
|
if (it[2] == '\xA8')
|
2017-04-01 07:20:54 +00:00
|
|
|
writeCString("\\u2028", buf);
|
2017-08-08 21:07:14 +00:00
|
|
|
if (it[2] == '\xA9')
|
2017-04-01 07:20:54 +00:00
|
|
|
writeCString("\\u2029", buf);
|
2017-08-08 20:57:23 +00:00
|
|
|
|
|
|
|
/// Byte sequence is 3 bytes long. We have additional two bytes to skip.
|
|
|
|
it += 2;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
writeChar(*it, buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
writeChar('"', buf);
|
2013-05-16 12:52:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-22 11:10:00 +00:00
|
|
|
/** Will escape quote_character and a list of special characters('\b', '\f', '\n', '\r', '\t', '\0', '\\').
|
|
|
|
* - when escape_quote_with_quote is true, use backslash to escape list of special characters,
|
2019-06-24 14:38:58 +00:00
|
|
|
* and use quote_character to escape quote_character. such as: 'hello''world'
|
2019-06-22 11:10:00 +00:00
|
|
|
* - otherwise use backslash to escape list of special characters and quote_character
|
|
|
|
*/
|
|
|
|
template <char quote_character, bool escape_quote_with_quote = false>
|
2011-11-21 10:09:22 +00:00
|
|
|
void writeAnyEscapedString(const char * begin, const char * end, WriteBuffer & buf)
|
2011-11-01 17:57:37 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
const char * pos = begin;
|
|
|
|
while (true)
|
|
|
|
{
|
2017-05-28 14:29:40 +00:00
|
|
|
/// On purpose we will escape more characters than minimally necessary.
|
2019-06-22 11:10:00 +00:00
|
|
|
const char * next_pos = find_first_symbols<'\b', '\f', '\n', '\r', '\t', '\0', '\\', quote_character>(pos, end);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (next_pos == end)
|
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
pos = next_pos;
|
|
|
|
switch (*pos)
|
|
|
|
{
|
|
|
|
case '\b':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('b', buf);
|
|
|
|
break;
|
|
|
|
case '\f':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('f', buf);
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('n', buf);
|
|
|
|
break;
|
|
|
|
case '\r':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('r', buf);
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('t', buf);
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('0', buf);
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar('\\', buf);
|
|
|
|
break;
|
2019-06-22 11:10:00 +00:00
|
|
|
case quote_character:
|
|
|
|
{
|
|
|
|
if constexpr (escape_quote_with_quote)
|
|
|
|
writeChar(quote_character, buf);
|
|
|
|
else
|
|
|
|
writeChar('\\', buf);
|
|
|
|
writeChar(quote_character, buf);
|
2017-04-01 07:20:54 +00:00
|
|
|
break;
|
2019-06-22 11:10:00 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
default:
|
|
|
|
writeChar(*pos, buf);
|
|
|
|
}
|
|
|
|
++pos;
|
|
|
|
}
|
|
|
|
}
|
2011-11-01 17:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-12 16:32:37 +00:00
|
|
|
inline void writeJSONString(const StringRef & s, WriteBuffer & buf, const FormatSettings & settings)
|
2013-05-16 12:52:09 +00:00
|
|
|
{
|
2020-07-12 16:32:37 +00:00
|
|
|
writeJSONString(s.data, s.data + s.size, buf, settings);
|
2013-05-16 12:52:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 16:32:37 +00:00
|
|
|
inline void writeJSONString(const std::string_view & s, WriteBuffer & buf, const FormatSettings & settings)
|
|
|
|
{
|
|
|
|
writeJSONString(StringRef{s}, buf, settings);
|
|
|
|
}
|
2013-05-16 12:52:09 +00:00
|
|
|
|
2020-07-12 16:32:37 +00:00
|
|
|
inline void writeJSONString(const String & s, WriteBuffer & buf, const FormatSettings & settings)
|
2015-12-30 11:53:12 +00:00
|
|
|
{
|
2020-07-12 16:32:37 +00:00
|
|
|
writeJSONString(StringRef{s}, buf, settings);
|
2015-12-30 11:53:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
template <char c>
|
|
|
|
void writeAnyEscapedString(const String & s, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeAnyEscapedString<c>(s.data(), s.data() + s.size(), buf);
|
2011-11-21 10:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-28 14:08:31 +00:00
|
|
|
inline void writeEscapedString(const char * str, size_t size, WriteBuffer & buf)
|
2011-11-01 17:57:37 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeAnyEscapedString<'\''>(str, str + size, buf);
|
2015-05-28 14:08:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void writeEscapedString(const String & s, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeEscapedString(s.data(), s.size(), buf);
|
2011-11-01 17:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
inline void writeEscapedString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeEscapedString(ref.data, ref.size, buf);
|
2015-12-30 11:53:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-22 11:10:00 +00:00
|
|
|
template <char quote_character>
|
2013-04-15 19:33:05 +00:00
|
|
|
void writeAnyQuotedString(const char * begin, const char * end, WriteBuffer & buf)
|
2011-11-01 17:57:37 +00:00
|
|
|
{
|
2019-06-22 11:10:00 +00:00
|
|
|
writeChar(quote_character, buf);
|
|
|
|
writeAnyEscapedString<quote_character>(begin, end, buf);
|
|
|
|
writeChar(quote_character, buf);
|
2011-11-01 17:57:37 +00:00
|
|
|
}
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
2019-06-22 11:10:00 +00:00
|
|
|
template <char quote_character>
|
2013-04-15 19:33:05 +00:00
|
|
|
void writeAnyQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
{
|
2019-06-22 11:10:00 +00:00
|
|
|
writeAnyQuotedString<quote_character>(s.data(), s.data() + s.size(), buf);
|
2013-04-15 19:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-22 11:10:00 +00:00
|
|
|
template <char quote_character>
|
2015-12-30 11:53:12 +00:00
|
|
|
void writeAnyQuotedString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
{
|
2019-06-22 11:10:00 +00:00
|
|
|
writeAnyQuotedString<quote_character>(ref.data, ref.data + ref.size, buf);
|
2015-12-30 11:53:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
inline void writeQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeAnyQuotedString<'\''>(s, buf);
|
2011-11-01 17:57:37 +00:00
|
|
|
}
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
|
|
|
|
inline void writeQuotedString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeAnyQuotedString<'\''>(ref, buf);
|
2015-12-30 11:53:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-08 18:42:22 +00:00
|
|
|
inline void writeDoubleQuotedString(const StringRef & s, WriteBuffer & buf)
|
2011-11-01 17:57:37 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeAnyQuotedString<'"'>(s, buf);
|
2010-06-04 18:25:25 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 05:22:04 +00:00
|
|
|
/// Outputs a string in backquotes.
|
2019-10-08 18:42:22 +00:00
|
|
|
inline void writeBackQuotedString(const StringRef & s, WriteBuffer & buf)
|
2011-11-01 17:57:37 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeAnyQuotedString<'`'>(s, buf);
|
2011-11-01 17:57:37 +00:00
|
|
|
}
|
2011-06-15 18:54:18 +00:00
|
|
|
|
2019-06-21 05:22:04 +00:00
|
|
|
/// Outputs a string in backquotes for MySQL.
|
2019-10-08 18:42:22 +00:00
|
|
|
inline void writeBackQuotedStringMySQL(const StringRef & s, WriteBuffer & buf)
|
2019-06-21 05:22:04 +00:00
|
|
|
{
|
2019-06-22 11:10:00 +00:00
|
|
|
writeChar('`', buf);
|
2019-10-08 18:42:22 +00:00
|
|
|
writeAnyEscapedString<'`', true>(s.data, s.data + s.size, buf);
|
2019-06-22 11:10:00 +00:00
|
|
|
writeChar('`', buf);
|
2019-06-21 05:22:04 +00:00
|
|
|
}
|
|
|
|
|
2018-07-16 01:02:46 +00:00
|
|
|
|
2020-03-05 14:55:53 +00:00
|
|
|
/// Write quoted if the string doesn't look like and identifier.
|
|
|
|
void writeProbablyBackQuotedString(const StringRef & s, WriteBuffer & buf);
|
|
|
|
void writeProbablyDoubleQuotedString(const StringRef & s, WriteBuffer & buf);
|
|
|
|
void writeProbablyBackQuotedStringMySQL(const StringRef & s, WriteBuffer & buf);
|
2019-06-21 05:22:04 +00:00
|
|
|
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/** Outputs the string in for the CSV format.
|
|
|
|
* Rules:
|
|
|
|
* - the string is outputted in quotation marks;
|
|
|
|
* - the quotation mark inside the string is outputted as two quotation marks in sequence.
|
2016-02-07 08:42:21 +00:00
|
|
|
*/
|
|
|
|
template <char quote = '"'>
|
|
|
|
void writeCSVString(const char * begin, const char * end, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar(quote, buf);
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
const char * pos = begin;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
const char * next_pos = find_first_symbols<quote>(pos, end);
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (next_pos == end)
|
|
|
|
{
|
|
|
|
buf.write(pos, end - pos);
|
|
|
|
break;
|
|
|
|
}
|
2017-11-20 04:37:54 +00:00
|
|
|
else /// Quotation.
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
++next_pos;
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
writeChar(quote, buf);
|
|
|
|
}
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
pos = next_pos;
|
|
|
|
}
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar(quote, buf);
|
2016-02-07 08:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <char quote = '"'>
|
|
|
|
void writeCSVString(const String & s, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeCSVString<quote>(s.data(), s.data() + s.size(), buf);
|
2016-02-07 08:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <char quote = '"'>
|
|
|
|
void writeCSVString(const StringRef & s, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeCSVString<quote>(s.data, s.data + s.size, buf);
|
2016-02-07 08:42:21 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 09:00:27 +00:00
|
|
|
inline void writeXMLStringForTextElementOrAttributeValue(const char * begin, const char * end, WriteBuffer & buf)
|
2020-12-01 08:32:09 +00:00
|
|
|
{
|
|
|
|
const char * pos = begin;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
const char * next_pos = find_first_symbols<'<', '&', '>', '"', '\''>(pos, end);
|
|
|
|
|
|
|
|
if (next_pos == end)
|
|
|
|
{
|
|
|
|
buf.write(pos, end - pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (*next_pos == '<')
|
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString("<", buf);
|
|
|
|
}
|
|
|
|
else if (*next_pos == '&')
|
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString("&", buf);
|
2020-12-10 21:09:52 +00:00
|
|
|
}
|
|
|
|
else if (*next_pos == '>')
|
2020-12-01 08:32:09 +00:00
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString(">", buf);
|
2020-12-10 21:09:52 +00:00
|
|
|
}
|
|
|
|
else if (*next_pos == '"')
|
2020-12-01 08:32:09 +00:00
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString(""", buf);
|
2020-12-10 21:09:52 +00:00
|
|
|
}
|
|
|
|
else if (*next_pos == '\'')
|
2020-12-01 08:32:09 +00:00
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString("'", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = next_pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 09:00:27 +00:00
|
|
|
inline void writeXMLStringForTextElementOrAttributeValue(const String & s, WriteBuffer & buf)
|
2020-12-01 08:32:09 +00:00
|
|
|
{
|
2020-12-02 09:00:27 +00:00
|
|
|
writeXMLStringForTextElementOrAttributeValue(s.data(), s.data() + s.size(), buf);
|
2020-12-01 08:32:09 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 09:00:27 +00:00
|
|
|
inline void writeXMLStringForTextElementOrAttributeValue(const StringRef & s, WriteBuffer & buf)
|
2020-12-01 08:32:09 +00:00
|
|
|
{
|
2020-12-02 09:00:27 +00:00
|
|
|
writeXMLStringForTextElementOrAttributeValue(s.data, s.data + s.size, buf);
|
2020-12-01 08:32:09 +00:00
|
|
|
}
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// Writing a string to a text node in XML (not into an attribute - otherwise you need more escaping).
|
2020-12-02 09:00:27 +00:00
|
|
|
inline void writeXMLStringForTextElement(const char * begin, const char * end, WriteBuffer & buf)
|
2011-11-06 20:47:07 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
const char * pos = begin;
|
|
|
|
while (true)
|
|
|
|
{
|
2017-05-28 14:29:40 +00:00
|
|
|
/// NOTE Perhaps for some XML parsers, you need to escape the zero byte and some control characters.
|
2017-04-01 07:20:54 +00:00
|
|
|
const char * next_pos = find_first_symbols<'<', '&'>(pos, end);
|
|
|
|
|
|
|
|
if (next_pos == end)
|
|
|
|
{
|
|
|
|
buf.write(pos, end - pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (*next_pos == '<')
|
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString("<", buf);
|
|
|
|
}
|
|
|
|
else if (*next_pos == '&')
|
|
|
|
{
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
++next_pos;
|
|
|
|
writeCString("&", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = next_pos;
|
|
|
|
}
|
2011-11-06 20:47:07 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 09:00:27 +00:00
|
|
|
inline void writeXMLStringForTextElement(const String & s, WriteBuffer & buf)
|
2016-02-14 02:37:42 +00:00
|
|
|
{
|
2020-12-02 09:00:27 +00:00
|
|
|
writeXMLStringForTextElement(s.data(), s.data() + s.size(), buf);
|
2016-02-14 02:37:42 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 09:00:27 +00:00
|
|
|
inline void writeXMLStringForTextElement(const StringRef & s, WriteBuffer & buf)
|
2016-02-14 02:37:42 +00:00
|
|
|
{
|
2020-12-02 09:00:27 +00:00
|
|
|
writeXMLStringForTextElement(s.data, s.data + s.size, buf);
|
2016-02-14 02:37:42 +00:00
|
|
|
}
|
|
|
|
|
2017-07-14 15:08:01 +00:00
|
|
|
template <typename IteratorSrc, typename IteratorDst>
|
2017-07-21 06:46:50 +00:00
|
|
|
void formatHex(IteratorSrc src, IteratorDst dst, const size_t num_bytes);
|
2017-06-15 09:12:32 +00:00
|
|
|
void formatUUID(const UInt8 * src16, UInt8 * dst36);
|
2020-03-08 21:18:53 +00:00
|
|
|
void formatUUID(std::reverse_iterator<const UInt8 *> src16, UInt8 * dst36);
|
2017-06-15 09:12:32 +00:00
|
|
|
|
2017-07-04 10:42:53 +00:00
|
|
|
inline void writeUUIDText(const UUID & uuid, WriteBuffer & buf)
|
2017-06-15 09:12:32 +00:00
|
|
|
{
|
|
|
|
char s[36];
|
|
|
|
|
2017-07-14 15:08:01 +00:00
|
|
|
formatUUID(std::reverse_iterator<const UInt8 *>(reinterpret_cast<const UInt8 *>(&uuid) + 16), reinterpret_cast<UInt8 *>(s));
|
2017-06-15 09:12:32 +00:00
|
|
|
buf.write(s, sizeof(s));
|
|
|
|
}
|
2010-06-04 18:25:25 +00:00
|
|
|
|
2020-10-13 10:59:43 +00:00
|
|
|
template<typename DecimalType>
|
|
|
|
inline void writeDecimalTypeFractionalText(typename DecimalType::NativeType fractional, UInt32 scale, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
static constexpr UInt32 MaxScale = DecimalUtils::maxPrecision<DecimalType>();
|
|
|
|
|
|
|
|
char data[20] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
|
|
|
|
static_assert(sizeof(data) >= MaxScale);
|
|
|
|
|
|
|
|
for (Int32 pos = scale - 1; pos >= 0 && fractional; --pos, fractional /= DateTime64(10))
|
|
|
|
data[pos] += fractional % DateTime64(10);
|
|
|
|
|
|
|
|
writeString(&data[0], static_cast<size_t>(scale), buf);
|
|
|
|
}
|
2019-12-03 01:22:25 +00:00
|
|
|
|
|
|
|
static const char digits100[201] =
|
|
|
|
"00010203040506070809"
|
|
|
|
"10111213141516171819"
|
|
|
|
"20212223242526272829"
|
|
|
|
"30313233343536373839"
|
|
|
|
"40414243444546474849"
|
|
|
|
"50515253545556575859"
|
|
|
|
"60616263646566676869"
|
|
|
|
"70717273747576777879"
|
|
|
|
"80818283848586878889"
|
|
|
|
"90919293949596979899";
|
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// in YYYY-MM-DD format
|
2017-11-16 02:07:19 +00:00
|
|
|
template <char delimiter = '-'>
|
|
|
|
inline void writeDateText(const LocalDate & date, WriteBuffer & buf)
|
2011-05-05 19:10:17 +00:00
|
|
|
{
|
2021-01-04 18:07:52 +00:00
|
|
|
if (reinterpret_cast<intptr_t>(buf.position()) + 10 <= reinterpret_cast<intptr_t>(buf.buffer().end()))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[date.year() / 100 * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[date.year() % 100 * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = delimiter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[date.month() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = delimiter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[date.day() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[date.year() / 100 * 2], 2);
|
|
|
|
buf.write(&digits100[date.year() % 100 * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(delimiter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[date.month() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(delimiter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[date.day() * 2], 2);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2011-05-05 19:10:17 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 02:07:19 +00:00
|
|
|
template <char delimiter = '-'>
|
2018-05-25 13:29:15 +00:00
|
|
|
inline void writeDateText(DayNum date, WriteBuffer & buf)
|
2011-11-21 10:09:22 +00:00
|
|
|
{
|
2017-11-16 02:07:19 +00:00
|
|
|
writeDateText<delimiter>(LocalDate(date), buf);
|
2011-11-21 10:09:22 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
2017-11-16 02:07:19 +00:00
|
|
|
/// In the format YYYY-MM-DD HH:MM:SS
|
|
|
|
template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' '>
|
|
|
|
inline void writeDateTimeText(const LocalDateTime & datetime, WriteBuffer & buf)
|
2011-08-07 02:08:22 +00:00
|
|
|
{
|
2021-01-04 18:07:52 +00:00
|
|
|
if (reinterpret_cast<intptr_t>(buf.position()) + 19 <= reinterpret_cast<intptr_t>(buf.buffer().end()))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.year() / 100 * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.year() % 100 * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = date_delimeter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.month() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = date_delimeter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.day() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = between_date_time_delimiter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.hour() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = time_delimeter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.minute() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
*buf.position() = time_delimeter;
|
|
|
|
++buf.position();
|
2019-12-03 01:22:25 +00:00
|
|
|
memcpy(buf.position(), &digits100[datetime.second() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.position() += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[datetime.year() / 100 * 2], 2);
|
|
|
|
buf.write(&digits100[datetime.year() % 100 * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(date_delimeter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[datetime.month() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(date_delimeter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[datetime.day() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(between_date_time_delimiter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[datetime.hour() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(time_delimeter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[datetime.minute() * 2], 2);
|
2017-11-16 02:07:19 +00:00
|
|
|
buf.write(time_delimeter);
|
2019-12-03 01:22:25 +00:00
|
|
|
buf.write(&digits100[datetime.second() * 2], 2);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2011-08-07 02:08:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 02:07:19 +00:00
|
|
|
/// In the format YYYY-MM-DD HH:MM:SS, according to the specified time zone.
|
|
|
|
template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' '>
|
|
|
|
inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
|
2011-11-21 10:09:22 +00:00
|
|
|
{
|
2017-11-16 02:07:19 +00:00
|
|
|
const auto & values = date_lut.getValues(datetime);
|
|
|
|
writeDateTimeText<date_delimeter, time_delimeter, between_date_time_delimiter>(
|
|
|
|
LocalDateTime(values.year, values.month, values.day_of_month,
|
2019-11-20 08:57:19 +00:00
|
|
|
date_lut.toHour(datetime), date_lut.toMinute(datetime), date_lut.toSecond(datetime)), buf);
|
2011-11-21 10:09:22 +00:00
|
|
|
}
|
|
|
|
|
2019-05-01 22:42:17 +00:00
|
|
|
/// In the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN, according to the specified time zone.
|
|
|
|
template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' ', char fractional_time_delimiter = '.'>
|
2019-10-02 05:53:38 +00:00
|
|
|
inline void writeDateTimeText(DateTime64 datetime64, UInt32 scale, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
|
2019-05-01 22:42:17 +00:00
|
|
|
{
|
2019-12-06 21:05:31 +00:00
|
|
|
static constexpr UInt32 MaxScale = DecimalUtils::maxPrecision<DateTime64>();
|
2019-10-02 05:53:38 +00:00
|
|
|
scale = scale > MaxScale ? MaxScale : scale;
|
2020-07-12 20:10:04 +00:00
|
|
|
|
2019-12-06 21:05:31 +00:00
|
|
|
auto c = DecimalUtils::split(datetime64, scale);
|
2019-09-26 15:12:40 +00:00
|
|
|
const auto & values = date_lut.getValues(c.whole);
|
2019-05-01 22:42:17 +00:00
|
|
|
writeDateTimeText<date_delimeter, time_delimeter, between_date_time_delimiter>(
|
|
|
|
LocalDateTime(values.year, values.month, values.day_of_month,
|
2019-11-20 08:57:19 +00:00
|
|
|
date_lut.toHour(c.whole), date_lut.toMinute(c.whole), date_lut.toSecond(c.whole)), buf);
|
2019-05-01 22:42:17 +00:00
|
|
|
|
2019-12-11 08:56:32 +00:00
|
|
|
if (scale > 0)
|
2019-11-04 14:06:22 +00:00
|
|
|
{
|
|
|
|
buf.write(fractional_time_delimiter);
|
2020-10-13 10:59:43 +00:00
|
|
|
writeDecimalTypeFractionalText<DateTime64>(c.fractional, scale, buf);
|
2019-11-04 14:06:22 +00:00
|
|
|
}
|
2019-05-02 22:40:45 +00:00
|
|
|
}
|
2017-03-13 21:46:18 +00:00
|
|
|
|
2019-12-03 01:22:25 +00:00
|
|
|
/// In the RFC 1123 format: "Tue, 03 Dec 2019 00:11:50 GMT". You must provide GMT DateLUT.
|
|
|
|
/// This is needed for HTTP requests.
|
|
|
|
inline void writeDateTimeTextRFC1123(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut)
|
|
|
|
{
|
|
|
|
const auto & values = date_lut.getValues(datetime);
|
|
|
|
|
2019-12-03 01:29:19 +00:00
|
|
|
static const char week_days[3 * 8 + 1] = "XXX" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun";
|
|
|
|
static const char months[3 * 13 + 1] = "XXX" "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec";
|
2019-12-03 01:22:25 +00:00
|
|
|
|
|
|
|
buf.write(&week_days[values.day_of_week * 3], 3);
|
|
|
|
buf.write(", ", 2);
|
|
|
|
buf.write(&digits100[values.day_of_month * 2], 2);
|
|
|
|
buf.write(' ');
|
|
|
|
buf.write(&months[values.month * 3], 3);
|
|
|
|
buf.write(' ');
|
|
|
|
buf.write(&digits100[values.year / 100 * 2], 2);
|
|
|
|
buf.write(&digits100[values.year % 100 * 2], 2);
|
|
|
|
buf.write(' ');
|
|
|
|
buf.write(&digits100[date_lut.toHour(datetime) * 2], 2);
|
|
|
|
buf.write(':');
|
|
|
|
buf.write(&digits100[date_lut.toMinute(datetime) * 2], 2);
|
|
|
|
buf.write(':');
|
|
|
|
buf.write(&digits100[date_lut.toSecond(datetime) * 2], 2);
|
|
|
|
buf.write(" GMT", 4);
|
|
|
|
}
|
|
|
|
|
2020-10-13 10:59:43 +00:00
|
|
|
inline void writeDateTimeTextISO(time_t datetime, WriteBuffer & buf, const DateLUTImpl & utc_time_zone)
|
|
|
|
{
|
|
|
|
writeDateTimeText<'-', ':', 'T'>(datetime, buf, utc_time_zone);
|
|
|
|
buf.write('Z');
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void writeDateTimeTextISO(DateTime64 datetime64, UInt32 scale, WriteBuffer & buf, const DateLUTImpl & utc_time_zone)
|
|
|
|
{
|
|
|
|
writeDateTimeText<'-', ':', 'T'>(datetime64, scale, buf, utc_time_zone);
|
|
|
|
buf.write('Z');
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void writeDateTimeUnixTimestamp(DateTime64 datetime64, UInt32 scale, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
static constexpr UInt32 MaxScale = DecimalUtils::maxPrecision<DateTime64>();
|
|
|
|
scale = scale > MaxScale ? MaxScale : scale;
|
|
|
|
|
|
|
|
auto c = DecimalUtils::split(datetime64, scale);
|
|
|
|
writeIntText(c.whole, buf);
|
|
|
|
|
2020-10-13 12:23:50 +00:00
|
|
|
if (scale > 0)
|
2020-10-13 10:59:43 +00:00
|
|
|
{
|
|
|
|
buf.write('.');
|
|
|
|
writeDecimalTypeFractionalText<DateTime64>(c.fractional, scale, buf);
|
|
|
|
}
|
|
|
|
}
|
2019-12-03 01:22:25 +00:00
|
|
|
|
2017-11-16 02:07:19 +00:00
|
|
|
/// Methods for output in binary format.
|
2017-03-13 19:23:56 +00:00
|
|
|
template <typename T>
|
2019-11-02 05:55:06 +00:00
|
|
|
inline std::enable_if_t<is_arithmetic_v<T>, void>
|
2017-03-13 19:23:56 +00:00
|
|
|
writeBinary(const T & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
|
|
|
|
2017-06-21 01:24:05 +00:00
|
|
|
inline void writeBinary(const String & x, WriteBuffer & buf) { writeStringBinary(x, buf); }
|
|
|
|
inline void writeBinary(const StringRef & x, WriteBuffer & buf) { writeStringBinary(x, buf); }
|
2018-07-20 19:05:07 +00:00
|
|
|
inline void writeBinary(const Int128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
2017-06-30 20:21:42 +00:00
|
|
|
inline void writeBinary(const UInt128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
2020-09-01 09:54:50 +00:00
|
|
|
inline void writeBinary(const DummyUInt256 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
2018-09-11 18:42:06 +00:00
|
|
|
inline void writeBinary(const Decimal32 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
|
|
|
inline void writeBinary(const Decimal64 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
|
|
|
inline void writeBinary(const Decimal128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
2020-08-19 11:52:17 +00:00
|
|
|
inline void writeBinary(const Decimal256 & x, WriteBuffer & buf) { writeBigIntBinary(x.value, buf); }
|
2017-06-21 01:24:05 +00:00
|
|
|
inline void writeBinary(const LocalDate & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
|
|
|
inline void writeBinary(const LocalDateTime & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
2012-02-26 01:52:43 +00:00
|
|
|
|
2020-09-01 09:54:50 +00:00
|
|
|
inline void writeBinary(const UInt256 & x, WriteBuffer & buf) { writeBigIntBinary(x, buf); }
|
|
|
|
inline void writeBinary(const Int256 & x, WriteBuffer & buf) { writeBigIntBinary(x, buf); }
|
2012-02-26 01:52:43 +00:00
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// Methods for outputting the value in text form for a tab-separated format.
|
2017-03-13 19:23:56 +00:00
|
|
|
template <typename T>
|
2020-08-19 11:52:17 +00:00
|
|
|
inline std::enable_if_t<is_integer_v<T> && !is_big_int_v<T>, void>
|
2017-03-13 19:23:56 +00:00
|
|
|
writeText(const T & x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
|
|
|
template <typename T>
|
2017-12-25 04:01:46 +00:00
|
|
|
inline std::enable_if_t<std::is_floating_point_v<T>, void>
|
2017-03-13 19:23:56 +00:00
|
|
|
writeText(const T & x, WriteBuffer & buf) { writeFloatText(x, buf); }
|
|
|
|
|
2020-11-19 15:26:44 +00:00
|
|
|
inline void writeText(const String & x, WriteBuffer & buf) { writeString(x.c_str(), x.size(), buf); }
|
2017-03-13 21:46:18 +00:00
|
|
|
|
|
|
|
/// Implemented as template specialization (not function overload) to avoid preference over templates on arithmetic types above.
|
|
|
|
template <> inline void writeText<bool>(const bool & x, WriteBuffer & buf) { writeBoolText(x, buf); }
|
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// unlike the method for std::string
|
|
|
|
/// assumes here that `x` is a null-terminated string.
|
2020-11-19 15:26:44 +00:00
|
|
|
inline void writeText(const char * x, WriteBuffer & buf) { writeCString(x, buf); }
|
|
|
|
inline void writeText(const char * x, size_t size, WriteBuffer & buf) { writeString(x, size, buf); }
|
2012-02-26 01:52:43 +00:00
|
|
|
|
2020-09-04 13:33:02 +00:00
|
|
|
inline void writeText(const DayNum & x, WriteBuffer & buf) { writeDateText(LocalDate(x), buf); }
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeText(const LocalDate & x, WriteBuffer & buf) { writeDateText(x, buf); }
|
|
|
|
inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTimeText(x, buf); }
|
2017-07-04 10:42:53 +00:00
|
|
|
inline void writeText(const UUID & x, WriteBuffer & buf) { writeUUIDText(x, buf); }
|
2018-08-29 11:58:40 +00:00
|
|
|
inline void writeText(const UInt128 & x, WriteBuffer & buf) { writeText(UUID(x), buf); }
|
2020-09-01 09:54:50 +00:00
|
|
|
inline void writeText(const UInt256 & x, WriteBuffer & buf) { writeText(bigintToString(x), buf); }
|
|
|
|
inline void writeText(const Int256 & x, WriteBuffer & buf) { writeText(bigintToString(x), buf); }
|
2020-08-19 11:52:17 +00:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
String decimalFractional(const T & x, UInt32 scale)
|
|
|
|
{
|
2020-09-01 09:54:50 +00:00
|
|
|
if constexpr (std::is_same_v<T, Int256>)
|
2020-08-19 11:52:17 +00:00
|
|
|
{
|
|
|
|
static constexpr Int128 max_int128 = (Int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll;
|
|
|
|
|
|
|
|
if (x <= std::numeric_limits<UInt32>::max())
|
|
|
|
return decimalFractional(static_cast<UInt32>(x), scale);
|
|
|
|
else if (x <= std::numeric_limits<UInt64>::max())
|
|
|
|
return decimalFractional(static_cast<UInt64>(x), scale);
|
|
|
|
else if (x <= max_int128)
|
|
|
|
return decimalFractional(static_cast<Int128>(x), scale);
|
|
|
|
}
|
|
|
|
else if constexpr (std::is_same_v<T, Int128>)
|
|
|
|
{
|
|
|
|
if (x <= std::numeric_limits<UInt32>::max())
|
|
|
|
return decimalFractional(static_cast<UInt32>(x), scale);
|
|
|
|
else if (x <= std::numeric_limits<UInt64>::max())
|
|
|
|
return decimalFractional(static_cast<UInt64>(x), scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
String str(scale, '0');
|
|
|
|
T value = x;
|
|
|
|
for (Int32 pos = scale - 1; pos >= 0; --pos, value /= 10)
|
|
|
|
str[pos] += static_cast<char>(value % 10);
|
|
|
|
return str;
|
|
|
|
}
|
2012-02-26 01:52:43 +00:00
|
|
|
|
2018-08-23 19:11:31 +00:00
|
|
|
template <typename T>
|
2020-08-19 11:52:17 +00:00
|
|
|
void writeText(Decimal<T> x, UInt32 scale, WriteBuffer & ostr)
|
2018-08-23 19:11:31 +00:00
|
|
|
{
|
2020-08-26 16:33:25 +00:00
|
|
|
T part = DecimalUtils::getWholePart(x, scale);
|
|
|
|
|
|
|
|
if (x.value < 0 && part == 0)
|
2018-08-23 19:11:31 +00:00
|
|
|
{
|
|
|
|
writeChar('-', ostr); /// avoid crop leading minus when whole part is zero
|
|
|
|
}
|
|
|
|
|
2020-09-01 09:54:50 +00:00
|
|
|
if constexpr (std::is_same_v<T, Int256>)
|
2020-08-19 11:52:17 +00:00
|
|
|
writeText(part, ostr);
|
|
|
|
else
|
|
|
|
writeIntText(part, ostr);
|
2018-08-23 19:11:31 +00:00
|
|
|
|
|
|
|
if (scale)
|
|
|
|
{
|
|
|
|
writeChar('.', ostr);
|
2020-08-19 11:52:17 +00:00
|
|
|
part = DecimalUtils::getFractionalPart(x, scale);
|
|
|
|
String fractional = decimalFractional(part, scale);
|
|
|
|
ostr.write(fractional.data(), scale);
|
2018-08-23 19:11:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// String, date, datetime are in single quotes with C-style escaping. Numbers - without.
|
2017-03-13 19:23:56 +00:00
|
|
|
template <typename T>
|
2019-11-02 05:55:06 +00:00
|
|
|
inline std::enable_if_t<is_arithmetic_v<T>, void>
|
2017-03-13 19:23:56 +00:00
|
|
|
writeQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); }
|
2012-02-26 01:52:43 +00:00
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeQuoted(const String & x, WriteBuffer & buf) { writeQuotedString(x, buf); }
|
2012-01-24 16:45:50 +00:00
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeQuoted(const LocalDate & x, WriteBuffer & buf)
|
2012-01-24 16:45:50 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('\'', buf);
|
|
|
|
writeDateText(x, buf);
|
|
|
|
writeChar('\'', buf);
|
2012-01-24 16:45:50 +00:00
|
|
|
}
|
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeQuoted(const LocalDateTime & x, WriteBuffer & buf)
|
2012-01-24 16:45:50 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('\'', buf);
|
|
|
|
writeDateTimeText(x, buf);
|
|
|
|
writeChar('\'', buf);
|
2012-01-24 16:45:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-29 11:58:40 +00:00
|
|
|
inline void writeQuoted(const UUID & x, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
writeChar('\'', buf);
|
|
|
|
writeText(x, buf);
|
|
|
|
writeChar('\'', buf);
|
|
|
|
}
|
2012-01-24 16:45:50 +00:00
|
|
|
|
2020-09-01 09:54:50 +00:00
|
|
|
inline void writeQuoted(const UInt256 & x, WriteBuffer & buf)
|
2020-08-19 11:52:17 +00:00
|
|
|
{
|
|
|
|
writeChar('\'', buf);
|
|
|
|
writeText(x, buf);
|
|
|
|
writeChar('\'', buf);
|
|
|
|
}
|
|
|
|
|
2020-09-01 09:54:50 +00:00
|
|
|
inline void writeQuoted(const Int256 & x, WriteBuffer & buf)
|
2020-08-19 11:52:17 +00:00
|
|
|
{
|
|
|
|
writeChar('\'', buf);
|
|
|
|
writeText(x, buf);
|
|
|
|
writeChar('\'', buf);
|
|
|
|
}
|
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// String, date, datetime are in double quotes with C-style escaping. Numbers - without.
|
2017-03-13 19:23:56 +00:00
|
|
|
template <typename T>
|
2019-11-02 05:55:06 +00:00
|
|
|
inline std::enable_if_t<is_arithmetic_v<T>, void>
|
2017-03-13 19:23:56 +00:00
|
|
|
writeDoubleQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); }
|
2012-11-06 13:58:29 +00:00
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeDoubleQuoted(const String & x, WriteBuffer & buf) { writeDoubleQuotedString(x, buf); }
|
2012-11-06 13:58:29 +00:00
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeDoubleQuoted(const LocalDate & x, WriteBuffer & buf)
|
2012-11-06 13:58:29 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('"', buf);
|
|
|
|
writeDateText(x, buf);
|
|
|
|
writeChar('"', buf);
|
2012-11-06 13:58:29 +00:00
|
|
|
}
|
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeDoubleQuoted(const LocalDateTime & x, WriteBuffer & buf)
|
2012-11-06 13:58:29 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('"', buf);
|
|
|
|
writeDateTimeText(x, buf);
|
|
|
|
writeChar('"', buf);
|
2012-11-06 13:58:29 +00:00
|
|
|
}
|
|
|
|
|
2017-07-06 14:42:27 +00:00
|
|
|
inline void writeDoubleQuoted(const UUID & x, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
writeChar('"', buf);
|
|
|
|
writeText(x, buf);
|
|
|
|
writeChar('"', buf);
|
|
|
|
}
|
|
|
|
|
2012-11-06 13:58:29 +00:00
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// String - in double quotes and with CSV-escaping; date, datetime - in double quotes. Numbers - without.
|
2017-03-13 19:23:56 +00:00
|
|
|
template <typename T>
|
2019-11-02 05:55:06 +00:00
|
|
|
inline std::enable_if_t<is_arithmetic_v<T>, void>
|
2017-03-13 19:23:56 +00:00
|
|
|
writeCSV(const T & x, WriteBuffer & buf) { writeText(x, buf); }
|
|
|
|
|
2017-11-20 04:37:54 +00:00
|
|
|
inline void writeCSV(const String & x, WriteBuffer & buf) { writeCSVString<>(x, buf); }
|
|
|
|
inline void writeCSV(const LocalDate & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
|
2016-02-07 08:42:21 +00:00
|
|
|
inline void writeCSV(const LocalDateTime & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
|
2017-07-06 14:42:27 +00:00
|
|
|
inline void writeCSV(const UUID & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
|
2019-07-08 00:16:39 +00:00
|
|
|
[[noreturn]] inline void writeCSV(const UInt128, WriteBuffer &)
|
2017-07-06 14:42:27 +00:00
|
|
|
{
|
|
|
|
/** Because UInt128 isn't a natural type, without arithmetic operator and only use as an intermediary type -for UUID-
|
|
|
|
* it should never arrive here. But because we used the DataTypeNumber class we should have at least a definition of it.
|
|
|
|
*/
|
|
|
|
throw Exception("UInt128 cannot be write as a text", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
}
|
2016-02-07 08:42:21 +00:00
|
|
|
|
2014-01-05 13:40:11 +00:00
|
|
|
template <typename T>
|
|
|
|
void writeBinary(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t size = x.size();
|
|
|
|
writeVarUInt(size, buf);
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
|
|
writeBinary(x[i], buf);
|
2014-01-05 13:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void writeQuoted(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('[', buf);
|
|
|
|
for (size_t i = 0, size = x.size(); i < size; ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
writeChar(',', buf);
|
|
|
|
writeQuoted(x[i], buf);
|
|
|
|
}
|
|
|
|
writeChar(']', buf);
|
2014-01-05 13:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void writeDoubleQuoted(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeChar('[', buf);
|
|
|
|
for (size_t i = 0, size = x.size(); i < size; ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
writeChar(',', buf);
|
|
|
|
writeDoubleQuoted(x[i], buf);
|
|
|
|
}
|
|
|
|
writeChar(']', buf);
|
2014-01-05 13:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void writeText(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
writeQuoted(x, buf);
|
2014-01-05 13:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// Serialize exception (so that it can be transferred over the network)
|
2018-08-24 07:30:53 +00:00
|
|
|
void writeException(const Exception & e, WriteBuffer & buf, bool with_stack_trace);
|
2012-05-08 05:42:05 +00:00
|
|
|
|
|
|
|
|
2017-05-28 14:29:40 +00:00
|
|
|
/// An easy-to-use method for converting something to a string in text form.
|
2013-06-21 20:34:19 +00:00
|
|
|
template <typename T>
|
|
|
|
inline String toString(const T & x)
|
|
|
|
{
|
2017-07-31 21:39:24 +00:00
|
|
|
WriteBufferFromOwnString buf;
|
|
|
|
writeText(x, buf);
|
|
|
|
return buf.str();
|
2013-06-21 20:34:19 +00:00
|
|
|
}
|
2019-11-20 14:48:01 +00:00
|
|
|
|
2020-05-30 17:04:02 +00:00
|
|
|
inline void writeNullTerminatedString(const String & s, WriteBuffer & buffer)
|
|
|
|
{
|
2020-06-21 11:32:54 +00:00
|
|
|
/// c_str is guaranteed to return zero-terminated string
|
2020-06-21 11:41:06 +00:00
|
|
|
buffer.write(s.c_str(), s.size() + 1);
|
2020-05-30 17:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline std::enable_if_t<is_arithmetic_v<T> && (sizeof(T) <= 8), void>
|
|
|
|
writeBinaryBigEndian(T x, WriteBuffer & buf) /// Assuming little endian architecture.
|
|
|
|
{
|
|
|
|
if constexpr (sizeof(x) == 2)
|
|
|
|
x = __builtin_bswap16(x);
|
|
|
|
else if constexpr (sizeof(x) == 4)
|
|
|
|
x = __builtin_bswap32(x);
|
|
|
|
else if constexpr (sizeof(x) == 8)
|
|
|
|
x = __builtin_bswap64(x);
|
|
|
|
|
|
|
|
writePODBinary(x, buf);
|
|
|
|
}
|
|
|
|
|
2020-11-09 13:07:38 +00:00
|
|
|
struct PcgSerializer
|
|
|
|
{
|
|
|
|
static void serializePcg32(const pcg32_fast & rng, WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
writeText(rng.multiplier(), buf);
|
|
|
|
writeChar(' ', buf);
|
|
|
|
writeText(rng.increment(), buf);
|
|
|
|
writeChar(' ', buf);
|
|
|
|
writeText(rng.state_, buf);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-09 19:07:38 +00:00
|
|
|
void writePointerHex(const void * ptr, WriteBuffer & buf);
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
}
|