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>
|
|
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/Common.h>
|
|
|
|
|
#include <common/DateLUT.h>
|
2017-01-21 04:24:28 +00:00
|
|
|
|
#include <common/LocalDate.h>
|
|
|
|
|
#include <common/LocalDateTime.h>
|
2016-02-17 02:38:56 +00:00
|
|
|
|
#include <common/find_first_symbols.h>
|
2011-05-05 19:10:17 +00:00
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
#include <DB/Core/Types.h>
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2016-08-16 21:23:53 +00:00
|
|
|
|
#include <DB/Common/StringUtils.h>
|
2015-12-30 11:53:12 +00:00
|
|
|
|
#include <DB/Core/StringRef.h>
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/IO/WriteBuffer.h>
|
2013-05-04 14:51:37 +00:00
|
|
|
|
#include <DB/IO/WriteIntText.h>
|
2011-08-19 18:31:14 +00:00
|
|
|
|
#include <DB/IO/VarInt.h>
|
2013-06-21 20:34:19 +00:00
|
|
|
|
#include <DB/IO/WriteBufferFromString.h>
|
2014-12-09 12:07:27 +00:00
|
|
|
|
#include <DB/IO/DoubleConverter.h>
|
2014-04-02 13:45:39 +00:00
|
|
|
|
#include <city.h>
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
/// Функции-помошники для форматированной записи
|
|
|
|
|
|
|
|
|
|
inline void writeChar(char x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
buf.nextIfAtEnd();
|
|
|
|
|
*buf.position() = x;
|
|
|
|
|
++buf.position();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-02-26 01:52:43 +00:00
|
|
|
|
/// Запись POD-типа в native формате
|
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
|
|
|
|
{
|
|
|
|
|
buf.write(reinterpret_cast<const char *>(&x), sizeof(x));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
{
|
2012-02-26 01:52:43 +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
|
|
|
|
{
|
2012-02-26 01:52:43 +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
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
writeVarUInt(strlen(s), buf);
|
|
|
|
|
buf.write(s, strlen(s));
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 09:30:29 +00:00
|
|
|
|
inline void writeStringBinary(const StringRef & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeVarUInt(s.size, buf);
|
|
|
|
|
buf.write(s.data, s.size);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
writeVarUInt(v.size(), buf);
|
|
|
|
|
|
|
|
|
|
for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
|
|
|
|
|
writeBinary(*it, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
|
inline void writeBoolText(bool x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeChar(x ? '1' : '0', buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-16 20:02:36 +00:00
|
|
|
|
inline void writeFloatText(double x, WriteBuffer & buf)
|
2010-06-04 18:25:25 +00:00
|
|
|
|
{
|
2015-11-30 15:15:45 +00:00
|
|
|
|
DoubleConverter<false>::BufferType buffer;
|
|
|
|
|
double_conversion::StringBuilder builder{buffer, sizeof(buffer)};
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
2015-11-30 15:15:45 +00:00
|
|
|
|
const auto result = DoubleConverter<false>::instance().ToShortest(x, &builder);
|
2014-12-09 12:07:27 +00:00
|
|
|
|
|
|
|
|
|
if (!result)
|
2015-07-16 20:02:36 +00:00
|
|
|
|
throw Exception("Cannot print double number", ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER);
|
|
|
|
|
|
2015-11-30 15:15:45 +00:00
|
|
|
|
buf.write(buffer, builder.position());
|
2015-07-16 20:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void writeFloatText(float x, WriteBuffer & buf)
|
|
|
|
|
{
|
2015-11-30 15:15:45 +00:00
|
|
|
|
DoubleConverter<false>::BufferType buffer;
|
|
|
|
|
double_conversion::StringBuilder builder{buffer, sizeof(buffer)};
|
2015-07-16 20:02:36 +00:00
|
|
|
|
|
2015-11-30 15:15:45 +00:00
|
|
|
|
const auto result = DoubleConverter<false>::instance().ToShortestSingle(x, &builder);
|
2015-07-16 20:02:36 +00:00
|
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
|
throw Exception("Cannot print float number", ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER);
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
2015-11-30 15:15:45 +00:00
|
|
|
|
buf.write(buffer, builder.position());
|
2010-06-04 18:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-09 17:24:17 +00:00
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
inline void writeString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
buf.write(s.data(), s.size());
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-15 22:58:57 +00:00
|
|
|
|
inline void writeString(const char * data, size_t size, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
buf.write(data, size);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
|
inline void writeString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeString(ref.data, ref.size, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-15 22:58:57 +00:00
|
|
|
|
|
2013-05-20 09:33:45 +00:00
|
|
|
|
/** Пишет С-строку без создания временного объекта. Если строка - литерал, то strlen выполняется на этапе компиляции.
|
|
|
|
|
* Используйте, когда строка - литерал.
|
|
|
|
|
*/
|
|
|
|
|
#define writeCString(s, buf) \
|
|
|
|
|
(buf).write((s), strlen(s))
|
|
|
|
|
|
|
|
|
|
/** Пишет строку для использования в формате JSON:
|
|
|
|
|
* - строка выводится в двойных кавычках
|
|
|
|
|
* - эскейпится символ прямого слеша '/'
|
|
|
|
|
* - байты из диапазона 0x00-0x1F кроме '\b', '\f', '\n', '\r', '\t' эскейпятся как \u00XX
|
|
|
|
|
* - кодовые точки U+2028 и U+2029 (последовательности байт в UTF-8: e2 80 a8, e2 80 a9) эскейпятся как \u2028 и \u2029
|
|
|
|
|
* - предполагается, что строка в кодировке UTF-8, невалидный UTF-8 не обрабатывается
|
|
|
|
|
* - не-ASCII символы остаются как есть
|
|
|
|
|
*/
|
2013-05-16 12:52:09 +00:00
|
|
|
|
inline void writeJSONString(const char * begin, const char * end, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
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);
|
2014-08-14 01:37:06 +00:00
|
|
|
|
break;
|
2013-05-16 12:52:09 +00:00
|
|
|
|
case '\\':
|
|
|
|
|
writeChar('\\', buf);
|
|
|
|
|
writeChar('\\', buf);
|
|
|
|
|
break;
|
|
|
|
|
case '/':
|
|
|
|
|
writeChar('\\', buf);
|
|
|
|
|
writeChar('/', buf);
|
|
|
|
|
break;
|
2013-09-02 15:32:17 +00:00
|
|
|
|
case '"':
|
|
|
|
|
writeChar('\\', buf);
|
|
|
|
|
writeChar('"', buf);
|
|
|
|
|
break;
|
2013-05-16 12:52:09 +00:00
|
|
|
|
default:
|
|
|
|
|
if (0x00 <= *it && *it <= 0x1F)
|
|
|
|
|
{
|
2013-05-20 09:33:45 +00:00
|
|
|
|
char higher_half = (*it) >> 4;
|
|
|
|
|
char lower_half = (*it) & 0xF;
|
2014-08-14 01:37:06 +00:00
|
|
|
|
|
2013-05-20 09:33:45 +00:00
|
|
|
|
writeCString("\\u00", buf);
|
|
|
|
|
writeChar('0' + higher_half, buf);
|
2014-08-14 01:37:06 +00:00
|
|
|
|
|
2013-05-20 09:33:45 +00:00
|
|
|
|
if (0 <= lower_half && lower_half <= 9)
|
|
|
|
|
writeChar('0' + lower_half, buf);
|
|
|
|
|
else
|
|
|
|
|
writeChar('A' + lower_half - 10, buf);
|
2013-05-16 12:52:09 +00:00
|
|
|
|
}
|
2013-05-20 09:33:45 +00:00
|
|
|
|
else if (end - it >= 3 && it[0] == '\xE2' && it[1] == '\x80' && (it[2] == '\xA8' || it[2] == '\xA9'))
|
2013-05-16 12:52:09 +00:00
|
|
|
|
{
|
2013-05-20 09:33:45 +00:00
|
|
|
|
if (it[2] == '\xA8')
|
|
|
|
|
writeCString("\\u2028", buf);
|
|
|
|
|
if (it[2] == '\xA9')
|
|
|
|
|
writeCString("\\u2029", buf);
|
2013-05-16 12:52:09 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
writeChar(*it, buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
writeChar('"', buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-11-01 17:57:37 +00:00
|
|
|
|
template <char c>
|
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
|
|
|
|
{
|
2016-02-17 02:38:56 +00:00
|
|
|
|
const char * pos = begin;
|
|
|
|
|
while (true)
|
2011-11-01 17:57:37 +00:00
|
|
|
|
{
|
2016-02-17 02:38:56 +00:00
|
|
|
|
/// Специально будем эскейпить больше символов, чем минимально необходимо.
|
|
|
|
|
const char * next_pos = find_first_symbols<'\b', '\f', '\n', '\r', '\t', '\0', '\\', c>(pos, end);
|
|
|
|
|
|
|
|
|
|
if (next_pos == end)
|
2011-11-01 17:57:37 +00:00
|
|
|
|
{
|
2016-02-17 02:38:56 +00:00
|
|
|
|
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;
|
|
|
|
|
case c:
|
|
|
|
|
writeChar('\\', buf);
|
|
|
|
|
writeChar(c, buf);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
writeChar(*pos, buf);
|
|
|
|
|
}
|
|
|
|
|
++pos;
|
2011-11-01 17:57:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-16 12:52:09 +00:00
|
|
|
|
inline void writeJSONString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeJSONString(s.data(), s.data() + s.size(), buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
|
inline void writeJSONString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeJSONString(ref.data, ref.data + ref.size, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
|
template <char c>
|
|
|
|
|
void writeAnyEscapedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeAnyEscapedString<c>(s.data(), s.data() + s.size(), buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2016-02-17 02:38:56 +00:00
|
|
|
|
writeAnyEscapedString<'\''>(str, str + size, buf);
|
2015-05-28 14:08:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline void writeEscapedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
writeEscapedString(ref.data, ref.size, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-11-01 17:57:37 +00:00
|
|
|
|
template <char c>
|
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
|
|
|
|
{
|
|
|
|
|
writeChar(c, buf);
|
2013-04-15 19:33:05 +00:00
|
|
|
|
writeAnyEscapedString<c>(begin, end, buf);
|
2011-11-01 17:57:37 +00:00
|
|
|
|
writeChar(c, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
2013-04-15 19:33:05 +00:00
|
|
|
|
|
|
|
|
|
template <char c>
|
|
|
|
|
void writeAnyQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeAnyQuotedString<c>(s.data(), s.data() + s.size(), buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
|
template <char c>
|
|
|
|
|
void writeAnyQuotedString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeAnyQuotedString<c>(ref.data, ref.data + ref.size, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
inline void writeQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
2011-11-01 17:57:37 +00:00
|
|
|
|
writeAnyQuotedString<'\''>(s, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-30 11:53:12 +00:00
|
|
|
|
|
|
|
|
|
inline void writeQuotedString(const StringRef & ref, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeAnyQuotedString<'\''>(ref, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-01 17:57:37 +00:00
|
|
|
|
inline void writeDoubleQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeAnyQuotedString<'"'>(s, buf);
|
2010-06-04 18:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-06 20:47:07 +00:00
|
|
|
|
/// Выводит строку в обратных кавычках, как идентификатор в MySQL.
|
2011-11-01 17:57:37 +00:00
|
|
|
|
inline void writeBackQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeAnyQuotedString<'`'>(s, buf);
|
|
|
|
|
}
|
2011-06-15 18:54:18 +00:00
|
|
|
|
|
2016-02-14 02:37:42 +00:00
|
|
|
|
/// То же самое, но обратные кавычки применяются только при наличии символов, не подходящих для идентификатора без обратных кавычек.
|
|
|
|
|
inline void writeProbablyBackQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
2016-08-16 21:23:53 +00:00
|
|
|
|
if (s.empty() || !isWordCharASCII(s[0]))
|
2016-02-14 02:37:42 +00:00
|
|
|
|
writeBackQuotedString(s, buf);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char * pos = s.data() + 1;
|
|
|
|
|
const char * end = s.data() + s.size();
|
|
|
|
|
for (; pos < end; ++pos)
|
2016-08-16 21:23:53 +00:00
|
|
|
|
if (!isWordCharASCII(*pos))
|
2016-02-14 02:37:42 +00:00
|
|
|
|
break;
|
|
|
|
|
if (pos != end)
|
|
|
|
|
writeBackQuotedString(s, buf);
|
|
|
|
|
else
|
|
|
|
|
writeString(s, buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-07 08:42:21 +00:00
|
|
|
|
|
|
|
|
|
/** Выводит строку в для формата CSV.
|
|
|
|
|
* Правила:
|
|
|
|
|
* - строка выводится в кавычках;
|
2016-06-14 18:32:07 +00:00
|
|
|
|
* - кавычка внутри строки выводится как две кавычки подряд.
|
2016-02-07 08:42:21 +00:00
|
|
|
|
*/
|
|
|
|
|
template <char quote = '"'>
|
|
|
|
|
void writeCSVString(const char * begin, const char * end, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeChar(quote, buf);
|
|
|
|
|
|
|
|
|
|
const char * pos = begin;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
2016-02-17 02:38:56 +00:00
|
|
|
|
const char * next_pos = find_first_symbols<quote>(pos, end);
|
2016-02-07 08:42:21 +00:00
|
|
|
|
|
|
|
|
|
if (next_pos == end)
|
|
|
|
|
{
|
|
|
|
|
buf.write(pos, end - pos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else /// Кавычка.
|
|
|
|
|
{
|
|
|
|
|
++next_pos;
|
|
|
|
|
buf.write(pos, next_pos - pos);
|
|
|
|
|
writeChar(quote, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos = next_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writeChar(quote, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <char quote = '"'>
|
|
|
|
|
void writeCSVString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeCSVString<quote>(s.data(), s.data() + s.size(), buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <char quote = '"'>
|
|
|
|
|
void writeCSVString(const StringRef & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeCSVString<quote>(s.data, s.data + s.size, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-14 02:37:42 +00:00
|
|
|
|
/// Запись строки в текстовый узел в XML (не в атрибут - иначе нужно больше эскейпинга).
|
|
|
|
|
inline void writeXMLString(const char * begin, const char * end, WriteBuffer & buf)
|
2011-11-06 20:47:07 +00:00
|
|
|
|
{
|
2016-02-14 02:37:42 +00:00
|
|
|
|
const char * pos = begin;
|
|
|
|
|
while (true)
|
2011-11-06 20:47:07 +00:00
|
|
|
|
{
|
2016-02-17 02:38:56 +00:00
|
|
|
|
/// NOTE Возможно, для некоторых парсеров XML нужно ещё эскейпить нулевой байт и некоторые control characters.
|
|
|
|
|
const char * next_pos = find_first_symbols<'<', '&'>(pos, end);
|
2016-02-14 02:37:42 +00:00
|
|
|
|
|
2016-02-17 02:38:56 +00:00
|
|
|
|
if (next_pos == end)
|
2016-02-14 02:37:42 +00:00
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-14 02:37:42 +00:00
|
|
|
|
inline void writeXMLString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeXMLString(s.data(), s.data() + s.size(), buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void writeXMLString(const StringRef & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeXMLString(s.data, s.data + s.size, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
/// в формате YYYY-MM-DD
|
2013-08-11 03:40:14 +00:00
|
|
|
|
inline void writeDateText(DayNum_t date, WriteBuffer & buf)
|
2011-05-05 19:10:17 +00:00
|
|
|
|
{
|
2011-08-07 03:42:36 +00:00
|
|
|
|
char s[10] = {'0', '0', '0', '0', '-', '0', '0', '-', '0', '0'};
|
|
|
|
|
|
|
|
|
|
if (unlikely(date > DATE_LUT_MAX_DAY_NUM || date == 0))
|
|
|
|
|
{
|
|
|
|
|
buf.write(s, 10);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-05-05 19:10:17 +00:00
|
|
|
|
|
2015-06-26 15:11:31 +00:00
|
|
|
|
const auto & values = DateLUT::instance().getValues(date);
|
2011-05-05 19:10:17 +00:00
|
|
|
|
|
2011-08-07 03:42:36 +00:00
|
|
|
|
s[0] += values.year / 1000;
|
|
|
|
|
s[1] += (values.year / 100) % 10;
|
|
|
|
|
s[2] += (values.year / 10) % 10;
|
|
|
|
|
s[3] += values.year % 10;
|
|
|
|
|
s[5] += values.month / 10;
|
|
|
|
|
s[6] += values.month % 10;
|
|
|
|
|
s[8] += values.day_of_month / 10;
|
|
|
|
|
s[9] += values.day_of_month % 10;
|
2014-08-14 01:37:06 +00:00
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
buf.write(s, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeDateText(LocalDate date, WriteBuffer & buf)
|
2011-11-21 10:09:22 +00:00
|
|
|
|
{
|
|
|
|
|
char s[10] = {'0', '0', '0', '0', '-', '0', '0', '-', '0', '0'};
|
|
|
|
|
|
|
|
|
|
s[0] += date.year() / 1000;
|
|
|
|
|
s[1] += (date.year() / 100) % 10;
|
|
|
|
|
s[2] += (date.year() / 10) % 10;
|
|
|
|
|
s[3] += date.year() % 10;
|
|
|
|
|
s[5] += date.month() / 10;
|
|
|
|
|
s[6] += date.month() % 10;
|
|
|
|
|
s[8] += date.day() / 10;
|
|
|
|
|
s[9] += date.day() % 10;
|
|
|
|
|
|
|
|
|
|
buf.write(s, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
|
2011-08-07 02:08:22 +00:00
|
|
|
|
/// в формате YYYY-MM-DD HH:MM:SS, согласно текущему часовому поясу
|
2015-07-07 09:29:29 +00:00
|
|
|
|
template <char date_delimeter = '-', char time_delimeter = ':'>
|
2017-01-22 08:33:16 +00:00
|
|
|
|
inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
|
2011-08-07 02:08:22 +00:00
|
|
|
|
{
|
2014-12-03 10:50:00 +00:00
|
|
|
|
char s[19] = {'0', '0', '0', '0', date_delimeter, '0', '0', date_delimeter, '0', '0', ' ', '0', '0', time_delimeter, '0', '0', time_delimeter, '0', '0'};
|
2011-08-07 03:42:36 +00:00
|
|
|
|
|
|
|
|
|
if (unlikely(datetime > DATE_LUT_MAX || datetime == 0))
|
|
|
|
|
{
|
|
|
|
|
buf.write(s, 19);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
2015-06-26 15:11:31 +00:00
|
|
|
|
const auto & values = date_lut.getValues(datetime);
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
2011-08-07 03:42:36 +00:00
|
|
|
|
s[0] += values.year / 1000;
|
|
|
|
|
s[1] += (values.year / 100) % 10;
|
|
|
|
|
s[2] += (values.year / 10) % 10;
|
|
|
|
|
s[3] += values.year % 10;
|
|
|
|
|
s[5] += values.month / 10;
|
|
|
|
|
s[6] += values.month % 10;
|
|
|
|
|
s[8] += values.day_of_month / 10;
|
|
|
|
|
s[9] += values.day_of_month % 10;
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
2016-12-27 06:36:53 +00:00
|
|
|
|
UInt8 hour = date_lut.toHour(datetime);
|
2012-08-31 20:38:05 +00:00
|
|
|
|
UInt8 minute = date_lut.toMinuteInaccurate(datetime);
|
|
|
|
|
UInt8 second = date_lut.toSecondInaccurate(datetime);
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
2011-08-07 03:42:36 +00:00
|
|
|
|
s[11] += hour / 10;
|
|
|
|
|
s[12] += hour % 10;
|
|
|
|
|
s[14] += minute / 10;
|
|
|
|
|
s[15] += minute % 10;
|
|
|
|
|
s[17] += second / 10;
|
|
|
|
|
s[18] += second % 10;
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
|
|
|
|
buf.write(s, 19);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 09:29:29 +00:00
|
|
|
|
template <char date_delimeter = '-', char time_delimeter = ':'>
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeDateTimeText(LocalDateTime datetime, WriteBuffer & buf)
|
2011-11-21 10:09:22 +00:00
|
|
|
|
{
|
2014-12-03 10:50:00 +00:00
|
|
|
|
char s[19] = {'0', '0', '0', '0', date_delimeter, '0', '0', date_delimeter, '0', '0', ' ', '0', '0', time_delimeter, '0', '0', time_delimeter, '0', '0'};
|
2011-11-21 10:09:22 +00:00
|
|
|
|
|
|
|
|
|
s[0] += datetime.year() / 1000;
|
|
|
|
|
s[1] += (datetime.year() / 100) % 10;
|
|
|
|
|
s[2] += (datetime.year() / 10) % 10;
|
|
|
|
|
s[3] += datetime.year() % 10;
|
|
|
|
|
s[5] += datetime.month() / 10;
|
|
|
|
|
s[6] += datetime.month() % 10;
|
|
|
|
|
s[8] += datetime.day() / 10;
|
|
|
|
|
s[9] += datetime.day() % 10;
|
|
|
|
|
|
|
|
|
|
s[11] += datetime.hour() / 10;
|
|
|
|
|
s[12] += datetime.hour() % 10;
|
|
|
|
|
s[14] += datetime.minute() / 10;
|
|
|
|
|
s[15] += datetime.minute() % 10;
|
|
|
|
|
s[17] += datetime.second() / 10;
|
|
|
|
|
s[18] += datetime.second() % 10;
|
|
|
|
|
|
|
|
|
|
buf.write(s, 19);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-02-26 01:52:43 +00:00
|
|
|
|
/// Методы вывода в бинарном виде
|
2017-03-13 19:23:56 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
|
|
|
|
writeBinary(const T & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
|
|
|
|
|
2012-02-26 01:52:43 +00:00
|
|
|
|
inline void writeBinary(const String & x, WriteBuffer & buf) { writeStringBinary(x, buf); }
|
2014-04-02 13:45:39 +00:00
|
|
|
|
inline void writeBinary(const uint128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
|
2016-02-03 01:17:58 +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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Методы для вывода значения в текстовом виде для tab-separated формата.
|
2017-03-13 19:23:56 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
inline typename std::enable_if<std::is_integral<T>::value, void>::type
|
|
|
|
|
writeText(const T & x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
inline typename std::enable_if<std::is_floating_point<T>::value, void>::type
|
|
|
|
|
writeText(const T & x, WriteBuffer & buf) { writeFloatText(x, buf); }
|
|
|
|
|
|
2012-02-26 01:52:43 +00:00
|
|
|
|
inline void writeText(const String & x, WriteBuffer & buf) { writeEscapedString(x, 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); }
|
|
|
|
|
|
2015-05-28 14:08:31 +00:00
|
|
|
|
/// в отличие от метода для std::string
|
|
|
|
|
/// здесь предполагается, что x null-terminated строка.
|
|
|
|
|
inline void writeText(const char * x, WriteBuffer & buf) { writeEscapedString(x, strlen(x), buf); }
|
|
|
|
|
inline void writeText(const char * x, size_t size, WriteBuffer & buf) { writeEscapedString(x, size, buf); }
|
2012-02-26 01:52:43 +00:00
|
|
|
|
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeText(const LocalDate & x, WriteBuffer & buf) { writeDateText(x, buf); }
|
|
|
|
|
inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTimeText(x, buf); }
|
2012-02-26 01:52:43 +00:00
|
|
|
|
|
2016-02-07 08:42:21 +00:00
|
|
|
|
/// Строки, даты, даты-с-временем - в одинарных кавычках с C-style эскейпингом. Числа - без.
|
2017-03-13 19:23:56 +00:00
|
|
|
|
template <typename T>
|
2017-03-13 19:26:31 +00:00
|
|
|
|
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
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-03-13 19:23:56 +00:00
|
|
|
|
inline void writeQuoted(const String & x, WriteBuffer & buf) { writeQuotedString(x, buf); }
|
2012-01-24 16:45:50 +00:00
|
|
|
|
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeQuoted(const LocalDate & x, WriteBuffer & buf)
|
2012-01-24 16:45:50 +00:00
|
|
|
|
{
|
|
|
|
|
writeChar('\'', buf);
|
|
|
|
|
writeDateText(x, buf);
|
|
|
|
|
writeChar('\'', buf);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeQuoted(const LocalDateTime & x, WriteBuffer & buf)
|
2012-01-24 16:45:50 +00:00
|
|
|
|
{
|
|
|
|
|
writeChar('\'', buf);
|
|
|
|
|
writeDateTimeText(x, buf);
|
|
|
|
|
writeChar('\'', buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-07 08:42:21 +00:00
|
|
|
|
/// Строки, даты, даты-с-временем - в двойных кавычках с C-style эскейпингом. Числа - без.
|
2017-03-13 19:23:56 +00:00
|
|
|
|
template <typename T>
|
2017-03-13 19:26:31 +00:00
|
|
|
|
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
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-03-13 19:23:56 +00:00
|
|
|
|
inline void writeDoubleQuoted(const String & x, WriteBuffer & buf) { writeDoubleQuotedString(x, buf); }
|
2012-11-06 13:58:29 +00:00
|
|
|
|
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeDoubleQuoted(const LocalDate & x, WriteBuffer & buf)
|
2012-11-06 13:58:29 +00:00
|
|
|
|
{
|
|
|
|
|
writeChar('"', buf);
|
|
|
|
|
writeDateText(x, buf);
|
|
|
|
|
writeChar('"', buf);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-03 01:17:58 +00:00
|
|
|
|
inline void writeDoubleQuoted(const LocalDateTime & x, WriteBuffer & buf)
|
2012-11-06 13:58:29 +00:00
|
|
|
|
{
|
|
|
|
|
writeChar('"', buf);
|
|
|
|
|
writeDateTimeText(x, buf);
|
|
|
|
|
writeChar('"', buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-07 08:42:21 +00:00
|
|
|
|
/// Строки - в двойных кавычках и с CSV-эскейпингом; даты, даты-с-временем - в двойных кавычках. Числа - без.
|
2017-03-13 19:23:56 +00:00
|
|
|
|
template <typename T>
|
2017-03-13 19:26:31 +00:00
|
|
|
|
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
2017-03-13 19:23:56 +00:00
|
|
|
|
writeCSV(const T & x, WriteBuffer & buf) { writeText(x, buf); }
|
|
|
|
|
|
2016-02-07 08:42:21 +00:00
|
|
|
|
inline void writeCSV(const String & x, WriteBuffer & buf) { writeCSVString<>(x, buf); }
|
|
|
|
|
inline void writeCSV(const LocalDate & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
|
|
|
|
|
inline void writeCSV(const LocalDateTime & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
|
|
|
|
|
|
|
|
|
|
|
2014-01-05 13:40:11 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
void writeBinary(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
size_t size = x.size();
|
|
|
|
|
writeVarUInt(size, buf);
|
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
|
|
|
writeBinary(x[i], buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void writeQuoted(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeChar('[', buf);
|
|
|
|
|
for (size_t i = 0, size = x.size(); i < size; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (i != 0)
|
|
|
|
|
writeChar(',', buf);
|
|
|
|
|
writeQuoted(x[i], buf);
|
|
|
|
|
}
|
|
|
|
|
writeChar(']', buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void writeDoubleQuoted(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeChar('[', buf);
|
|
|
|
|
for (size_t i = 0, size = x.size(); i < size; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (i != 0)
|
|
|
|
|
writeChar(',', buf);
|
|
|
|
|
writeDoubleQuoted(x[i], buf);
|
|
|
|
|
}
|
|
|
|
|
writeChar(']', buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void writeText(const std::vector<T> & x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeQuoted(x, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-05-08 05:42:05 +00:00
|
|
|
|
/// Сериализация эксепшена (чтобы его можно было передать по сети)
|
|
|
|
|
void writeException(const Exception & e, WriteBuffer & buf);
|
|
|
|
|
|
|
|
|
|
|
2013-06-21 20:34:19 +00:00
|
|
|
|
/// Простой для использования метод преобразования чего-либо в строку в текстовом виде.
|
|
|
|
|
template <typename T>
|
|
|
|
|
inline String toString(const T & x)
|
|
|
|
|
{
|
|
|
|
|
String res;
|
|
|
|
|
{
|
|
|
|
|
WriteBufferFromString buf(res);
|
|
|
|
|
writeText(x, buf);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
}
|