2011-10-30 05:19:41 +00:00
|
|
|
|
#pragma once
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2010-06-01 13:35:09 +00:00
|
|
|
|
#include <cstring>
|
2010-06-01 13:41:51 +00:00
|
|
|
|
#include <limits>
|
2010-05-28 19:13:55 +00:00
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
2011-10-24 19:03:38 +00:00
|
|
|
|
#include <tr1/type_traits>
|
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
#include <Yandex/DateLUT.h>
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
|
#include <mysqlxx/Date.h>
|
|
|
|
|
#include <mysqlxx/DateTime.h>
|
|
|
|
|
|
2010-05-28 19:13:55 +00:00
|
|
|
|
#include <DB/Core/Types.h>
|
|
|
|
|
#include <DB/Core/Exception.h>
|
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
#include <DB/IO/ReadBuffer.h>
|
2011-08-19 18:31:14 +00:00
|
|
|
|
#include <DB/IO/VarInt.h>
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_MAX_STRING_SIZE 0x00FFFFFFULL
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2010-06-01 13:35:09 +00:00
|
|
|
|
/// Функции-помошники для форматированного чтения
|
|
|
|
|
|
|
|
|
|
static inline char parseEscapeSequence(char c)
|
|
|
|
|
{
|
|
|
|
|
switch(c)
|
2010-05-28 19:13:55 +00:00
|
|
|
|
{
|
2010-06-01 13:35:09 +00:00
|
|
|
|
case 'b':
|
|
|
|
|
return '\b';
|
|
|
|
|
case 'f':
|
|
|
|
|
return '\f';
|
|
|
|
|
case 'n':
|
|
|
|
|
return '\n';
|
|
|
|
|
case 'r':
|
|
|
|
|
return '\r';
|
|
|
|
|
case 't':
|
|
|
|
|
return '\t';
|
|
|
|
|
case '0':
|
|
|
|
|
return '\0';
|
|
|
|
|
default:
|
|
|
|
|
return c;
|
2010-05-28 19:13:55 +00:00
|
|
|
|
}
|
2010-06-01 13:35:09 +00:00
|
|
|
|
}
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
static inline void throwReadAfterEOF()
|
|
|
|
|
{
|
|
|
|
|
throw Exception("Attempt to read after eof", ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-07-04 18:22:37 +00:00
|
|
|
|
/// Чтение числа в native формате
|
|
|
|
|
template <typename T>
|
2011-08-09 17:24:17 +00:00
|
|
|
|
inline void readBinary(T & x, ReadBuffer & buf)
|
2011-07-04 18:22:37 +00:00
|
|
|
|
{
|
|
|
|
|
buf.readStrict(reinterpret_cast<char *>(&x), sizeof(x));
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-09 17:24:17 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
inline void readIntBinary(T & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
readBinary(x, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
inline void readFloatBinary(T & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
readBinary(x, buf);
|
|
|
|
|
}
|
2011-07-04 18:22:37 +00:00
|
|
|
|
|
2011-08-19 18:31:14 +00:00
|
|
|
|
|
|
|
|
|
inline void readStringBinary(std::string & s, DB::ReadBuffer & buf, size_t MAX_STRING_SIZE = DEFAULT_MAX_STRING_SIZE)
|
|
|
|
|
{
|
|
|
|
|
size_t size = 0;
|
|
|
|
|
DB::readVarUInt(size, buf);
|
|
|
|
|
|
|
|
|
|
if (size > MAX_STRING_SIZE)
|
|
|
|
|
throw Poco::Exception("Too large string size.");
|
|
|
|
|
|
|
|
|
|
s.resize(size);
|
|
|
|
|
buf.readStrict(const_cast<char *>(s.data()), size);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-22 17:39:13 +00:00
|
|
|
|
template <> inline void readBinary(std::string & s, DB::ReadBuffer & buf) { readStringBinary(s, buf); }
|
|
|
|
|
|
2011-08-19 18:31:14 +00:00
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
inline void readChar(char & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
if (!buf.eof())
|
|
|
|
|
{
|
|
|
|
|
x = *buf.position();
|
|
|
|
|
++buf.position();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throwReadAfterEOF();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 14:12:28 +00:00
|
|
|
|
void assertString(const char * s, ReadBuffer & buf);
|
2010-06-01 13:35:09 +00:00
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
|
|
|
|
|
|
inline void readBoolText(bool & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
char tmp = '0';
|
|
|
|
|
readChar(tmp, buf);
|
|
|
|
|
x = tmp != '0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-01 13:35:09 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
void readIntText(T & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
bool negative = false;
|
|
|
|
|
x = 0;
|
2010-06-04 18:25:25 +00:00
|
|
|
|
if (buf.eof())
|
|
|
|
|
throwReadAfterEOF();
|
|
|
|
|
|
2010-06-01 13:35:09 +00:00
|
|
|
|
while (!buf.eof())
|
|
|
|
|
{
|
|
|
|
|
switch (*buf.position())
|
2010-05-28 19:13:55 +00:00
|
|
|
|
{
|
2010-06-01 13:35:09 +00:00
|
|
|
|
case '+':
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
2011-10-24 19:03:38 +00:00
|
|
|
|
if (std::tr1::is_signed<T>::value)
|
|
|
|
|
negative = true;
|
|
|
|
|
else
|
|
|
|
|
return;
|
2010-06-01 13:35:09 +00:00
|
|
|
|
break;
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
case '2':
|
|
|
|
|
case '3':
|
|
|
|
|
case '4':
|
|
|
|
|
case '5':
|
|
|
|
|
case '6':
|
|
|
|
|
case '7':
|
|
|
|
|
case '8':
|
|
|
|
|
case '9':
|
|
|
|
|
x *= 10;
|
|
|
|
|
x += *buf.position() - '0';
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (negative)
|
2010-05-28 19:13:55 +00:00
|
|
|
|
x = -x;
|
2010-06-01 13:35:09 +00:00
|
|
|
|
return;
|
2010-05-28 19:13:55 +00:00
|
|
|
|
}
|
2010-06-01 13:35:09 +00:00
|
|
|
|
++buf.position();
|
2010-05-28 19:13:55 +00:00
|
|
|
|
}
|
2010-06-01 13:35:09 +00:00
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// грубо
|
|
|
|
|
template <typename T>
|
|
|
|
|
void readFloatText(T & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
bool negative = false;
|
|
|
|
|
x = 0;
|
|
|
|
|
bool after_point = false;
|
|
|
|
|
double power_of_ten = 1;
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2010-06-04 18:25:25 +00:00
|
|
|
|
if (buf.eof())
|
|
|
|
|
throwReadAfterEOF();
|
|
|
|
|
|
2010-06-01 13:35:09 +00:00
|
|
|
|
while (!buf.eof())
|
2010-05-28 19:13:55 +00:00
|
|
|
|
{
|
2010-06-01 13:35:09 +00:00
|
|
|
|
switch (*buf.position())
|
2010-05-28 19:13:55 +00:00
|
|
|
|
{
|
2010-06-01 13:35:09 +00:00
|
|
|
|
case '+':
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
negative = true;
|
|
|
|
|
break;
|
|
|
|
|
case '.':
|
|
|
|
|
after_point = true;
|
|
|
|
|
break;
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
case '2':
|
|
|
|
|
case '3':
|
|
|
|
|
case '4':
|
|
|
|
|
case '5':
|
|
|
|
|
case '6':
|
|
|
|
|
case '7':
|
|
|
|
|
case '8':
|
|
|
|
|
case '9':
|
|
|
|
|
if (after_point)
|
|
|
|
|
{
|
|
|
|
|
power_of_ten /= 10;
|
|
|
|
|
x += (*buf.position() - '0') * power_of_ten;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x *= 10;
|
|
|
|
|
x += *buf.position() - '0';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'E':
|
2010-05-28 19:13:55 +00:00
|
|
|
|
{
|
2010-06-01 13:35:09 +00:00
|
|
|
|
++buf.position();
|
|
|
|
|
Int32 exponent = 0;
|
|
|
|
|
readIntText(exponent, buf);
|
|
|
|
|
if (exponent == 0)
|
|
|
|
|
{
|
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (exponent > 0)
|
|
|
|
|
{
|
|
|
|
|
for (Int32 i = 0; i < exponent; ++i)
|
2010-05-28 19:13:55 +00:00
|
|
|
|
x *= 10;
|
2010-06-01 13:35:09 +00:00
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
2010-05-28 19:13:55 +00:00
|
|
|
|
return;
|
2010-06-01 13:35:09 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (Int32 i = 0; i < exponent; ++i)
|
|
|
|
|
x /= 10;
|
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-05-28 19:13:55 +00:00
|
|
|
|
}
|
2010-06-01 13:35:09 +00:00
|
|
|
|
case 'i':
|
|
|
|
|
++buf.position();
|
|
|
|
|
assertString("nf", buf);
|
|
|
|
|
x = std::numeric_limits<T>::infinity();
|
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
|
|
|
|
return;
|
|
|
|
|
case 'I':
|
|
|
|
|
++buf.position();
|
|
|
|
|
assertString("NF", buf);
|
|
|
|
|
x = std::numeric_limits<T>::infinity();
|
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
|
|
|
|
return;
|
|
|
|
|
case 'n':
|
|
|
|
|
++buf.position();
|
|
|
|
|
assertString("an", buf);
|
|
|
|
|
x = std::numeric_limits<T>::quiet_NaN();
|
|
|
|
|
return;
|
|
|
|
|
case 'N':
|
|
|
|
|
++buf.position();
|
|
|
|
|
assertString("AN", buf);
|
|
|
|
|
x = std::numeric_limits<T>::quiet_NaN();
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
2010-05-28 19:13:55 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2010-06-01 13:35:09 +00:00
|
|
|
|
++buf.position();
|
2010-05-28 19:13:55 +00:00
|
|
|
|
}
|
2010-06-01 13:35:09 +00:00
|
|
|
|
if (negative)
|
|
|
|
|
x = -x;
|
|
|
|
|
}
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2011-08-09 17:24:17 +00:00
|
|
|
|
|
2010-06-01 13:35:09 +00:00
|
|
|
|
/// грубо; всё до '\n' или '\t'
|
2010-06-01 14:12:28 +00:00
|
|
|
|
void readString(String & s, ReadBuffer & buf);
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2010-06-01 14:12:28 +00:00
|
|
|
|
void readEscapedString(String & s, ReadBuffer & buf);
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2010-06-01 14:12:28 +00:00
|
|
|
|
void readQuotedString(String & s, ReadBuffer & buf);
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2011-06-15 18:54:18 +00:00
|
|
|
|
void readDoubleQuotedString(String & s, ReadBuffer & buf);
|
|
|
|
|
|
2011-11-01 17:57:37 +00:00
|
|
|
|
void readBackQuotedString(String & s, ReadBuffer & buf);
|
|
|
|
|
|
2010-05-28 19:13:55 +00:00
|
|
|
|
|
2011-05-05 19:10:17 +00:00
|
|
|
|
/// в формате YYYY-MM-DD
|
|
|
|
|
inline void readDateText(Yandex::DayNum_t & date, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
char s[10];
|
2011-05-27 18:46:29 +00:00
|
|
|
|
size_t size = buf.read(s, 10);
|
|
|
|
|
if (10 != size)
|
|
|
|
|
{
|
|
|
|
|
s[size] = 0;
|
|
|
|
|
throw Exception(std::string("Cannot parse date ") + s, ErrorCodes::CANNOT_PARSE_DATE);
|
|
|
|
|
}
|
2011-05-05 19:10:17 +00:00
|
|
|
|
|
|
|
|
|
UInt16 year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
|
|
|
|
|
UInt8 month = (s[5] - '0') * 10 + (s[6] - '0');
|
|
|
|
|
UInt8 day = (s[8] - '0') * 10 + (s[9] - '0');
|
|
|
|
|
|
|
|
|
|
date = Yandex::DateLUTSingleton::instance().makeDayNum(year, month, day);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
|
inline void readDateText(mysqlxx::Date & date, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
char s[10];
|
|
|
|
|
size_t size = buf.read(s, 10);
|
|
|
|
|
if (10 != size)
|
|
|
|
|
{
|
|
|
|
|
s[size] = 0;
|
|
|
|
|
throw Exception(std::string("Cannot parse date ") + s, ErrorCodes::CANNOT_PARSE_DATE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
date.year((s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0'));
|
|
|
|
|
date.month((s[5] - '0') * 10 + (s[6] - '0'));
|
|
|
|
|
date.day((s[8] - '0') * 10 + (s[9] - '0'));
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
|
|
|
|
/// в формате YYYY-MM-DD HH:MM:SS, согласно текущему часовому поясу
|
|
|
|
|
inline void readDateTimeText(time_t & datetime, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
char s[19];
|
|
|
|
|
size_t size = buf.read(s, 19);
|
|
|
|
|
if (19 != size)
|
|
|
|
|
{
|
|
|
|
|
s[size] = 0;
|
|
|
|
|
throw Exception(std::string("Cannot parse datetime ") + s, ErrorCodes::CANNOT_PARSE_DATETIME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UInt16 year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
|
|
|
|
|
UInt8 month = (s[5] - '0') * 10 + (s[6] - '0');
|
|
|
|
|
UInt8 day = (s[8] - '0') * 10 + (s[9] - '0');
|
|
|
|
|
|
|
|
|
|
UInt8 hour = (s[11] - '0') * 10 + (s[12] - '0');
|
|
|
|
|
UInt8 minute = (s[14] - '0') * 10 + (s[15] - '0');
|
|
|
|
|
UInt8 second = (s[17] - '0') * 10 + (s[18] - '0');
|
|
|
|
|
|
|
|
|
|
datetime = Yandex::DateLUTSingleton::instance().makeDateTime(year, month, day, hour, minute, second);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-21 10:09:22 +00:00
|
|
|
|
inline void readDateTimeText(mysqlxx::DateTime & datetime, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
char s[19];
|
|
|
|
|
size_t size = buf.read(s, 19);
|
|
|
|
|
if (19 != size)
|
|
|
|
|
{
|
|
|
|
|
s[size] = 0;
|
|
|
|
|
throw Exception(std::string("Cannot parse datetime ") + s, ErrorCodes::CANNOT_PARSE_DATETIME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
datetime.year((s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0'));
|
|
|
|
|
datetime.month((s[5] - '0') * 10 + (s[6] - '0'));
|
|
|
|
|
datetime.day((s[8] - '0') * 10 + (s[9] - '0'));
|
|
|
|
|
|
|
|
|
|
datetime.hour((s[11] - '0') * 10 + (s[12] - '0'));
|
|
|
|
|
datetime.minute((s[14] - '0') * 10 + (s[15] - '0'));
|
|
|
|
|
datetime.second((s[17] - '0') * 10 + (s[18] - '0'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void readText(T & x, ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
/// Переношу ошибку в рантайм, так как метод требуется для компиляции DBObject-ов
|
|
|
|
|
throw Exception("Method readText is not implemented for this type.", ErrorCodes::NOT_IMPLEMENTED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <> inline void readText<UInt8> (UInt8 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<UInt16> (UInt16 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<UInt32> (UInt32 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<UInt64> (UInt64 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<Int8> (Int8 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<Int16> (Int16 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<Int32> (Int32 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<Int64> (Int64 & x, ReadBuffer & buf) { readIntText(x, buf); }
|
|
|
|
|
template <> inline void readText<Float32> (Float32 & x, ReadBuffer & buf) { readFloatText(x, buf); }
|
|
|
|
|
template <> inline void readText<Float64> (Float64 & x, ReadBuffer & buf) { readFloatText(x, buf); }
|
|
|
|
|
template <> inline void readText<String> (String & x, ReadBuffer & buf) { readEscapedString(x, buf); }
|
|
|
|
|
template <> inline void readText<bool> (bool & x, ReadBuffer & buf) { readBoolText(x, buf); }
|
|
|
|
|
|
|
|
|
|
template <> inline void readText<mysqlxx::Date> (mysqlxx::Date & x, ReadBuffer & buf) { readDateText(x, buf); }
|
|
|
|
|
template <> inline void readText<mysqlxx::DateTime> (mysqlxx::DateTime & x, ReadBuffer & buf) { readDateTimeText(x, buf); }
|
|
|
|
|
|
2011-08-07 02:08:22 +00:00
|
|
|
|
|
2011-10-30 05:19:41 +00:00
|
|
|
|
/// Пропустить пробельные символы.
|
|
|
|
|
inline void skipWhitespaceIfAny(ReadBuffer & buf)
|
|
|
|
|
{
|
|
|
|
|
while (!buf.eof()
|
|
|
|
|
&& (*buf.position() == ' '
|
|
|
|
|
|| *buf.position() == '\t'
|
|
|
|
|
|| *buf.position() == '\n'
|
|
|
|
|
|| *buf.position() == '\r'
|
|
|
|
|
|| *buf.position() == '\f'))
|
|
|
|
|
++buf.position();
|
2010-05-28 19:13:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-30 05:19:41 +00:00
|
|
|
|
}
|