TrinityCore
QueryResult.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "QueryResult.h"
19#include "Errors.h"
20#include "Field.h"
22#include "Log.h"
23#include "MySQLHacks.h"
24#include "MySQLWorkaround.h"
25#include <chrono>
26#include <cstring>
27
28namespace
29{
30static uint32 SizeForType(MYSQL_FIELD* field)
31{
32 switch (field->type)
33 {
34 case MYSQL_TYPE_NULL:
35 return 0;
36 case MYSQL_TYPE_TINY:
37 return 1;
38 case MYSQL_TYPE_YEAR:
39 case MYSQL_TYPE_SHORT:
40 return 2;
41 case MYSQL_TYPE_INT24:
42 case MYSQL_TYPE_LONG:
43 case MYSQL_TYPE_FLOAT:
44 return 4;
45 case MYSQL_TYPE_DOUBLE:
46 case MYSQL_TYPE_LONGLONG:
47 case MYSQL_TYPE_BIT:
48 return 8;
49
50 case MYSQL_TYPE_TIMESTAMP:
51 case MYSQL_TYPE_DATE:
52 case MYSQL_TYPE_TIME:
53 case MYSQL_TYPE_DATETIME:
54 return sizeof(MYSQL_TIME);
55
56 case MYSQL_TYPE_TINY_BLOB:
57 case MYSQL_TYPE_MEDIUM_BLOB:
58 case MYSQL_TYPE_LONG_BLOB:
59 case MYSQL_TYPE_BLOB:
60 case MYSQL_TYPE_STRING:
61 case MYSQL_TYPE_VAR_STRING:
62 return field->max_length + 1;
63
64 case MYSQL_TYPE_DECIMAL:
65 case MYSQL_TYPE_NEWDECIMAL:
66 return 64;
67
68 case MYSQL_TYPE_GEOMETRY:
69 /*
70 Following types are not sent over the wire:
71 MYSQL_TYPE_ENUM:
72 MYSQL_TYPE_SET:
73 */
74 default:
75 TC_LOG_WARN("sql.sql", "SQL::SizeForType(): invalid field type {}", uint32(field->type));
76 return 0;
77 }
78}
79
80DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type, uint32 flags)
81{
82 switch (type)
83 {
84 case MYSQL_TYPE_NULL:
86 case MYSQL_TYPE_TINY:
87 return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt8 : DatabaseFieldTypes::Int8;
88 case MYSQL_TYPE_YEAR:
89 case MYSQL_TYPE_SHORT:
91 case MYSQL_TYPE_INT24:
92 case MYSQL_TYPE_LONG:
94 case MYSQL_TYPE_LONGLONG:
95 case MYSQL_TYPE_BIT:
97 case MYSQL_TYPE_FLOAT:
99 case MYSQL_TYPE_DOUBLE:
101 case MYSQL_TYPE_DECIMAL:
102 case MYSQL_TYPE_NEWDECIMAL:
104 case MYSQL_TYPE_TIMESTAMP:
105 case MYSQL_TYPE_DATE:
106 case MYSQL_TYPE_DATETIME:
108 case MYSQL_TYPE_TIME:
110 case MYSQL_TYPE_TINY_BLOB:
111 case MYSQL_TYPE_MEDIUM_BLOB:
112 case MYSQL_TYPE_LONG_BLOB:
113 case MYSQL_TYPE_BLOB:
114 case MYSQL_TYPE_STRING:
115 case MYSQL_TYPE_VAR_STRING:
117 default:
118 TC_LOG_WARN("sql.sql", "MysqlTypeToFieldType(): invalid field type {}", uint32(type));
119 break;
120 }
121
123}
124
125static char const* FieldTypeToString(enum_field_types type, uint32 flags)
126{
127 switch (type)
128 {
129 case MYSQL_TYPE_BIT: return "BIT";
130 case MYSQL_TYPE_BLOB: return "BLOB";
131 case MYSQL_TYPE_DATE: return "DATE";
132 case MYSQL_TYPE_DATETIME: return "DATETIME";
133 case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL";
134 case MYSQL_TYPE_DECIMAL: return "DECIMAL";
135 case MYSQL_TYPE_DOUBLE: return "DOUBLE";
136 case MYSQL_TYPE_ENUM: return "ENUM";
137 case MYSQL_TYPE_FLOAT: return "FLOAT";
138 case MYSQL_TYPE_GEOMETRY: return "GEOMETRY";
139 case MYSQL_TYPE_INT24: return (flags & UNSIGNED_FLAG) ? "UNSIGNED INT24" : "INT24";
140 case MYSQL_TYPE_LONG: return (flags & UNSIGNED_FLAG) ? "UNSIGNED LONG" : "LONG";
141 case MYSQL_TYPE_LONGLONG: return (flags & UNSIGNED_FLAG) ? "UNSIGNED LONGLONG" : "LONGLONG";
142 case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB";
143 case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB";
144 case MYSQL_TYPE_NEWDATE: return "NEWDATE";
145 case MYSQL_TYPE_NULL: return "NULL";
146 case MYSQL_TYPE_SET: return "SET";
147 case MYSQL_TYPE_SHORT: return (flags & UNSIGNED_FLAG) ? "UNSIGNED SHORT" : "SHORT";
148 case MYSQL_TYPE_STRING: return "STRING";
149 case MYSQL_TYPE_TIME: return "TIME";
150 case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP";
151 case MYSQL_TYPE_TINY: return (flags & UNSIGNED_FLAG) ? "UNSIGNED TINY" : "TINY";
152 case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB";
153 case MYSQL_TYPE_VAR_STRING: return "VAR_STRING";
154 case MYSQL_TYPE_YEAR: return "YEAR";
155 default: return "-Unknown-";
156 }
157}
158
159template <typename>
160class FromStringToMYSQL_TIME
161{
162public:
163 static MYSQL_TIME GetDatabaseValue(char const* data, uint32 size)
164 {
165 MYSQL_TIME result = {};
166 if (!data || !size)
167 {
168 result.time_type = MYSQL_TIMESTAMP_NONE;
169 return result;
170 }
171
172 std::string_view in(data, size);
173
174 size_t firstSeparatorIndex = in.find_first_of(":-");
175 if (firstSeparatorIndex == std::string_view::npos)
176 {
177 result.time_type = MYSQL_TIMESTAMP_NONE;
178 return result;
179 }
180
181 char firstSeparator = in[firstSeparatorIndex];
182
183 auto parseNextComponent = [&](uint32& value, char requiredSeparator = '\0') -> bool
184 {
185 std::from_chars_result parseResult = std::from_chars(in.data(), in.data() + in.size(), value);
186 if (parseResult.ec != std::errc())
187 return false;
188
189 in.remove_prefix(parseResult.ptr - in.data());
190 if (requiredSeparator)
191 {
192 if (in.empty() || in[0] != requiredSeparator)
193 return false;
194
195 in.remove_prefix(1);
196 }
197
198 return true;
199 };
200
201 uint32 yearOrHours = 0;
202 uint32 monthOrMinutes = 0;
203 uint32 dayOrSeconds = 0;
204 if (!parseNextComponent(yearOrHours, firstSeparator)
205 || !parseNextComponent(monthOrMinutes, firstSeparator)
206 || !parseNextComponent(dayOrSeconds))
207 {
208 result.time_type = MYSQL_TIMESTAMP_ERROR;
209 return result;
210 }
211
212 if (firstSeparator == ':')
213 {
214 if (!in.empty())
215 {
216 result.time_type = MYSQL_TIMESTAMP_ERROR;
217 return result;
218 }
219
220 // time
221 result.hour = yearOrHours;
222 result.minute = monthOrMinutes;
223 result.second = dayOrSeconds;
224 result.time_type = MYSQL_TIMESTAMP_TIME;
225 }
226 else
227 {
228 if (in.empty())
229 {
230 // date
231 result.year = yearOrHours;
232 result.month = monthOrMinutes;
233 result.day = dayOrSeconds;
234 result.time_type = MYSQL_TIMESTAMP_DATE;
235 return result;
236 }
237
238 // date+time
239 if (in[0] != ' ')
240 {
241 result.time_type = MYSQL_TIMESTAMP_ERROR;
242 return result;
243 }
244
245 in.remove_prefix(1);
246
247 uint32 hours = 0;
248 uint32 minutes = 0;
249 uint32 seconds = 0;
250 if (!parseNextComponent(hours, ':')
251 || !parseNextComponent(minutes, ':')
252 || !parseNextComponent(seconds))
253 {
254 result.time_type = MYSQL_TIMESTAMP_ERROR;
255 return result;
256 }
257
258 uint32 microseconds = 0;
259 if (!in.empty())
260 {
261 if (in[0] != '.')
262 {
263 result.time_type = MYSQL_TIMESTAMP_ERROR;
264 return result;
265 }
266
267 in.remove_prefix(1);
268 if (!parseNextComponent(microseconds))
269 {
270 result.time_type = MYSQL_TIMESTAMP_ERROR;
271 return result;
272 }
273
274 if (!in.empty())
275 {
276 result.time_type = MYSQL_TIMESTAMP_ERROR;
277 return result;
278 }
279 }
280
281 result.year = yearOrHours;
282 result.month = monthOrMinutes;
283 result.day = dayOrSeconds;
284 result.hour = hours;
285 result.minute = minutes;
286 result.second = seconds;
287 result.second_part = microseconds;
288 result.time_type = MYSQL_TIMESTAMP_DATETIME;
289 }
290
291 return result;
292 }
293
294 static char const* GetStringValue(char const* data)
295 {
296 return data;
297 }
298};
299
300template<template<typename> typename ToDatabaseTypeConverter>
301class DateResultValueConverter : public BaseDatabaseResultValueConverter
302{
303 uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; }
304 int8 GetInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt8", meta); return 0; }
305 uint16 GetUInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt16", meta); return 0; }
306 int16 GetInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt16", meta); return 0; }
307 uint32 GetUInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt32", meta); return 0; }
308 int32 GetInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt32", meta); return 0; }
309 uint64 GetUInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt64", meta); return 0; }
310 int64 GetInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt64", meta); return 0; }
311 float GetFloat(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetFloat", meta); return 0.0f; }
312 double GetDouble(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDouble", meta); return 0.0; }
313
314 SystemTimePoint GetDate(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override
315 {
316 using namespace std::chrono;
317 MYSQL_TIME source = ToDatabaseTypeConverter<MYSQL_TIME>::GetDatabaseValue(data, size);
318 switch (source.time_type)
319 {
320 case MYSQL_TIMESTAMP_DATE:
321 return sys_days(year(source.year) / month(source.month) / day(source.day));
322 case MYSQL_TIMESTAMP_DATETIME:
323 return sys_days(year(source.year) / month(source.month) / day(source.day))
324 + hours(source.hour)
325 + minutes(source.minute)
326 + seconds(source.second)
327 + microseconds(source.second_part);
328 default:
329 break;
330 }
331
332 LogTruncation("Field::GetDate", meta);
333 return SystemTimePoint();
334 }
335
336 char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override
337 {
338 char const* result = ToDatabaseTypeConverter<MYSQL_TIME>::GetStringValue(data);
339 if (data && !result)
340 LogTruncation("Field::GetCString", meta);
341 return result;
342 }
343};
344
345std::unique_ptr<BaseDatabaseResultValueConverter> const FromStringValueConverters[15] =
346{
347 nullptr,
348 std::make_unique<PrimitiveResultValueConverter<uint8, FromStringToDatabaseTypeConverter>>(),
350 std::make_unique<PrimitiveResultValueConverter<uint16, FromStringToDatabaseTypeConverter>>(),
352 std::make_unique<PrimitiveResultValueConverter<uint32, FromStringToDatabaseTypeConverter>>(),
354 std::make_unique<PrimitiveResultValueConverter<uint64, FromStringToDatabaseTypeConverter>>(),
356 std::make_unique<PrimitiveResultValueConverter<float, FromStringToDatabaseTypeConverter>>(),
358 std::make_unique<PrimitiveResultValueConverter<double, FromStringToDatabaseTypeConverter>>(),
359 std::make_unique<DateResultValueConverter<FromStringToMYSQL_TIME>>(),
360 std::make_unique<NotImplementedResultValueConverter>(), // DatabaseFieldTypes::Time
361 std::make_unique<StringResultValueConverter>()
362};
363
364std::unique_ptr<BaseDatabaseResultValueConverter> const BinaryValueConverters[15] =
365{
366 nullptr,
367 std::make_unique<PrimitiveResultValueConverter<uint8, FromBinaryToDatabaseTypeConverter>>(),
369 std::make_unique<PrimitiveResultValueConverter<uint16, FromBinaryToDatabaseTypeConverter>>(),
371 std::make_unique<PrimitiveResultValueConverter<uint32, FromBinaryToDatabaseTypeConverter>>(),
373 std::make_unique<PrimitiveResultValueConverter<uint64, FromBinaryToDatabaseTypeConverter>>(),
375 std::make_unique<PrimitiveResultValueConverter<float, FromBinaryToDatabaseTypeConverter>>(),
377 std::make_unique<PrimitiveResultValueConverter<double, FromStringToDatabaseTypeConverter>>(), // always sent as string
378 std::make_unique<DateResultValueConverter<FromBinaryToDatabaseTypeConverter>>(),
379 std::make_unique<NotImplementedResultValueConverter>(), // DatabaseFieldTypes::Time
380 std::make_unique<StringResultValueConverter>()
381};
382
383void InitializeDatabaseFieldMetadata(QueryResultFieldMetadata* meta, MySQLField const* field, uint32 fieldIndex, bool binaryProtocol)
384{
385 meta->TableName = field->org_table;
386 meta->TableAlias = field->table;
387 meta->Name = field->org_name;
388 meta->Alias = field->name;
389 meta->TypeName = FieldTypeToString(field->type, field->flags);
390 meta->Index = fieldIndex;
391 meta->Type = MysqlTypeToFieldType(field->type, field->flags);
392 meta->Converter = binaryProtocol ? BinaryValueConverters[AsUnderlyingType(meta->Type)].get() : FromStringValueConverters[AsUnderlyingType(meta->Type)].get();
393}
394}
395
396ResultSet::ResultSet(MySQLResult* result, MySQLField* fields, uint64 rowCount, uint32 fieldCount) :
397_rowCount(rowCount),
398_fieldCount(fieldCount),
399_result(result),
400_fields(fields)
401{
404 for (uint32 i = 0; i < _fieldCount; i++)
405 {
406 InitializeDatabaseFieldMetadata(&_fieldMetadata[i], &_fields[i], i, false);
408 }
409}
410
412m_rowCount(rowCount),
413m_rowPosition(0),
414m_fieldCount(fieldCount),
415m_rBind(nullptr),
416m_stmt(stmt),
417m_metadataResult(result)
418{
419 if (!m_metadataResult)
420 return;
421
422 if (m_stmt->bind_result_done)
423 {
424 delete[] m_stmt->bind->length;
425 delete[] m_stmt->bind->is_null;
426 }
427
429
430 //- for future readers wondering where the fuck this is freed - mysql_stmt_bind_result moves pointers to these
431 // from m_rBind to m_stmt->bind and it is later freed by the `if (m_stmt->bind_result_done)` block just above here
432 // MYSQL_STMT lifetime is equal to connection lifetime
433 MySQLBool* m_isNull = new MySQLBool[m_fieldCount];
434 unsigned long* m_length = new unsigned long[m_fieldCount];
435
436 memset(m_isNull, 0, sizeof(MySQLBool) * m_fieldCount);
437 memset(m_rBind, 0, sizeof(MySQLBind) * m_fieldCount);
438 memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);
439
440 //- This is where we store the (entire) resultset
441 if (mysql_stmt_store_result(m_stmt))
442 {
443 TC_LOG_WARN("sql.sql", "{}:mysql_stmt_store_result, cannot bind result from MySQL server. Error: {}", __FUNCTION__, mysql_stmt_error(m_stmt));
444 delete[] m_rBind;
445 delete[] m_isNull;
446 delete[] m_length;
447 return;
448 }
449
450 m_rowCount = mysql_stmt_num_rows(m_stmt);
451
452 //- This is where we prepare the buffer based on metadata
453 MySQLField* field = reinterpret_cast<MySQLField*>(mysql_fetch_fields(m_metadataResult));
455 std::size_t rowSize = 0;
456 for (uint32 i = 0; i < m_fieldCount; ++i)
457 {
458 uint32 size = SizeForType(&field[i]);
459 rowSize += size;
460
461 InitializeDatabaseFieldMetadata(&m_fieldMetadata[i], &field[i], i, true);
462
463 m_rBind[i].buffer_type = field[i].type;
464 m_rBind[i].buffer_length = size;
465 m_rBind[i].length = &m_length[i];
466 m_rBind[i].is_null = &m_isNull[i];
467 m_rBind[i].error = nullptr;
468 m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
469 }
470
471 char* dataBuffer = new char[rowSize * m_rowCount];
472 for (uint32 i = 0, offset = 0; i < m_fieldCount; ++i)
473 {
474 m_rBind[i].buffer = dataBuffer + offset;
475 offset += m_rBind[i].buffer_length;
476 }
477
478 //- This is where we bind the bind the buffer to the statement
479 if (mysql_stmt_bind_result(m_stmt, m_rBind))
480 {
481 TC_LOG_WARN("sql.sql", "{}:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: {}", __FUNCTION__, mysql_stmt_error(m_stmt));
482 mysql_stmt_free_result(m_stmt);
483 CleanUp();
484 delete[] m_isNull;
485 delete[] m_length;
486 return;
487 }
488
489 m_rows.resize(std::size_t(m_rowCount) * m_fieldCount);
490 while (_NextRow())
491 {
492 for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
493 {
494 m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&m_fieldMetadata[fIndex]);
495
496 unsigned long buffer_length = m_rBind[fIndex].buffer_length;
497 unsigned long fetched_length = *m_rBind[fIndex].length;
498 if (!*m_rBind[fIndex].is_null)
499 {
500 void* buffer = m_stmt->bind[fIndex].buffer;
501 switch (m_rBind[fIndex].buffer_type)
502 {
503 case MYSQL_TYPE_TINY_BLOB:
504 case MYSQL_TYPE_MEDIUM_BLOB:
505 case MYSQL_TYPE_LONG_BLOB:
506 case MYSQL_TYPE_BLOB:
507 case MYSQL_TYPE_STRING:
508 case MYSQL_TYPE_VAR_STRING:
509 // warning - the string will not be null-terminated if there is no space for it in the buffer
510 // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
511 // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
512 // in this case using Field::GetCString will result in garbage
513 // TODO: remove Field::GetCString and use std::string_view in C++17
514 if (fetched_length < buffer_length)
515 *((char*)buffer + fetched_length) = '\0';
516 break;
517 default:
518 break;
519 }
520
521 m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetValue(
522 (char const*)buffer,
523 fetched_length);
524
525 // move buffer pointer to next part
526 m_stmt->bind[fIndex].buffer = (char*)buffer + rowSize;
527 }
528 else
529 {
530 m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetValue(
531 nullptr,
532 *m_rBind[fIndex].length);
533 }
534 }
536 }
537 m_rowPosition = 0;
538
540 mysql_stmt_free_result(m_stmt);
541}
542
544{
545 CleanUp();
546}
547
549{
550 CleanUp();
551}
552
554{
555 if (!_result)
556 return false;
557
558 MYSQL_ROW row = mysql_fetch_row(_result);
559 if (!row)
560 {
561 CleanUp();
562 return false;
563 }
564
565 unsigned long* lengths = mysql_fetch_lengths(_result);
566 if (!lengths)
567 {
568 TC_LOG_WARN("sql.sql", "{}:mysql_fetch_lengths, cannot retrieve value lengths. Error {}.", __FUNCTION__, mysql_error(_result->handle));
569 CleanUp();
570 return false;
571 }
572
573 for (uint32 i = 0; i < _fieldCount; i++)
574 _currentRow[i].SetValue(row[i], lengths[i]);
575
576 return true;
577}
578
580{
583 if (++m_rowPosition >= m_rowCount)
584 return false;
585
586 return true;
587}
588
590{
594 return false;
595
596 int retval = mysql_stmt_fetch(m_stmt);
597 return retval == 0 || retval == MYSQL_DATA_TRUNCATED;
598}
599
601{
602 if (_currentRow)
603 {
604 delete [] _currentRow;
605 _currentRow = nullptr;
606 }
607
608 if (_result)
609 {
610 mysql_free_result(_result);
611 _result = nullptr;
612 }
613}
614
616{
618 mysql_free_result(m_metadataResult);
619
620 if (m_rBind)
621 {
622 delete[](char*)m_rBind->buffer;
623 delete[] m_rBind;
624 m_rBind = nullptr;
625 }
626}
627
628Field const& ResultSet::operator[](std::size_t index) const
629{
630 ASSERT(index < std::size_t(_fieldCount));
631 return _currentRow[index];
632}
633
635{
636 ASSERT(index < std::size_t(_fieldCount));
637 return _fieldMetadata[index];
638}
639
641{
643 return const_cast<Field*>(&m_rows[std::size_t(m_rowPosition) * m_fieldCount]);
644}
645
646Field const& PreparedResultSet::operator[](std::size_t index) const
647{
649 ASSERT(index < std::size_t(m_fieldCount));
650 return m_rows[std::size_t(m_rowPosition) * m_fieldCount + index];
651}
652
654{
655 ASSERT(index < std::size_t(m_fieldCount));
656 return m_fieldMetadata[index];
657}
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int16_t int16
Definition: Define.h:139
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::system_clock::time_point SystemTimePoint
Definition: Duration.h:37
#define ASSERT
Definition: Errors.h:68
DatabaseFieldTypes
Definition: Field.h:32
#define TC_LOG_WARN(filterType__, message__,...)
Definition: Log.h:185
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
Definition: MySQLHacks.h:32
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:528
virtual uint64 GetUInt64(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual SystemTimePoint GetDate(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual float GetFloat(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual double GetDouble(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual uint8 GetUInt8(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual int64 GetInt64(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual uint16 GetUInt16(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual int32 GetInt32(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual uint32 GetUInt32(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual int8 GetInt8(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
virtual int16 GetInt16(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
static void LogTruncation(char const *getter, QueryResultFieldMetadata const *meta)
virtual char const * GetCString(char const *data, uint32 size, QueryResultFieldMetadata const *meta) const =0
Class used to access individual fields of database query result.
Definition: Field.h:93
void SetMetadata(QueryResultFieldMetadata const *meta)
Definition: Field.cpp:172
Field const & operator[](std::size_t index) const
std::vector< QueryResultFieldMetadata > m_fieldMetadata
Definition: QueryResult.h:71
MySQLStmt * m_stmt
Definition: QueryResult.h:79
uint64 m_rowPosition
Definition: QueryResult.h:74
PreparedResultSet(MySQLStmt *stmt, MySQLResult *result, uint64 rowCount, uint32 fieldCount)
MySQLBind * m_rBind
Definition: QueryResult.h:78
QueryResultFieldMetadata const & GetFieldMetadata(std::size_t index) const
std::vector< Field > m_rows
Definition: QueryResult.h:72
Field * Fetch() const
MySQLResult * m_metadataResult
Field metadata, returned by mysql_stmt_result_metadata.
Definition: QueryResult.h:80
uint32 _fieldCount
Definition: QueryResult.h:44
Field * _currentRow
Definition: QueryResult.h:43
void CleanUp()
QueryResultFieldMetadata const & GetFieldMetadata(std::size_t index) const
bool NextRow()
Field const & operator[](std::size_t index) const
MySQLField * _fields
Definition: QueryResult.h:49
std::vector< QueryResultFieldMetadata > _fieldMetadata
Definition: QueryResult.h:41
ResultSet(MySQLResult *result, MySQLField *fields, uint64 rowCount, uint32 fieldCount)
MySQLResult * _result
Definition: QueryResult.h:48
constexpr std::size_t size()
Definition: UpdateField.h:769
BaseDatabaseResultValueConverter const * Converter
Definition: Field.h:59
DatabaseFieldTypes Type
Definition: Field.h:58
char const * Alias
Definition: Field.h:55
char const * TableAlias
Definition: Field.h:53
char const * TableName
Definition: Field.h:52
char const * TypeName
Definition: Field.h:56
char const * Name
Definition: Field.h:54