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;
138
139
140
141
145 for (
int i = 0; i < n; ++i)
154
155 if (fbBaseType(fbType) == SQL_INT128)
156 return QMetaType::QString;
157 return QMetaType::Double;
161 case SQL_LONG:
return QMetaType::Int;
162 case SQL_INT64:
return QMetaType::LongLong;
163 case SQL_INT128:
return QMetaType::QString;
164 case SQL_FLOAT:
return QMetaType::Double;
165 case SQL_DOUBLE:
return QMetaType::Double;
167 case SQL_DEC34:
return QMetaType::QString;
168 case SQL_BOOLEAN:
return QMetaType::Bool;
169 case SQL_TYPE_DATE:
return QMetaType::QDate;
170 case SQL_TYPE_TIME:
return QMetaType::QTime;
172 case SQL_TIMESTAMP_TZ:
173 case SQL_TIME_TZ:
return QMetaType::QDateTime;
174 case SQL_BLOB:
return QMetaType::QByteArray;
175 case SQL_ARRAY:
return QMetaType::QVariantList;
177 case SQL_VARYING:
return QMetaType::QString;
179 qCWarning(lcFirebird,
"fbTypeToQt: unknown Firebird type %d", fbType);
180 return QMetaType::QString;
185
186
187
188
189
190
193 QByteArray s = val.toByteArray();
194 const int t = val.typeId();
195 if ((t == QMetaType::Double || t == QMetaType::Float)
196 && (s.contains(
'e') || s.contains(
'E'))) {
197 s = QByteArray::number(val.toDouble(),
'f', 18);
198 if (s.contains(
'.')) {
199 while (s.endsWith(
'0'))
209
210
211
212
213
214
215
216
217
220 const QByteArray s = decimal.trimmed();
222 bool negative =
false;
223 if (pos < s.size() && (s[pos] ==
'+' || s[pos] ==
'-'))
224 negative = (s[pos++] ==
'-');
226 QByteArray intPart, fracPart;
227 bool dot =
false, anyDigit =
false;
228 for (; pos < s.size(); ++pos) {
229 const char c = s[pos];
234 }
else if (c >=
'0' && c <=
'9') {
235 (dot ? fracPart : intPart).append(c);
245 const int shift = -scale;
247 while (fracPart.size() < shift)
248 fracPart.append(
'0');
249 intPart += fracPart.left(shift);
250 fracPart.remove(0, shift);
252 const qsizetype k = -shift;
253 while (intPart.size() < k)
254 intPart.prepend(
'0');
255 fracPart.prepend(intPart.right(k));
260 const bool roundUp = !fracPart.isEmpty() && fracPart[0] >=
'5';
262 constexpr quint64 maxPos = quint64((std::numeric_limits<qint64>::max)());
263 const quint64 limit = negative ? maxPos + 1 : maxPos;
264 quint64 magnitude = 0;
265 for (
const char c : intPart) {
266 const unsigned d =
unsigned(c -
'0');
267 if (magnitude > (limit - d) / 10)
269 magnitude = magnitude * 10 + d;
272 if (magnitude == limit)
278 *out = (magnitude == maxPos + 1)
279 ? (std::numeric_limits<qint64>::min)()
280 : -
static_cast<qint64>(magnitude);
282 *out =
static_cast<qint64>(magnitude);
288 const FB_I128 *value,
int scale)
291 util->getInt128(&st)->toString(&st, value, scale,
sizeof(buf), buf);
292 return QString::fromLatin1(buf);
300
301
302
303
304
305
308 return util->encodeDate(
static_cast<
unsigned>(d.year()),
309 static_cast<
unsigned>(d.month()),
310 static_cast<
unsigned>(d.day()));
317 return util->encodeTime(
static_cast<
unsigned>(t.hour()),
318 static_cast<
unsigned>(t.minute()),
319 static_cast<
unsigned>(t.second()),
320 static_cast<
unsigned>(t.msec()) * 10);
326
327
328
329
331 ts.timestamp_date = encodeQDate(util, dt.date());
332 ts.timestamp_time = encodeQTime(util, dt.time());
337
338
339
340
343 QByteArray id = zone.id();
344 if (id.size() > 3 && id.startsWith(
"UTC") && (id.at(3) ==
'+' || id.at(3) ==
'-'))
352 return QTimeZone::utc();
353 if (id.at(0) ==
'+' || id.at(0) ==
'-')
354 return QTimeZone(
"UTC" + id);
355 return QTimeZone(id);
360 ThrowStatusWrapper st(iStatus);
361 ISC_TIMESTAMP_TZ tstz;
363 const bool valid = dt.isValid();
364 const QDate d = valid ? dt.date() : QDate(1858, 11, 17);
365 const QTime t = valid ? dt.time() : QTime(0, 0, 0);
366 const QByteArray ianaId =
367 (valid && dt.timeZone().isValid()) ? toFirebirdZoneId(dt.timeZone()) :
"UTC"_ba;
368 util->encodeTimeStampTz(&st, &tstz,
369 static_cast<
unsigned>(d.year()),
370 static_cast<
unsigned>(d.month()),
371 static_cast<
unsigned>(d.day()),
372 static_cast<
unsigned>(t.hour()),
373 static_cast<
unsigned>(t.minute()),
374 static_cast<
unsigned>(t.second()),
375 static_cast<
unsigned>(t.msec()) * 10,
382 ThrowStatusWrapper st(iStatus);
384 const bool valid = dt.isValid();
385 const QTime t = valid ? dt.time() : QTime(0, 0, 0);
386 const QByteArray ianaId =
387 (valid && dt.timeZone().isValid()) ? toFirebirdZoneId(dt.timeZone()) :
"UTC"_ba;
388 util->encodeTimeTz(&st, &ttz,
389 static_cast<
unsigned>(t.hour()),
390 static_cast<
unsigned>(t.minute()),
391 static_cast<
unsigned>(t.second()),
392 static_cast<
unsigned>(t.msec()) * 10,
404 util->decodeDate(date, &year, &month, &day);
405 return QDate(
static_cast<
int>(year),
static_cast<
int>(month),
static_cast<
int>(day));
414 util->decodeTime(time, &hour, &minute, &sec, &frac);
415 return QTime(
static_cast<
int>(hour),
static_cast<
int>(minute),
416 static_cast<
int>(sec),
static_cast<
int>(frac / 10));
422
423
424
425 return QDateTime(decodeFirebirdDate(util, ts.timestamp_date),
426 decodeFirebirdTime(util, ts.timestamp_time));
430 const ISC_TIMESTAMP_TZ &tstz)
432 CheckStatusWrapper st(iStatus);
440 char tzName[64] = {};
441 util->decodeTimeStampTz(&st, &tstz, &year, &month, &day, &hour, &minute, &sec, &frac,
442 sizeof(tzName), tzName);
443 const QTimeZone tz = fromFirebirdZoneId(QByteArray(tzName));
444 return QDateTime(QDate(
static_cast<
int>(year),
static_cast<
int>(month),
static_cast<
int>(day)),
445 QTime(
static_cast<
int>(hour),
static_cast<
int>(minute),
446 static_cast<
int>(sec),
static_cast<
int>(frac / 10)),
451 const ISC_TIME_TZ &ttz)
453 CheckStatusWrapper st(iStatus);
458 char tzName[64] = {};
459 util->decodeTimeTz(&st, &ttz, &hour, &minute, &sec, &frac,
sizeof(tzName), tzName);
460 const QTimeZone tz = fromFirebirdZoneId(QByteArray(tzName));
461 return QDateTime(QDate(1970, 1, 1),
462 QTime(
static_cast<
int>(hour),
static_cast<
int>(minute),
463 static_cast<
int>(sec),
static_cast<
int>(frac / 10)),
468
469
470
471
472
473void encodeTextValue(
char *data,
int fbType, qsizetype length,
const QByteArray &bytes)
475 if (fbBaseType(fbType) == SQL_VARYING) {
477 const qsizetype len =
std::min(length, bytes.size());
478 *
reinterpret_cast<
unsigned short *>(data) =
static_cast<
unsigned short>(len);
479 std::memcpy(data + 2, bytes.constData(), len);
481 const qsizetype len =
std::min(bytes.size(), length);
482 std::memcpy(data, bytes.constData(), len);
484 std::memset(data + len,
' ', length - len);
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static QByteArray toFirebirdZoneId(const QTimeZone &zone)
static QTimeZone fromFirebirdZoneId(const QByteArray &id)
QDateTime decodeFirebirdTimestamp(Firebird::IUtil *util, const ISC_TIMESTAMP &ts)
QString fbErrorLog(const QSqlError &err)
Firebird::ITransaction * startDefaultTransaction(Firebird::IAttachment *att, Firebird::ThrowStatusWrapper &st, TxnWait wait)
QString fbErrorString(Firebird::IMaster *master, Firebird::IStatus *status)
bool decimalToScaledInt64(const QByteArray &decimal, int scale, qint64 *out)
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)
QByteArray numericInputString(const QVariant &val)
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)
QString int128ToString(Firebird::IUtil *util, Firebird::ThrowStatusWrapper &st, const FB_I128 *value, int scale)
QSqlError fbError(Firebird::IMaster *master, Firebird::IStatus *status, QSqlError::ErrorType type)
ISC_DATE encodeQDate(Firebird::IUtil *util, const QDate &d)
QMetaType::Type fbTypeToQt(int fbType, int scale)