@@ -303,6 +303,13 @@ static bool qIsBlob(int t)
303303 || t == MYSQL_TYPE_LONG_BLOB;
304304}
305305
306+ static bool qIsTimeOrDate (int t)
307+ {
308+ // *not* MYSQL_TYPE_TIME because its range is bigger than QTime
309+ // (see above)
310+ return t == MYSQL_TYPE_DATE || t == MYSQL_TYPE_DATETIME || t == MYSQL_TYPE_TIMESTAMP;
311+ }
312+
306313static bool qIsInteger (int t)
307314{
308315 return t == QMetaType::Char || t == QMetaType::UChar
@@ -354,6 +361,8 @@ bool QMYSQLResultPrivate::bindInValues()
354361 // after mysql_stmt_exec() in QMYSQLResult::exec()
355362 bind->buffer_length = f.bufLength = 0 ;
356363 hasBlobs = true ;
364+ } else if (qIsTimeOrDate (fieldInfo->type )) {
365+ bind->buffer_length = f.bufLength = sizeof (MYSQL_TIME);
357366 } else if (qIsInteger (f.type .id ())) {
358367 bind->buffer_length = f.bufLength = 8 ;
359368 } else {
@@ -364,8 +373,10 @@ bool QMYSQLResultPrivate::bindInValues()
364373 bind->length = &f.bufLength ;
365374 bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0 ;
366375
367- char *field = new char [bind->buffer_length + 1 ]{};
376+ char *field = bind-> buffer_length ? new char [bind->buffer_length + 1 ]{} : nullptr ;
368377 bind->buffer = f.outField = field;
378+ if (qIsTimeOrDate (fieldInfo->type ))
379+ new (field) MYSQL_TIME;
369380
370381 ++i;
371382 }
@@ -416,9 +427,11 @@ void QMYSQLResult::cleanup()
416427 d->meta = 0 ;
417428 }
418429
419- int i;
420- for (i = 0 ; i < d->fields .count (); ++i)
421- delete[] d->fields [i].outField ;
430+ for (const auto &field : qAsConst (d->fields )) {
431+ if (qIsTimeOrDate (field.myField ->type ))
432+ reinterpret_cast <MYSQL_TIME *>(field.outField )->~MYSQL_TIME ();
433+ delete[] field.outField ;
434+ }
422435
423436 if (d->outBinds ) {
424437 delete[] d->outBinds ;
@@ -557,6 +570,20 @@ QVariant QMYSQLResult::data(int field)
557570 else if (f.type .id () == QMetaType::Char)
558571 return variant.toInt ();
559572 return variant;
573+ } else if (qIsTimeOrDate (f.myField ->type ) && f.bufLength == sizeof (MYSQL_TIME)) {
574+ auto t = reinterpret_cast <const MYSQL_TIME *>(f.outField );
575+ QDate date;
576+ QTime time;
577+ if (f.type .id () != QMetaType::QTime)
578+ date = QDate (t->year , t->month , t->day );
579+ if (f.type .id () != QMetaType::QDate)
580+ time = QTime (t->hour , t->minute , t->second , t->second_part / 1000 );
581+ if (f.type .id () == QMetaType::QDateTime)
582+ return QDateTime (date, time);
583+ else if (f.type .id () == QMetaType::QDate)
584+ return date;
585+ else
586+ return time;
560587 }
561588
562589 if (f.type .id () != QMetaType::QByteArray)
@@ -1485,7 +1512,21 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
14851512 } else {
14861513 qWarning (" QMYSQLDriver::formatValue: Database not open" );
14871514 }
1488- // fall through
1515+ Q_FALLTHROUGH ();
1516+ case QMetaType::QDateTime:
1517+ if (QDateTime dt = field.value ().toDateTime (); dt.isValid ()) {
1518+ // MySQL format doesn't like the "Z" at the end, but does allow
1519+ // "+00:00" starting in version 8.0.19. However, if we got here,
1520+ // it's because the MySQL server is too old for prepared queries
1521+ // in the first place, so it won't understand timezones either.
1522+ // Besides, MYSQL_TIME does not support timezones, so match it.
1523+ r = QLatin1Char (' \' ' ) +
1524+ dt.date ().toString (Qt::ISODate) +
1525+ QLatin1Char (' T' ) +
1526+ dt.time ().toString (Qt::ISODate) +
1527+ QLatin1Char (' \' ' );
1528+ }
1529+ break ;
14891530 default :
14901531 r = QSqlDriver::formatValue (field, trimStrings);
14911532 }
0 commit comments