2010-06-04 18:25:25 +00:00
|
|
|
|
#ifndef DBMS_COMMON_WRITEHELPERS_H
|
|
|
|
|
#define DBMS_COMMON_WRITEHELPERS_H
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
#include <Yandex/DateLUT.h>
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
#include <DB/Core/Types.h>
|
|
|
|
|
#include <DB/Core/Exception.h>
|
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/IO/WriteBuffer.h>
|
|
|
|
|
|
2010-06-07 17:14:13 +00:00
|
|
|
|
#define WRITE_HELPERS_DEFAULT_FLOAT_PRECISION 6U
|
|
|
|
|
/// 20 цифр и знак
|
|
|
|
|
#define WRITE_HELPERS_MAX_INT_WIDTH 21U
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/// Функции-помошники для форматированной записи
|
|
|
|
|
|
|
|
|
|
inline void writeChar(char x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
buf.nextIfAtEnd();
|
|
|
|
|
*buf.position() = x;
|
|
|
|
|
++buf.position();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-07-04 18:22:37 +00:00
|
|
|
|
/// Запись числа в native формате
|
|
|
|
|
template <typename T>
|
2011-08-09 17:24:17 +00:00
|
|
|
|
inline void writeBinary(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>
|
|
|
|
|
inline void writeIntBinary(T & x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeBinary(x, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
inline void writeFloatBinary(T & x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeBinary(x, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-04 18:22:37 +00:00
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
void writeIntText(T x, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
char tmp[WRITE_HELPERS_MAX_INT_WIDTH];
|
2010-06-07 17:14:13 +00:00
|
|
|
|
bool negative = false;
|
|
|
|
|
|
|
|
|
|
if (x == 0)
|
|
|
|
|
{
|
|
|
|
|
writeChar('0', buf);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x < 0)
|
|
|
|
|
{
|
|
|
|
|
x = -x;
|
|
|
|
|
negative = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char * pos;
|
|
|
|
|
for (pos = tmp + WRITE_HELPERS_MAX_INT_WIDTH - 1; x != 0; --pos)
|
|
|
|
|
{
|
|
|
|
|
*pos = '0' + x % 10;
|
|
|
|
|
x /= 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (negative)
|
|
|
|
|
*pos = '-';
|
|
|
|
|
else
|
|
|
|
|
++pos;
|
|
|
|
|
|
|
|
|
|
buf.write(pos, tmp + WRITE_HELPERS_MAX_INT_WIDTH - pos);
|
2010-06-04 18:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void writeFloatText(T x, WriteBuffer & buf, unsigned precision = WRITE_HELPERS_DEFAULT_FLOAT_PRECISION)
|
|
|
|
|
{
|
|
|
|
|
unsigned size = precision + 10;
|
|
|
|
|
char tmp[size]; /// знаки, +0.0e+123\0
|
|
|
|
|
int res = std::snprintf(tmp, size, "%.*g", precision, x);
|
|
|
|
|
|
|
|
|
|
if (res >= static_cast<int>(size) || res <= 0)
|
|
|
|
|
throw Exception("Cannot print float or double number", ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER);
|
|
|
|
|
|
2010-06-04 18:34:25 +00:00
|
|
|
|
buf.write(tmp, res);
|
2010-06-04 18:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-09 17:24:17 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
void writeText(T x, WriteBuffer & buf);
|
|
|
|
|
|
|
|
|
|
template <> inline void writeText<UInt8> (UInt8 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<UInt16> (UInt16 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<UInt32> (UInt32 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<UInt64> (UInt64 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<Int8> (Int8 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<Int16> (Int16 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<Int32> (Int32 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<Int64> (Int64 x, WriteBuffer & buf) { writeIntText(x, buf); }
|
|
|
|
|
template <> inline void writeText<Float32> (Float32 x, WriteBuffer & buf) { writeFloatText(x, buf); }
|
|
|
|
|
template <> inline void writeText<Float64> (Float64 x, WriteBuffer & buf) { writeFloatText(x, buf); }
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
inline void writeString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
buf.write(s.data(), s.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// предполагается, что строка в оперативке хранится непрерывно, и \0-terminated.
|
|
|
|
|
void writeEscapedString(const String & s, WriteBuffer & buf);
|
|
|
|
|
|
|
|
|
|
inline void writeQuotedString(const String & s, WriteBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
writeChar('\'', buf);
|
|
|
|
|
writeEscapedString(s, buf);
|
|
|
|
|
writeChar('\'', buf);
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 18:54:18 +00:00
|
|
|
|
/// Совместимо с JSON.
|
|
|
|
|
void writeDoubleQuotedString(const String & s, WriteBuffer & buf);
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
/// в формате YYYY-MM-DD
|
|
|
|
|
inline void writeDateText(Yandex::DayNum_t date, WriteBuffer & buf)
|
|
|
|
|
{
|
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
|
|
|
|
|
|
|
|
|
const Yandex::DateLUT::Values & values = Yandex::DateLUTSingleton::instance().getValues(date);
|
|
|
|
|
|
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-05-05 19:10:17 +00:00
|
|
|
|
|
|
|
|
|
buf.write(s, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-08-07 02:08:22 +00:00
|
|
|
|
/// в формате YYYY-MM-DD HH:MM:SS, согласно текущему часовому поясу
|
|
|
|
|
inline void writeDateTimeText(time_t datetime, WriteBuffer & buf)
|
|
|
|
|
{
|
2011-08-07 03:42:36 +00:00
|
|
|
|
char s[19] = {'0', '0', '0', '0', '-', '0', '0', '-', '0', '0', ' ', '0', '0', ':', '0', '0', ':', '0', '0'};
|
|
|
|
|
|
|
|
|
|
if (unlikely(datetime > DATE_LUT_MAX || datetime == 0))
|
|
|
|
|
{
|
|
|
|
|
buf.write(s, 19);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
|
|
|
|
Yandex::DateLUTSingleton & date_lut = Yandex::DateLUTSingleton::instance();
|
|
|
|
|
const Yandex::DateLUT::Values & values = date_lut.getValues(datetime);
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
UInt8 hour = date_lut.toHourInaccurate(datetime);
|
|
|
|
|
UInt8 minute = date_lut.toMinute(datetime);
|
|
|
|
|
UInt8 second = date_lut.toSecond(datetime);
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|