30static uint32 SizeForType(MYSQL_FIELD* field)
39 case MYSQL_TYPE_SHORT:
41 case MYSQL_TYPE_INT24:
43 case MYSQL_TYPE_FLOAT:
45 case MYSQL_TYPE_DOUBLE:
46 case MYSQL_TYPE_LONGLONG:
50 case MYSQL_TYPE_TIMESTAMP:
53 case MYSQL_TYPE_DATETIME:
54 return sizeof(MYSQL_TIME);
56 case MYSQL_TYPE_TINY_BLOB:
57 case MYSQL_TYPE_MEDIUM_BLOB:
58 case MYSQL_TYPE_LONG_BLOB:
60 case MYSQL_TYPE_STRING:
61 case MYSQL_TYPE_VAR_STRING:
62 return field->max_length + 1;
64 case MYSQL_TYPE_DECIMAL:
65 case MYSQL_TYPE_NEWDECIMAL:
68 case MYSQL_TYPE_GEOMETRY:
75 TC_LOG_WARN(
"sql.sql",
"SQL::SizeForType(): invalid field type {}",
uint32(field->type));
89 case MYSQL_TYPE_SHORT:
91 case MYSQL_TYPE_INT24:
94 case MYSQL_TYPE_LONGLONG:
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:
118 TC_LOG_WARN(
"sql.sql",
"MysqlTypeToFieldType(): invalid field type {}",
uint32(type));
125static char const* FieldTypeToString(enum_field_types type,
uint32 flags)
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-";
160class FromStringToMYSQL_TIME
163 static MYSQL_TIME GetDatabaseValue(
char const* data,
uint32 size)
165 MYSQL_TIME result = {};
168 result.time_type = MYSQL_TIMESTAMP_NONE;
172 std::string_view in(data,
size);
174 size_t firstSeparatorIndex = in.find_first_of(
":-");
175 if (firstSeparatorIndex == std::string_view::npos)
177 result.time_type = MYSQL_TIMESTAMP_NONE;
181 char firstSeparator = in[firstSeparatorIndex];
183 auto parseNextComponent = [&](
uint32& value,
char requiredSeparator =
'\0') ->
bool
185 std::from_chars_result parseResult = std::from_chars(in.data(), in.data() + in.size(), value);
186 if (parseResult.ec != std::errc())
189 in.remove_prefix(parseResult.ptr - in.data());
190 if (requiredSeparator)
192 if (in.empty() || in[0] != requiredSeparator)
202 uint32 monthOrMinutes = 0;
204 if (!parseNextComponent(yearOrHours, firstSeparator)
205 || !parseNextComponent(monthOrMinutes, firstSeparator)
206 || !parseNextComponent(dayOrSeconds))
208 result.time_type = MYSQL_TIMESTAMP_ERROR;
212 if (firstSeparator ==
':')
216 result.time_type = MYSQL_TIMESTAMP_ERROR;
221 result.hour = yearOrHours;
222 result.minute = monthOrMinutes;
223 result.second = dayOrSeconds;
224 result.time_type = MYSQL_TIMESTAMP_TIME;
231 result.year = yearOrHours;
232 result.month = monthOrMinutes;
233 result.day = dayOrSeconds;
234 result.time_type = MYSQL_TIMESTAMP_DATE;
241 result.time_type = MYSQL_TIMESTAMP_ERROR;
250 if (!parseNextComponent(hours,
':')
251 || !parseNextComponent(minutes,
':')
252 || !parseNextComponent(seconds))
254 result.time_type = MYSQL_TIMESTAMP_ERROR;
263 result.time_type = MYSQL_TIMESTAMP_ERROR;
268 if (!parseNextComponent(microseconds))
270 result.time_type = MYSQL_TIMESTAMP_ERROR;
276 result.time_type = MYSQL_TIMESTAMP_ERROR;
281 result.year = yearOrHours;
282 result.month = monthOrMinutes;
283 result.day = dayOrSeconds;
285 result.minute = minutes;
286 result.second = seconds;
287 result.second_part = microseconds;
288 result.time_type = MYSQL_TIMESTAMP_DATETIME;
294 static char const* GetStringValue(
char const* data)
300template<
template<
typename>
typename ToDatabaseTypeConverter>
316 using namespace std::chrono;
317 MYSQL_TIME source = ToDatabaseTypeConverter<MYSQL_TIME>::GetDatabaseValue(data,
size);
318 switch (source.time_type)
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))
325 + minutes(source.minute)
326 + seconds(source.second)
327 + microseconds(source.second_part);
338 char const* result = ToDatabaseTypeConverter<MYSQL_TIME>::GetStringValue(data);
345std::unique_ptr<BaseDatabaseResultValueConverter>
const FromStringValueConverters[15] =
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>(),
361 std::make_unique<StringResultValueConverter>()
364std::unique_ptr<BaseDatabaseResultValueConverter>
const BinaryValueConverters[15] =
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>>(),
378 std::make_unique<DateResultValueConverter<FromBinaryToDatabaseTypeConverter>>(),
379 std::make_unique<NotImplementedResultValueConverter>(),
380 std::make_unique<StringResultValueConverter>()
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);
398_fieldCount(fieldCount),
414m_fieldCount(fieldCount),
417m_metadataResult(result)
422 if (
m_stmt->bind_result_done)
424 delete[]
m_stmt->bind->length;
425 delete[]
m_stmt->bind->is_null;
434 unsigned long* m_length =
new unsigned long[
m_fieldCount];
438 memset(m_length, 0,
sizeof(
unsigned long) *
m_fieldCount);
441 if (mysql_stmt_store_result(
m_stmt))
443 TC_LOG_WARN(
"sql.sql",
"{}:mysql_stmt_store_result, cannot bind result from MySQL server. Error: {}", __FUNCTION__, mysql_stmt_error(
m_stmt));
455 std::size_t rowSize = 0;
461 InitializeDatabaseFieldMetadata(&
m_fieldMetadata[i], &field[i], i,
true);
463 m_rBind[i].buffer_type = field[i].type;
465 m_rBind[i].length = &m_length[i];
466 m_rBind[i].is_null = &m_isNull[i];
468 m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
471 char* dataBuffer =
new char[rowSize *
m_rowCount];
474 m_rBind[i].buffer = dataBuffer + offset;
475 offset +=
m_rBind[i].buffer_length;
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);
496 unsigned long buffer_length =
m_rBind[fIndex].buffer_length;
497 unsigned long fetched_length = *
m_rBind[fIndex].length;
500 void* buffer =
m_stmt->bind[fIndex].buffer;
501 switch (
m_rBind[fIndex].buffer_type)
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:
514 if (fetched_length < buffer_length)
515 *((
char*)buffer + fetched_length) =
'\0';
526 m_stmt->bind[fIndex].buffer = (
char*)buffer + rowSize;
540 mysql_stmt_free_result(
m_stmt);
558 MYSQL_ROW row = mysql_fetch_row(
_result);
565 unsigned long* lengths = mysql_fetch_lengths(
_result);
568 TC_LOG_WARN(
"sql.sql",
"{}:mysql_fetch_lengths, cannot retrieve value lengths. Error {}.", __FUNCTION__, mysql_error(
_result->handle));
596 int retval = mysql_stmt_fetch(
m_stmt);
597 return retval == 0 || retval == MYSQL_DATA_TRUNCATED;
622 delete[](
char*)
m_rBind->buffer;
std::chrono::system_clock::time_point SystemTimePoint
#define TC_LOG_WARN(filterType__, message__,...)
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
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.
void SetMetadata(QueryResultFieldMetadata const *meta)
Field const & operator[](std::size_t index) const
std::vector< QueryResultFieldMetadata > m_fieldMetadata
PreparedResultSet(MySQLStmt *stmt, MySQLResult *result, uint64 rowCount, uint32 fieldCount)
QueryResultFieldMetadata const & GetFieldMetadata(std::size_t index) const
std::vector< Field > m_rows
MySQLResult * m_metadataResult
Field metadata, returned by mysql_stmt_result_metadata.
QueryResultFieldMetadata const & GetFieldMetadata(std::size_t index) const
Field const & operator[](std::size_t index) const
std::vector< QueryResultFieldMetadata > _fieldMetadata
ResultSet(MySQLResult *result, MySQLField *fields, uint64 rowCount, uint32 fieldCount)
constexpr std::size_t size()