1#pragma once
2
3#include <string.h>
4#include <stdio.h>
5#include <time.h>
6#include <math.h>
7
8#include <string>
9#include <limits>
10
11#include <common/preciseExp10.h>
12#include <common/Types.h>
13#include <common/DateLUT.h>
14
15#include <mysqlxx/Types.h>
16#include <common/LocalDateTime.h>
17
18
19namespace mysqlxx
20{
21
22
23class ResultBase;
24
25
26/** Представляет одно значение, считанное из MySQL.
27 * Объект сам не хранит данные, а является всего лишь обёрткой над парой (const char *, size_t).
28 * Если уничтожить UseQueryResult/StoreQueryResult или Connection,
29 * или считать следующий Row при использовании UseQueryResult, то объект станет некорректным.
30 * Позволяет преобразовать значение (распарсить) в различные типы данных:
31 * - с помощью функций вида getUInt(), getString(), ... (рекомендуется);
32 * - с помощью шаблонной функции get<Type>(), которая специализирована для многих типов (для шаблонного кода);
33 * - шаблонная функция get<Type> работает также для всех типов, у которых есть конструктор из Value
34 * (это сделано для возможности расширения);
35 * - с помощью operator Type() - но этот метод реализован лишь для совместимости и не рекомендуется
36 * к использованию, так как неудобен (часто возникают неоднозначности).
37 *
38 * При ошибке парсинга, выкидывается исключение.
39 * При попытке достать значение, которое равно nullptr, выкидывается исключение
40 * - используйте метод isNull() для проверки.
41 *
42 * Во всех распространённых системах, time_t - это всего лишь typedef от Int64 или Int32.
43 * Для того, чтобы можно было писать row[0].get<time_t>(), ожидая, что значение вида '2011-01-01 00:00:00'
44 * корректно распарсится согласно текущей тайм-зоне, сделано так, что метод getUInt и соответствующие методы get<>()
45 * также умеют парсить дату и дату-время.
46 */
47class Value
48{
49public:
50 /** Параметр res_ используется только для генерации подробной информации в исключениях.
51 * Можно передать NULL - тогда подробной информации в исключениях не будет.
52 */
53 Value(const char * data_, size_t length_, const ResultBase * res_) : m_data(data_), m_length(length_), res(res_)
54 {
55 }
56
57 /// Получить значение bool.
58 bool getBool() const
59 {
60 if (unlikely(isNull()))
61 throwException("Value is NULL");
62
63 return m_length > 0 && m_data[0] != '0';
64 }
65
66 /// Получить беззнаковое целое.
67 UInt64 getUInt() const
68 {
69 if (unlikely(isNull()))
70 throwException("Value is NULL");
71
72 return readUIntText(m_data, m_length);
73 }
74
75 /// Получить целое со знаком или дату или дату-время (в unix timestamp согласно текущей тайм-зоне).
76 Int64 getInt() const
77 {
78 return getIntOrDateTime();
79 }
80
81 /// Получить число с плавающей запятой.
82 double getDouble() const
83 {
84 if (unlikely(isNull()))
85 throwException("Value is NULL");
86
87 return readFloatText(m_data, m_length);
88 }
89
90 /// Получить дату-время (из значения вида '2011-01-01 00:00:00').
91 LocalDateTime getDateTime() const
92 {
93 return LocalDateTime(data(), size());
94 }
95
96 /// Получить дату (из значения вида '2011-01-01' или '2011-01-01 00:00:00').
97 LocalDate getDate() const
98 {
99 return LocalDate(data(), size());
100 }
101
102 /// Получить строку.
103 std::string getString() const
104 {
105 if (unlikely(isNull()))
106 throwException("Value is NULL");
107
108 return std::string(m_data, m_length);
109 }
110
111 /// Является ли NULL.
112 bool isNull() const
113 {
114 return m_data == nullptr;
115 }
116
117 /// Для совместимости (используйте вместо этого метод isNull())
118 bool is_null() const { return isNull(); }
119
120 /** Получить любой поддерживаемый тип (для шаблонного кода).
121 * Поддерживаются основные типы, а также любые типы с конструктором от Value (для удобства расширения).
122 */
123 template <typename T> T get() const;
124
125 /// Для совместимости. Не рекомендуется к использованию, так как неудобен (часто возникают неоднозначности).
126 template <typename T> operator T() const { return get<T>(); }
127
128 const char * data() const { return m_data; }
129 size_t length() const { return m_length; }
130 size_t size() const { return m_length; }
131 bool empty() const { return 0 == m_length; }
132
133private:
134 const char * m_data;
135 size_t m_length;
136 const ResultBase * res;
137
138
139 bool checkDateTime() const
140 {
141 return (m_length == 10 || m_length == 19) && m_data[4] == '-' && m_data[7] == '-';
142 }
143
144
145 time_t getDateTimeImpl() const
146 {
147 const auto & date_lut = DateLUT::instance();
148
149 if (m_length == 10)
150 {
151 return date_lut.makeDate(
152 (m_data[0] - '0') * 1000 + (m_data[1] - '0') * 100 + (m_data[2] - '0') * 10 + (m_data[3] - '0'),
153 (m_data[5] - '0') * 10 + (m_data[6] - '0'),
154 (m_data[8] - '0') * 10 + (m_data[9] - '0'));
155 }
156 else if (m_length == 19)
157 {
158 return date_lut.makeDateTime(
159 (m_data[0] - '0') * 1000 + (m_data[1] - '0') * 100 + (m_data[2] - '0') * 10 + (m_data[3] - '0'),
160 (m_data[5] - '0') * 10 + (m_data[6] - '0'),
161 (m_data[8] - '0') * 10 + (m_data[9] - '0'),
162 (m_data[11] - '0') * 10 + (m_data[12] - '0'),
163 (m_data[14] - '0') * 10 + (m_data[15] - '0'),
164 (m_data[17] - '0') * 10 + (m_data[18] - '0'));
165 }
166 else
167 throwException("Cannot parse DateTime");
168
169 return 0; /// чтобы не было warning-а.
170 }
171
172
173 time_t getDateImpl() const
174 {
175 const auto & date_lut = DateLUT::instance();
176
177 if (m_length == 10 || m_length == 19)
178 {
179 return date_lut.makeDate(
180 (m_data[0] - '0') * 1000 + (m_data[1] - '0') * 100 + (m_data[2] - '0') * 10 + (m_data[3] - '0'),
181 (m_data[5] - '0') * 10 + (m_data[6] - '0'),
182 (m_data[8] - '0') * 10 + (m_data[9] - '0'));
183 }
184 else
185 throwException("Cannot parse Date");
186
187 return 0; /// чтобы не было warning-а.
188 }
189
190
191 Int64 getIntImpl() const
192 {
193 return readIntText(m_data, m_length);
194 }
195
196
197 Int64 getIntOrDateTime() const
198 {
199 if (unlikely(isNull()))
200 throwException("Value is NULL");
201
202 if (checkDateTime())
203 return getDateTimeImpl();
204 else
205 return getIntImpl();
206 }
207
208
209 Int64 getIntOrDate() const
210 {
211 if (unlikely(isNull()))
212 throwException("Value is NULL");
213
214 if (checkDateTime())
215 return getDateImpl();
216 else
217 {
218 const auto & date_lut = DateLUT::instance();
219 return date_lut.toDate(getIntImpl());
220 }
221 }
222
223
224 /// Прочитать беззнаковое целое в простом формате из не-0-terminated строки.
225 UInt64 readUIntText(const char * buf, size_t length) const;
226
227 /// Прочитать знаковое целое в простом формате из не-0-terminated строки.
228 Int64 readIntText(const char * buf, size_t length) const;
229
230 /// Прочитать число с плавающей запятой в простом формате, с грубым округлением, из не-0-terminated строки.
231 double readFloatText(const char * buf, size_t length) const;
232
233 /// Выкинуть исключение с подробной информацией
234 void throwException(const char * text) const;
235};
236
237
238template <> inline bool Value::get<bool >() const { return getBool(); }
239template <> inline char Value::get<char >() const { return getInt(); }
240template <> inline signed char Value::get<signed char >() const { return getInt(); }
241template <> inline unsigned char Value::get<unsigned char >() const { return getUInt(); }
242template <> inline short Value::get<short >() const { return getInt(); }
243template <> inline unsigned short Value::get<unsigned short >() const { return getUInt(); }
244template <> inline int Value::get<int >() const { return getInt(); }
245template <> inline unsigned int Value::get<unsigned int >() const { return getUInt(); }
246template <> inline long Value::get<long >() const { return getInt(); }
247template <> inline unsigned long Value::get<unsigned long >() const { return getUInt(); }
248template <> inline long long Value::get<long long >() const { return getInt(); }
249template <> inline unsigned long long Value::get<unsigned long long >() const { return getUInt(); }
250template <> inline float Value::get<float >() const { return getDouble(); }
251template <> inline double Value::get<double >() const { return getDouble(); }
252template <> inline std::string Value::get<std::string >() const { return getString(); }
253template <> inline LocalDate Value::get<LocalDate >() const { return getDate(); }
254template <> inline LocalDateTime Value::get<LocalDateTime >() const { return getDateTime(); }
255
256template <typename T> inline T Value::get() const { return T(*this); }
257
258
259inline std::ostream & operator<< (std::ostream & ostr, const Value & x)
260{
261 return ostr.write(x.data(), x.size());
262}
263
264
265}
266