TrinityCore
Loading...
Searching...
No Matches
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[std::ptrdiff_t(meta->Type)].get() : FromStringValueConverters[std::ptrdiff_t(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{
405 for (uint32 i = 0; i < _fieldCount; i++)
406 {
407 InitializeDatabaseFieldMetadata(&_fieldMetadata[i], &_fields[i], i, false);
408 auto [itr, success] = _fieldIndexByAlias.try_emplace({ Trinity::DB::FieldLookupByAliasKey::RuntimeInit, _fieldMetadata[i].Alias }, i);
409 ASSERT(success, "Duplicate column alias %s in query for column %s.%s, conflicts with column %s.%s",
410 _fieldMetadata[i].Alias, _fieldMetadata[i].TableName, _fieldMetadata[i].Name, _fieldMetadata[itr->second].TableName, _fieldMetadata[itr->second].Name);
412 }
413}
414
416m_rowCount(rowCount),
417m_rowPosition(0),
418m_fieldCount(fieldCount),
419m_rBind(nullptr),
420m_stmt(stmt),
421m_metadataResult(result)
422{
423 if (!m_metadataResult)
424 return;
425
426 if (m_stmt->bind_result_done)
427 {
428 delete[] m_stmt->bind->length;
429 delete[] m_stmt->bind->is_null;
430 }
431
433
434 //- for future readers wondering where the fuck this is freed - mysql_stmt_bind_result moves pointers to these
435 // from m_rBind to m_stmt->bind and it is later freed by the `if (m_stmt->bind_result_done)` block just above here
436 // MYSQL_STMT lifetime is equal to connection lifetime
437 MySQLBool* m_isNull = new MySQLBool[m_fieldCount];
438 unsigned long* m_length = new unsigned long[m_fieldCount];
439
440 memset(m_isNull, 0, sizeof(MySQLBool) * m_fieldCount);
441 memset(m_rBind, 0, sizeof(MySQLBind) * m_fieldCount);
442 memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);
443
444 //- This is where we store the (entire) resultset
445 if (mysql_stmt_store_result(m_stmt))
446 {
447 TC_LOG_WARN("sql.sql", "{}:mysql_stmt_store_result, cannot bind result from MySQL server. Error: {}", __FUNCTION__, mysql_stmt_error(m_stmt));
448 delete[] m_rBind;
449 delete[] m_isNull;
450 delete[] m_length;
451 return;
452 }
453
454 m_rowCount = mysql_stmt_num_rows(m_stmt);
455
456 //- This is where we prepare the buffer based on metadata
457 MySQLField* field = reinterpret_cast<MySQLField*>(mysql_fetch_fields(m_metadataResult));
460 std::size_t rowSize = 0;
461 for (uint32 i = 0; i < m_fieldCount; ++i)
462 {
463 uint32 size = SizeForType(&field[i]);
464 rowSize += size;
465
466 InitializeDatabaseFieldMetadata(&m_fieldMetadata[i], &field[i], i, true);
467 auto [itr, success] = m_fieldIndexByAlias.try_emplace({ Trinity::DB::FieldLookupByAliasKey::RuntimeInit, m_fieldMetadata[i].Alias }, i);
468 ASSERT(success, "Duplicate column alias %s in query for column %s.%s, conflicts with column %s.%s",
469 m_fieldMetadata[i].Alias, m_fieldMetadata[i].TableName, m_fieldMetadata[i].Name, m_fieldMetadata[itr->second].TableName, m_fieldMetadata[itr->second].Name);
470
471 m_rBind[i].buffer_type = field[i].type;
472 m_rBind[i].buffer_length = size;
473 m_rBind[i].length = &m_length[i];
474 m_rBind[i].is_null = &m_isNull[i];
475 m_rBind[i].error = nullptr;
476 m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
477 }
478
479 char* dataBuffer = new char[rowSize * m_rowCount];
480 for (uint32 i = 0, offset = 0; i < m_fieldCount; ++i)
481 {
482 m_rBind[i].buffer = dataBuffer + offset;
483 offset += m_rBind[i].buffer_length;
484 }
485
486 //- This is where we bind the bind the buffer to the statement
487 if (mysql_stmt_bind_result(m_stmt, m_rBind))
488 {
489 TC_LOG_WARN("sql.sql", "{}:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: {}", __FUNCTION__, mysql_stmt_error(m_stmt));
490 mysql_stmt_free_result(m_stmt);
491 CleanUp();
492 delete[] m_isNull;
493 delete[] m_length;
494 return;
495 }
496
497 m_rows.resize(std::size_t(m_rowCount) * m_fieldCount);
498 while (_NextRow())
499 {
500 for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
501 {
502 m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&m_fieldMetadata[fIndex]);
503
504 unsigned long buffer_length = m_rBind[fIndex].buffer_length;
505 unsigned long fetched_length = *m_rBind[fIndex].length;
506 if (!*m_rBind[fIndex].is_null)
507 {
508 void* buffer = m_stmt->bind[fIndex].buffer;
509 switch (m_rBind[fIndex].buffer_type)
510 {
511 case MYSQL_TYPE_TINY_BLOB:
512 case MYSQL_TYPE_MEDIUM_BLOB:
513 case MYSQL_TYPE_LONG_BLOB:
514 case MYSQL_TYPE_BLOB:
515 case MYSQL_TYPE_STRING:
516 case MYSQL_TYPE_VAR_STRING:
517 // warning - the string will not be null-terminated if there is no space for it in the buffer
518 // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
519 // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
520 // in this case using Field::GetCString will result in garbage
521 // TODO: remove Field::GetCString and use std::string_view in C++17
522 if (fetched_length < buffer_length)
523 *((char*)buffer + fetched_length) = '\0';
524 break;
525 default:
526 break;
527 }
528
529 m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetValue(
530 (char const*)buffer,
531 fetched_length);
532
533 // move buffer pointer to next part
534 m_stmt->bind[fIndex].buffer = (char*)buffer + rowSize;
535 }
536 else
537 {
538 m_rows[std::size_t(m_rowPosition) * m_fieldCount + fIndex].SetValue(
539 nullptr,
540 *m_rBind[fIndex].length);
541 }
542 }
544 }
545 m_rowPosition = 0;
546
548 mysql_stmt_free_result(m_stmt);
549}
550
555
560
562{
563 if (!_result)
564 return false;
565
566 MYSQL_ROW row = mysql_fetch_row(_result);
567 if (!row)
568 {
569 CleanUp();
570 return false;
571 }
572
573 unsigned long* lengths = mysql_fetch_lengths(_result);
574 if (!lengths)
575 {
576 TC_LOG_WARN("sql.sql", "{}:mysql_fetch_lengths, cannot retrieve value lengths. Error {}.", __FUNCTION__, mysql_error(_result->handle));
577 CleanUp();
578 return false;
579 }
580
581 for (uint32 i = 0; i < _fieldCount; i++)
582 _currentRow[i].SetValue(row[i], lengths[i]);
583
584 return true;
585}
586
588{
591 if (++m_rowPosition >= m_rowCount)
592 return false;
593
594 return true;
595}
596
598{
602 return false;
603
604 int retval = mysql_stmt_fetch(m_stmt);
605 return retval == 0 || retval == MYSQL_DATA_TRUNCATED;
606}
607
609{
610 if (_currentRow)
611 {
612 delete [] _currentRow;
613 _currentRow = nullptr;
614 }
615
616 if (_result)
617 {
618 mysql_free_result(_result);
619 _result = nullptr;
620 }
621}
622
624{
626 mysql_free_result(m_metadataResult);
627
628 if (m_rBind)
629 {
630 delete[](char*)m_rBind->buffer;
631 delete[] m_rBind;
632 m_rBind = nullptr;
633 }
634}
635
636Field const& ResultSet::operator[](std::size_t index) const
637{
638 ASSERT(index < std::size_t(_fieldCount));
639 return _currentRow[index];
640}
641
643{
644 auto itr = _fieldIndexByAlias.find(alias);
645 ASSERT(itr != _fieldIndexByAlias.end());
646 return _currentRow[itr->second];
647}
648
650{
651 ASSERT(index < std::size_t(_fieldCount));
652 return _fieldMetadata[index];
653}
654
656{
657 auto itr = _fieldIndexByAlias.find(alias);
658 ASSERT(itr != _fieldIndexByAlias.end());
659 return _fieldMetadata[itr->second];
660}
661
663{
665 return const_cast<Field*>(&m_rows[std::size_t(m_rowPosition) * m_fieldCount]);
666}
667
668Field const& PreparedResultSet::operator[](std::size_t index) const
669{
671 ASSERT(index < std::size_t(m_fieldCount));
672 return m_rows[std::size_t(m_rowPosition) * m_fieldCount + index];
673}
674
676{
678 auto itr = m_fieldIndexByAlias.find(alias);
679 ASSERT(itr != m_fieldIndexByAlias.end());
680 return m_rows[std::size_t(m_rowPosition) * m_fieldCount + itr->second];
681}
682
684{
685 ASSERT(index < std::size_t(m_fieldCount));
686 return m_fieldMetadata[index];
687}
688
690{
691 auto itr = m_fieldIndexByAlias.find(alias);
692 ASSERT(itr != m_fieldIndexByAlias.end());
693 return m_fieldMetadata[itr->second];
694}
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int16_t int16
Definition Define.h:151
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
uint16 flags
std::chrono::system_clock::time_point SystemTimePoint
Definition Duration.h:41
#define ASSERT
Definition Errors.h:80
DatabaseFieldTypes
Definition Field.h:33
#define TC_LOG_WARN(filterType__, message__,...)
Definition Log.h:187
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
Definition MySQLHacks.h:32
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:94
void SetMetadata(QueryResultFieldMetadata const *meta)
Definition Field.cpp:254
Field const & operator[](std::size_t index) const
std::vector< QueryResultFieldMetadata > m_fieldMetadata
MySQLStmt * m_stmt
PreparedResultSet(MySQLStmt *stmt, MySQLResult *result, uint64 rowCount, uint32 fieldCount)
MySQLBind * m_rBind
QueryResultFieldMetadata const & GetFieldMetadata(std::size_t index) const
std::vector< Field > m_rows
Trinity::DB::FieldAliasToIndexMap m_fieldIndexByAlias
Field * Fetch() const
MySQLResult * m_metadataResult
Field metadata, returned by mysql_stmt_result_metadata.
uint32 _fieldCount
Definition QueryResult.h:72
Field * _currentRow
Definition QueryResult.h:71
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:77
std::vector< QueryResultFieldMetadata > _fieldMetadata
Definition QueryResult.h:68
ResultSet(MySQLResult *result, MySQLField *fields, uint64 rowCount, uint32 fieldCount)
Trinity::DB::FieldAliasToIndexMap _fieldIndexByAlias
Definition QueryResult.h:69
MySQLResult * _result
Definition QueryResult.h:76
BaseDatabaseResultValueConverter const * Converter
Definition Field.h:60
DatabaseFieldTypes Type
Definition Field.h:59
char const * Alias
Definition Field.h:56
char const * TableAlias
Definition Field.h:54
char const * TableName
Definition Field.h:53
char const * TypeName
Definition Field.h:57
char const * Name
Definition Field.h:55
struct Trinity::DB::FieldLookupByAliasKey::RuntimeInitTag RuntimeInit