ClickHouse/libs/libmysqlxx/include/mysqlxx/Value.h

270 lines
11 KiB
C++
Raw Normal View History

2014-04-08 06:51:53 +00:00
#pragma once
2011-03-03 19:57:34 +00:00
#include <string.h>
#include <stdio.h>
#include <time.h>
2014-02-21 01:57:01 +00:00
#include <math.h>
2011-03-03 19:57:34 +00:00
#include <string>
#include <limits>
#include <common/exp10.h>
2017-04-16 05:40:17 +00:00
#include <common/Types.h>
2015-09-29 19:19:54 +00:00
#include <common/DateLUT.h>
2011-03-03 19:57:34 +00:00
#include <mysqlxx/Types.h>
#include <common/LocalDateTime.h>
2011-03-03 19:57:34 +00:00
2011-03-18 20:26:54 +00:00
/// Обрезать длинный запрос до указанной длины для текста исключения.
#define MYSQLXX_QUERY_PREVIEW_LENGTH 1000
2011-03-03 19:57:34 +00:00
2011-03-18 20:26:54 +00:00
namespace mysqlxx
2011-03-03 19:57:34 +00:00
{
2011-03-18 20:26:54 +00:00
class ResultBase;
/** Представляет одно значение, считанное из MySQL.
* Объект сам не хранит данные, а является всего лишь обёрткой над парой (const char *, size_t).
* Если уничтожить UseQueryResult/StoreQueryResult или Connection,
* или считать следующий Row при использовании UseQueryResult, то объект станет некорректным.
* Позволяет преобразовать значение (распарсить) в различные типы данных:
* - с помощью функций вида getUInt(), getString(), ... (рекомендуется);
* - с помощью шаблонной функции get<Type>(), которая специализирована для многих типов (для шаблонного кода);
* - шаблонная функция get<Type> работает также для всех типов, у которых есть конструктор из Value
2011-03-18 20:26:54 +00:00
* (это сделано для возможности расширения);
* - с помощью operator Type() - но этот метод реализован лишь для совместимости и не рекомендуется
* к использованию, так как неудобен (часто возникают неоднозначности).
*
* При ошибке парсинга, выкидывается исключение.
2014-04-08 07:58:53 +00:00
* При попытке достать значение, которое равно nullptr, выкидывается исключение
2011-03-18 20:26:54 +00:00
* - используйте метод isNull() для проверки.
*
* Во всех распространённых системах, time_t - это всего лишь typedef от Int64 или Int32.
* Для того, чтобы можно было писать row[0].get<time_t>(), ожидая, что значение вида '2011-01-01 00:00:00'
* корректно распарсится согласно текущей тайм-зоне, сделано так, что метод getUInt и соответствующие методы get<>()
* также умеют парсить дату и дату-время.
*/
class Value
2011-03-03 19:57:34 +00:00
{
public:
/** Параметр res_ используется только для генерации подробной информации в исключениях.
* Можно передать NULL - тогда подробной информации в исключениях не будет.
*/
Value(const char * data_, size_t length_, const ResultBase * res_) : m_data(data_), m_length(length_), res(res_)
{
}
/// Получить значение bool.
bool getBool() const
{
if (unlikely(isNull()))
throwException("Value is NULL");
return m_length > 0 && m_data[0] != '0';
}
/// Получить беззнаковое целое.
UInt64 getUInt() const
{
if (unlikely(isNull()))
throwException("Value is NULL");
return readUIntText(m_data, m_length);;
}
/// Получить целое со знаком или дату или дату-время (в unix timestamp согласно текущей тайм-зоне).
Int64 getInt() const
{
return getIntOrDateTime();
}
/// Получить число с плавающей запятой.
double getDouble() const
{
if (unlikely(isNull()))
throwException("Value is NULL");
return readFloatText(m_data, m_length);
}
/// Получить дату-время (из значения вида '2011-01-01 00:00:00').
LocalDateTime getDateTime() const
{
return LocalDateTime(data(), size());
}
/// Получить дату (из значения вида '2011-01-01' или '2011-01-01 00:00:00').
LocalDate getDate() const
{
return LocalDate(data(), size());
}
/// Получить строку.
std::string getString() const
{
if (unlikely(isNull()))
throwException("Value is NULL");
return std::string(m_data, m_length);
}
/// Является ли NULL.
bool isNull() const
{
return m_data == nullptr;
}
/// Для совместимости (используйте вместо этого метод isNull())
bool is_null() const { return isNull(); }
/** Получить любой поддерживаемый тип (для шаблонного кода).
* Поддерживаются основные типы, а также любые типы с конструктором от Value (для удобства расширения).
*/
template <typename T> T get() const;
/// Для совместимости. Не рекомендуется к использованию, так как неудобен (часто возникают неоднозначности).
template <typename T> operator T() const { return get<T>(); }
const char * data() const { return m_data; }
size_t length() const { return m_length; }
size_t size() const { return m_length; }
bool empty() const { return 0 == m_length; }
2011-03-10 20:31:02 +00:00
private:
const char * m_data;
size_t m_length;
const ResultBase * res;
bool checkDateTime() const
{
return (m_length == 10 || m_length == 19) && m_data[4] == '-' && m_data[7] == '-';
}
time_t getDateTimeImpl() const
{
const auto & date_lut = DateLUT::instance();
if (m_length == 10)
{
return date_lut.makeDate(
(m_data[0] - '0') * 1000 + (m_data[1] - '0') * 100 + (m_data[2] - '0') * 10 + (m_data[3] - '0'),
(m_data[5] - '0') * 10 + (m_data[6] - '0'),
(m_data[8] - '0') * 10 + (m_data[9] - '0'));
}
else if (m_length == 19)
{
return date_lut.makeDateTime(
(m_data[0] - '0') * 1000 + (m_data[1] - '0') * 100 + (m_data[2] - '0') * 10 + (m_data[3] - '0'),
(m_data[5] - '0') * 10 + (m_data[6] - '0'),
(m_data[8] - '0') * 10 + (m_data[9] - '0'),
(m_data[11] - '0') * 10 + (m_data[12] - '0'),
(m_data[14] - '0') * 10 + (m_data[15] - '0'),
(m_data[17] - '0') * 10 + (m_data[18] - '0'));
}
else
throwException("Cannot parse DateTime");
return 0; /// чтобы не было warning-а.
}
time_t getDateImpl() const
{
const auto & date_lut = DateLUT::instance();
if (m_length == 10 || m_length == 19)
{
return date_lut.makeDate(
(m_data[0] - '0') * 1000 + (m_data[1] - '0') * 100 + (m_data[2] - '0') * 10 + (m_data[3] - '0'),
(m_data[5] - '0') * 10 + (m_data[6] - '0'),
(m_data[8] - '0') * 10 + (m_data[9] - '0'));
}
else
throwException("Cannot parse Date");
return 0; /// чтобы не было warning-а.
}
Int64 getIntImpl() const
{
return readIntText(m_data, m_length);;
}
Int64 getIntOrDateTime() const
{
if (unlikely(isNull()))
throwException("Value is NULL");
if (checkDateTime())
return getDateTimeImpl();
else
return getIntImpl();
}
Int64 getIntOrDate() const
{
if (unlikely(isNull()))
throwException("Value is NULL");
if (checkDateTime())
return getDateImpl();
else
{
const auto & date_lut = DateLUT::instance();
return date_lut.toDate(getIntImpl());
}
}
/// Прочитать беззнаковое целое в простом формате из не-0-terminated строки.
UInt64 readUIntText(const char * buf, size_t length) const;
/// Прочитать знаковое целое в простом формате из не-0-terminated строки.
Int64 readIntText(const char * buf, size_t length) const;
/// Прочитать число с плавающей запятой в простом формате, с грубым округлением, из не-0-terminated строки.
double readFloatText(const char * buf, size_t length) const;
/// Выкинуть исключение с подробной информацией
void throwException(const char * text) const;
2011-03-03 19:57:34 +00:00
};
2017-04-16 05:40:17 +00:00
template <> inline bool Value::get<bool >() const { return getBool(); }
template <> inline char Value::get<char >() const { return getInt(); }
template <> inline signed char Value::get<signed char >() const { return getInt(); }
template <> inline unsigned char Value::get<unsigned char >() const { return getUInt(); }
2017-04-16 05:40:17 +00:00
template <> inline short Value::get<short >() const { return getInt(); }
template <> inline unsigned short Value::get<unsigned short >() const { return getUInt(); }
template <> inline int Value::get<int >() const { return getInt(); }
template <> inline unsigned int Value::get<unsigned int >() const { return getUInt(); }
template <> inline long Value::get<long >() const { return getInt(); }
template <> inline unsigned long Value::get<unsigned long >() const { return getUInt(); }
template <> inline long long Value::get<long long >() const { return getInt(); }
template <> inline unsigned long long Value::get<unsigned long long >() const { return getUInt(); }
template <> inline float Value::get<float >() const { return getDouble(); }
template <> inline double Value::get<double >() const { return getDouble(); }
template <> inline std::string Value::get<std::string >() const { return getString(); }
template <> inline LocalDate Value::get<LocalDate >() const { return getDate(); }
template <> inline LocalDateTime Value::get<LocalDateTime >() const { return getDateTime(); }
2011-03-04 20:58:19 +00:00
2017-04-16 05:40:17 +00:00
template <typename T> inline T Value::get() const { return T(*this); }
2011-03-05 20:47:46 +00:00
2011-03-04 20:58:19 +00:00
inline std::ostream & operator<< (std::ostream & ostr, const Value & x)
2011-03-03 19:57:34 +00:00
{
return ostr.write(x.data(), x.size());
2011-03-03 19:57:34 +00:00
}
}