7#include <QtCore/qtimezone.h>
9#include <firebird/impl/blr.h>
19using namespace Firebird;
23using namespace Qt::StringLiterals;
29 IUtil *util = master->getUtilInterface();
31 util->formatStatus(buf,
sizeof(buf), status);
32 return QString::fromUtf8(buf);
36
37
38
39
40
41
42
45 const QString msg = fbErrorString(master, status);
46 const ISC_LONG sqlcode = isc_sqlcode(status->getErrors());
47 const QString code = (sqlcode != -1 && sqlcode != 0)
48 ? QString::number(sqlcode) : QString();
50 return QSqlError({}, msg, type, code);
55 static const char *typeNames[] = {
56 "NoError",
"ConnectionError",
"StatementError",
"TransactionError",
"UnknownError"
58 const int ti =
std::clamp(
static_cast<
int>(err.type()), 0,
59 static_cast<
int>(
std::size(typeNames)) - 1);
60 const QString code = err.nativeErrorCode();
61 const QString text = err.databaseText().isEmpty() ? err.driverText() : err.databaseText();
62 return QString::fromLatin1(
"[%1, %2] %3").arg(QLatin1StringView(typeNames[ti]), code, text);
66
67
68
69
70
71
72
73
75 Firebird::ITransaction *&tr,
TxnEnd end)
91
92
93
94
95
99 const unsigned char tpb[] = {
100 isc_tpb_version3, isc_tpb_write, isc_tpb_read_committed, isc_tpb_rec_version,
101 static_cast<
unsigned char>(wait == TxnWait::Wait ? isc_tpb_wait : isc_tpb_nowait)
103 return att->startTransaction(&st,
sizeof(tpb), tpb);
112 case blr_cstring:
return QMetaType::QString;
114 case blr_long:
return hasScale ? QMetaType::Double : QMetaType::Int;
116 case blr_int64:
return hasScale ? QMetaType::Double : QMetaType::LongLong;
121 case blr_dec128:
return QMetaType::Double;
122 case blr_int128:
return QMetaType::QString;
123 case blr_sql_date:
return QMetaType::QDate;
124 case blr_sql_time:
return QMetaType::QTime;
125 case blr_sql_time_tz:
return QMetaType::QDateTime;
127 case blr_timestamp_tz:
return QMetaType::QDateTime;
128 case blr_bool:
return QMetaType::Bool;
130
131 default:
return QMetaType::QString;
141
142 if (fbBaseType(fbType) == SQL_INT128)
143 return QMetaType::QString;
144 return QMetaType::Double;
148 case SQL_LONG:
return QMetaType::Int;
149 case SQL_INT64:
return QMetaType::LongLong;
150 case SQL_INT128:
return QMetaType::QString;
151 case SQL_FLOAT:
return QMetaType::Double;
152 case SQL_DOUBLE:
return QMetaType::Double;
154 case SQL_DEC34:
return QMetaType::QString;
155 case SQL_BOOLEAN:
return QMetaType::Bool;
156 case SQL_TYPE_DATE:
return QMetaType::QDate;
157 case SQL_TYPE_TIME:
return QMetaType::QTime;
159 case SQL_TIMESTAMP_TZ:
160 case SQL_TIME_TZ:
return QMetaType::QDateTime;
161 case SQL_BLOB:
return QMetaType::QByteArray;
162 case SQL_ARRAY:
return QMetaType::QVariantList;
164 case SQL_VARYING:
return QMetaType::QString;
166 qCWarning(lcFirebird,
"fbTypeToQt: unknown Firebird type %d", fbType);
167 return QMetaType::QString;
173#ifndef QSQL_HAS_INT128
178 ThrowStatusWrapper st(status);
180 master->getUtilInterface()->getInt128(&st)->toString(
181 &st,
reinterpret_cast<
const FB_I128 *>(slot), scale,
sizeof(buf), buf);
182 return QString::fromLatin1(buf);
188 IMaster *master, IStatus *status, QString &errorText)
190#ifdef QSQL_HAS_INT128
193 qinternalint128 v = 0;
194 if (!QtPrivate::sqlScaledFromVariant(val, scale, &v, &errorText))
197
198
199 static_assert(std::is_same_v<ISC_UINT64, quint64>,
200 "the FB_I128 words are written through quint64 pointers");
202 QtPrivate::sqlInt128ToWords(v, &raw.fb_data[0], &raw.fb_data[1]);
203 std::memcpy(slot, &raw,
sizeof(raw));
207
208
209
210
211
212 const QByteArray strVal = QtPrivate::sqlNumericInputString(val);
213 if (!QtPrivate::sqlIsPlainDecimal(strVal)) {
214 errorText = QtPrivate::sqlCannotEncodeError(strVal, scale);
218 ThrowStatusWrapper st(status);
219 master->getUtilInterface()->getInt128(&st)->fromString(
220 &st, scale, strVal.constData(),
reinterpret_cast<FB_I128 *>(slot));
222 }
catch (
const FbException &) {
224 errorText = QtPrivate::sqlIsIntegralVariant(val.typeId())
225 ? QtPrivate::sqlOutOfRangeError(val, scale)
226 : QtPrivate::sqlCannotEncodeError(strVal, scale);
233 IMaster *master, IStatus *status, QString *overflowText)
235#ifdef QSQL_HAS_INT128
240 std::memcpy(&raw, slot,
sizeof(raw));
241 const qinternalint128 value = QtPrivate::sqlInt128FromWords(raw.fb_data[0], raw.fb_data[1]);
242 bool overflow =
false;
243 const QVariant result = QtPrivate::sqlApplyScale(value, scale, policy, &overflow);
245 if (overflow && overflowText)
246 *overflowText = QtPrivate::sqlScaledToString(value, scale);
249 const QString str = int128SlotToString(slot, scale, master, status);
251 case QSql::HighPrecision:
253 case QSql::LowPrecisionDouble:
254 return QVariant(str.toDouble());
255 case QSql::LowPrecisionInt32:
256 case QSql::LowPrecisionInt64: {
258
259
260 const qsizetype dot = str.indexOf(u'.');
261 const QStringView intPart = dot < 0 ? QStringView(str) : QStringView(str).first(dot);
263 if (policy == QSql::LowPrecisionInt32) {
264 const int v = intPart.toInt(&ok);
268 const qint64 v = intPart.toLongLong(&ok);
275 return QVariant(str.toDouble());
278 return QVariant(str.toDouble());
287
288
289
290
291
292
295 return util->encodeDate(
static_cast<
unsigned>(d.year()),
296 static_cast<
unsigned>(d.month()),
297 static_cast<
unsigned>(d.day()));
304 return util->encodeTime(
static_cast<
unsigned>(t.hour()),
305 static_cast<
unsigned>(t.minute()),
306 static_cast<
unsigned>(t.second()),
307 static_cast<
unsigned>(t.msec()) * 10);
313
314
315
316
318 ts.timestamp_date = encodeQDate(util, dt.date());
319 ts.timestamp_time = encodeQTime(util, dt.time());
324
325
326
327
330 QByteArray id = zone.id();
331 if (id.size() > 3 && id.startsWith(
"UTC") && (id.at(3) ==
'+' || id.at(3) ==
'-'))
339 return QTimeZone::utc();
340 if (id.at(0) ==
'+' || id.at(0) ==
'-')
341 return QTimeZone(
"UTC" + id);
342 return QTimeZone(id);
347 ThrowStatusWrapper st(iStatus);
348 ISC_TIMESTAMP_TZ tstz;
350 const bool valid = dt.isValid();
351 const QDate d = valid ? dt.date() : QDate(1858, 11, 17);
352 const QTime t = valid ? dt.time() : QTime(0, 0, 0);
353 const QByteArray ianaId =
354 (valid && dt.timeZone().isValid()) ? toFirebirdZoneId(dt.timeZone()) :
"UTC"_ba;
355 util->encodeTimeStampTz(&st, &tstz,
356 static_cast<
unsigned>(d.year()),
357 static_cast<
unsigned>(d.month()),
358 static_cast<
unsigned>(d.day()),
359 static_cast<
unsigned>(t.hour()),
360 static_cast<
unsigned>(t.minute()),
361 static_cast<
unsigned>(t.second()),
362 static_cast<
unsigned>(t.msec()) * 10,
369 ThrowStatusWrapper st(iStatus);
371 const bool valid = dt.isValid();
372 const QTime t = valid ? dt.time() : QTime(0, 0, 0);
373 const QByteArray ianaId =
374 (valid && dt.timeZone().isValid()) ? toFirebirdZoneId(dt.timeZone()) :
"UTC"_ba;
375 util->encodeTimeTz(&st, &ttz,
376 static_cast<
unsigned>(t.hour()),
377 static_cast<
unsigned>(t.minute()),
378 static_cast<
unsigned>(t.second()),
379 static_cast<
unsigned>(t.msec()) * 10,
391 util->decodeDate(date, &year, &month, &day);
392 return QDate(
static_cast<
int>(year),
static_cast<
int>(month),
static_cast<
int>(day));
401 util->decodeTime(time, &hour, &minute, &sec, &frac);
402 return QTime(
static_cast<
int>(hour),
static_cast<
int>(minute),
403 static_cast<
int>(sec),
static_cast<
int>(frac / 10));
409
410
411
412 return QDateTime(decodeFirebirdDate(util, ts.timestamp_date),
413 decodeFirebirdTime(util, ts.timestamp_time));
417 const ISC_TIMESTAMP_TZ &tstz)
419 CheckStatusWrapper st(iStatus);
427 char tzName[64] = {};
428 util->decodeTimeStampTz(&st, &tstz, &year, &month, &day, &hour, &minute, &sec, &frac,
429 sizeof(tzName), tzName);
430 const QTimeZone tz = fromFirebirdZoneId(QByteArray(tzName));
431 return QDateTime(QDate(
static_cast<
int>(year),
static_cast<
int>(month),
static_cast<
int>(day)),
432 QTime(
static_cast<
int>(hour),
static_cast<
int>(minute),
433 static_cast<
int>(sec),
static_cast<
int>(frac / 10)),
438 const ISC_TIME_TZ &ttz)
440 CheckStatusWrapper st(iStatus);
445 char tzName[64] = {};
446 util->decodeTimeTz(&st, &ttz, &hour, &minute, &sec, &frac,
sizeof(tzName), tzName);
447 const QTimeZone tz = fromFirebirdZoneId(QByteArray(tzName));
448 return QDateTime(QDate(1970, 1, 1),
449 QTime(
static_cast<
int>(hour),
static_cast<
int>(minute),
450 static_cast<
int>(sec),
static_cast<
int>(frac / 10)),
455
456
457
458
459
460void encodeTextValue(
char *data,
int fbType, qsizetype length,
const QByteArray &bytes)
462 if (fbBaseType(fbType) == SQL_VARYING) {
464 const qsizetype len =
std::min(length, bytes.size());
465 *
reinterpret_cast<
unsigned short *>(data) =
static_cast<
unsigned short>(len);
466 std::memcpy(data + 2, bytes.constData(), len);
468 const qsizetype len =
std::min(bytes.size(), length);
469 std::memcpy(data, bytes.constData(), len);
471 std::memset(data + len,
' ', length - len);
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static QString int128SlotToString(const char *slot, int scale, IMaster *master, IStatus *status)
QSqlError fbError(IMaster *master, IStatus *status, QSqlError::ErrorType type)
static QByteArray toFirebirdZoneId(const QTimeZone &zone)
static QTimeZone fromFirebirdZoneId(const QByteArray &id)
QDateTime decodeFirebirdTimestamp(Firebird::IUtil *util, const ISC_TIMESTAMP &ts)
bool encodeInt128Slot(const QVariant &val, int scale, char *slot, Firebird::IMaster *master, Firebird::IStatus *status, QString &errorText)
QString fbErrorLog(const QSqlError &err)
Firebird::ITransaction * startDefaultTransaction(Firebird::IAttachment *att, Firebird::ThrowStatusWrapper &st, TxnWait wait)
QString fbErrorString(Firebird::IMaster *master, Firebird::IStatus *status)
ISC_TIMESTAMP encodeQDateTime(Firebird::IUtil *util, const QDateTime &dt)
ISC_TIME encodeQTime(Firebird::IUtil *util, const QTime &t)
QDate decodeFirebirdDate(Firebird::IUtil *util, ISC_DATE date)
QDateTime decodeFirebirdTimeTz(Firebird::IStatus *iStatus, Firebird::IUtil *util, const ISC_TIME_TZ &ttz)
void encodeTextValue(char *data, int fbType, qsizetype length, const QByteArray &bytes)
void finishAndClear(Firebird::ThrowStatusWrapper &st, Firebird::ITransaction *&tr, TxnEnd end)
QDateTime decodeFirebirdTimestampTz(Firebird::IStatus *iStatus, Firebird::IUtil *util, const ISC_TIMESTAMP_TZ &tstz)
QMetaType::Type blrTypeToQt(unsigned char blrType, bool hasScale)
QTime decodeFirebirdTime(Firebird::IUtil *util, ISC_TIME time)
ISC_TIMESTAMP_TZ encodeQDateTimeTz(Firebird::IStatus *iStatus, Firebird::IUtil *util, const QDateTime &dt)
ISC_TIME_TZ encodeQTimeTz(Firebird::IStatus *iStatus, Firebird::IUtil *util, const QDateTime &dt)
ISC_DATE encodeQDate(Firebird::IUtil *util, const QDate &d)
QMetaType::Type fbTypeToQt(int fbType, int scale)
QVariant decodeInt128Slot(const char *slot, int scale, QSql::NumericalPrecisionPolicy policy, Firebird::IMaster *master, Firebird::IStatus *status, QString *overflowText=nullptr)