5#include <QtCore/qcoreapplication.h>
6#include <QtCore/qdatetime.h>
7#include <QtCore/qtimezone.h>
8#include <QtCore/qdeadlinetimer.h>
9#include <QtCore/qdebug.h>
10#include <QtCore/qlist.h>
11#include <QtCore/qloggingcategory.h>
12#include <QtCore/qmap.h>
13#include <QtCore/qmutex.h>
14#include <QtCore/qvariant.h>
15#include <QtCore/qvarlengtharray.h>
16#include <QtSql/qsqlerror.h>
17#include <QtSql/qsqlfield.h>
18#include <QtSql/qsqlindex.h>
19#include <QtSql/qsqlquery.h>
20#include <QtSql/private/qsqlcachedresult_p.h>
21#include <QtSql/private/qsqldriver_p.h>
31using namespace
Qt::StringLiterals;
33#define FBVERSION SQL_DIALECT_V6
35#ifndef SQLDA_CURRENT_VERSION
36#define SQLDA_CURRENT_VERSION SQLDA_VERSION1
40#ifndef blr_boolean_dtype
41#define blr_boolean_dtype blr_bool
47typedef QMap<quint16, QByteArray> QFbTzIdToIanaIdMap;
48typedef QMap<QByteArray, quint16> QIanaIdToFbTzIdMap;
51std::once_flag initTZMappingFlag;
56 if (status[0] != 1 || status[1] <= 0)
60 sqlcode = isc_sqlcode(status);
62 while(fb_interpret(
buf, 512, &status)) {
72 sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));
73 if (sqlda == (XSQLDA*)0)
return;
77 sqlda->sqlvar[0].sqlind = 0;
78 sqlda->sqlvar[0].sqldata = 0;
83 if (sqlda != (XSQLDA*)0)
85 sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(
n));
86 if (sqlda == (XSQLDA*)0)
return;
93 for (
int i = 0;
i < sqlda->sqld; ++
i) {
94 switch (sqlda->sqlvar[
i].sqltype & ~1) {
101#if (FB_API_VER >= 40)
102 case SQL_TIMESTAMP_TZ:
109 sqlda->sqlvar[
i].sqldata =
new char[sqlda->sqlvar[
i].sqllen];
112 sqlda->sqlvar[
i].sqldata =
new char[
sizeof(ISC_QUAD)];
113 memset(sqlda->sqlvar[
i].sqldata, 0,
sizeof(ISC_QUAD));
116 sqlda->sqlvar[
i].sqldata =
new char[sqlda->sqlvar[
i].sqllen +
sizeof(short)];
120 sqlda->sqlvar[
i].sqldata = 0;
121 qCWarning(lcIbase,
"initDA: unknown sqltype: %d", sqlda->sqlvar[
i].sqltype & ~1);
124 if (sqlda->sqlvar[
i].sqltype & 1) {
125 sqlda->sqlvar[
i].sqlind =
new short[1];
126 *(sqlda->sqlvar[
i].sqlind) = 0;
128 sqlda->sqlvar[
i].sqlind = 0;
137 for (
int i = 0;
i < sqlda->sqld; ++
i) {
138 delete [] sqlda->sqlvar[
i].sqlind;
139 delete [] sqlda->sqlvar[
i].sqldata;
153 return QMetaType::QString;
155 return QMetaType::QTime;
157 return QMetaType::QDate;
159#if (FB_API_VER >= 40)
160 case blr_timestamp_tz:
162 return QMetaType::QDateTime;
164 return QMetaType::QByteArray;
168 return (hasScale ? QMetaType::Double : QMetaType::Int);
170 return (hasScale ? QMetaType::Double : QMetaType::LongLong);
174 return QMetaType::Double;
176 return QMetaType::Bool;
178 qCWarning(lcIbase,
"qIBaseTypeName: unknown datatype: %d", iType);
187 return QMetaType::QString;
190 return (hasScale ? QMetaType::Double : QMetaType::Int);
192 return (hasScale ? QMetaType::Double : QMetaType::LongLong);
195 return QMetaType::Double;
197#if (FB_API_VER >= 40)
198 case SQL_TIMESTAMP_TZ:
200 return QMetaType::QDateTime;
202 return QMetaType::QTime;
204 return QMetaType::QDate;
206 return QMetaType::QVariantList;
208 return QMetaType::QByteArray;
210 return QMetaType::Bool;
214 qCWarning(lcIbase,
"qIBaseTypeName: unknown datatype: %d", iType);
220 static const QTime midnight(0, 0, 0, 0);
221 static const QDate basedate(1858, 11, 17);
223 ts.timestamp_time = midnight.msecsTo(dt.time()) * 10;
224 ts.timestamp_date = basedate.daysTo(dt.date());
230 static const QDate bd(1858, 11, 17);
236 auto timebuf =
reinterpret_cast<ISC_TIMESTAMP*
>(
buffer);
237 t =
t.addMSecs(
static_cast<int>(timebuf->timestamp_time / 10));
238 d = bd.
addDays(timebuf->timestamp_date);
242#if (FB_API_VER >= 40)
245 static const QDate bd(1858, 11, 17);
251 auto timebuf =
reinterpret_cast<ISC_TIMESTAMP_TZ*
>(
buffer);
252 t =
t.addMSecs(
static_cast<int>(timebuf->utc_timestamp.timestamp_time / 10));
253 d = bd.
addDays(timebuf->utc_timestamp.timestamp_date);
254 quint16 fpTzID = timebuf->time_zone;
256 QByteArray timeZoneName = qFbTzIdToIanaIdMap()->value(fpTzID);
257 if (!timeZoneName.isEmpty())
263ISC_TIMESTAMP_TZ toTimeStampTz(
const QDateTime &dt)
265 static const QTime midnight(0, 0, 0, 0);
266 static const QDate basedate(1858, 11, 17);
268 ts.utc_timestamp.timestamp_time = midnight.msecsTo(dt.time()) * 10;
269 ts.utc_timestamp.timestamp_date = basedate.daysTo(dt.date());
270 ts.time_zone = qIanaIdToFbTzIdMap()->value(dt.timeZone().id().simplified(), 0);
277 static const QTime midnight(0, 0, 0, 0);
278 return (ISC_TIME)midnight.msecsTo(
t) * 10;
286 t =
t.addMSecs(
int((*(ISC_TIME*)
buffer) / 10));
293 static const QDate basedate(1858, 11, 17);
302 static const QDate bd(1858, 11, 17);
343#if (FB_API_VER >= 40)
344 void initTZMappingCache()
348 qry.setForwardOnly(
true);
349 qry.exec(
QString(
"select * from RDB$TIME_ZONES"_L1));
350 if (qry.lastError().type()) {
353 "failed to query time zone mapping from system table"),
354 qry.lastError().databaseText(),
356 qry.lastError().nativeErrorCode()));
362 auto record = qry.record();
365 qFbTzIdToIanaIdMap()->insert(fbTzId, ianaId);
366 qIanaIdToFbTzIdMap()->insert(ianaId, fbTzId);
385 qBufferDriverMap()->remove(
reinterpret_cast<void *
>(eBuffer->resultBuffer));
400 bool exec()
override;
424 const bool negative =
val < 0;
426 if constexpr (std::is_signed_v<T> || negative)
496 localTransaction(!drv_d_func()->ibase),
498 ibase(drv_d_func()->ibase),
513 isc_dsql_free_statement(
status, &
stmt, DSQL_drop);
526 isc_blob_handle
handle = 0;
527 ISC_QUAD *bId = (ISC_QUAD*)
inda->sqlvar[iPos].sqldata;
546 isc_blob_handle
handle = 0;
553 unsigned short len = 0;
564 bool isErr = (
status[1] == isc_segstr_eof ?
false :
566 "Unable to read BLOB"),
590 short* numElements, ISC_ARRAY_DESC *arrayDesc)
592 const short dim = arrayDesc->array_desc_dimensions - 1;
593 const unsigned char dataType = arrayDesc->array_desc_dtype;
594 QList<QVariant> valList;
595 unsigned short strLen = arrayDesc->array_desc_length;
598 for(
int i = 0;
i < numElements[curDim]; ++
i)
609 for (
int i = 0;
i < numElements[dim]; ++
i) {
618 valList = toList<int>(&
buffer, numElements[dim]);
621 valList = toList<short>(&
buffer, numElements[dim]);
624 valList = toList<qint64>(&
buffer, numElements[dim]);
627 valList = toList<float>(&
buffer, numElements[dim]);
630 valList = toList<double>(&
buffer, numElements[dim]);
633 for(
int i = 0;
i < numElements[dim]; ++
i) {
635 buffer +=
sizeof(ISC_TIMESTAMP);
638#if (FB_API_VER >= 40)
639 case blr_timestamp_tz:
640 for (
int i = 0;
i < numElements[dim]; ++
i) {
641 valList.append(fromTimeStampTz(
buffer));
642 buffer +=
sizeof(ISC_TIMESTAMP_TZ);
647 for (
int i = 0;
i < numElements[dim]; ++
i) {
649 buffer +=
sizeof(ISC_TIME);
653 for(
int i = 0;
i < numElements[dim]; ++
i) {
655 buffer +=
sizeof(ISC_DATE);
659 valList = toList<bool>(&
buffer, numElements[dim]);
672 QList<QVariant>
list;
681 isc_array_lookup_bounds(
status, &
ibase, &
trans, relname.data(), sqlname.data(), &desc);
687 int arraySize = 1, subArraySize;
688 short dimensions = desc.array_desc_dimensions;
689 QVarLengthArray<short> numElements(dimensions);
691 for(
int i = 0;
i < dimensions; ++
i) {
692 subArraySize = (desc.array_desc_bounds[
i].array_bound_upper -
693 desc.array_desc_bounds[
i].array_bound_lower + 1);
694 numElements[
i] = subArraySize;
695 arraySize = subArraySize * arraySize;
703 if (desc.array_desc_dtype == blr_varying
704 || desc.array_desc_dtype == blr_varying2) {
705 desc.array_desc_length += 2;
706 bufLen = desc.array_desc_length * arraySize *
sizeof(short);
708 bufLen = desc.array_desc_length * arraySize;
726 for (
const auto &elem :
list) {
727 T
val = qvariant_cast<T>(elem);
737 for (
const auto &elem :
list) {
738 double val = qvariant_cast<double>(elem);
739 float val2 = (float)
val;
740 memcpy(
buffer, &val2,
sizeof(
float));
747 short buflen,
bool varying,
bool array)
751 short tmpBuflen = buflen;
756 memset(
buffer + buflen, 0, tmpBuflen - buflen);
774 ISC_ARRAY_BOUND *bounds = arrayDesc->array_desc_bounds;
775 short dim = arrayDesc->array_desc_dimensions - 1;
777 int elements = (bounds[curDim].array_bound_upper -
778 bounds[curDim].array_bound_lower + 1);
781 error =
"Expected size: %1. Supplied size: %2"_L1;
782 error =
"Array size mismatch. Fieldname: %1 "_L1
788 for (
const auto &elem :
list) {
790 if (elem.typeId() != QMetaType::QVariantList) {
791 error =
"Array dimensons mismatch. Fieldname: %1"_L1;
803 case QMetaType::UInt:
804 if (arrayDesc->array_desc_dtype == blr_short)
809 case QMetaType::Double:
810 if (arrayDesc->array_desc_dtype == blr_float)
815 case QMetaType::LongLong:
818 case QMetaType::ULongLong:
821 case QMetaType::QString:
822 for (
const auto &elem :
list)
824 arrayDesc->array_desc_length,
825 arrayDesc->array_desc_dtype == blr_varying,
828 case QMetaType::QDate:
829 for (
const auto &elem :
list) {
831 buffer +=
sizeof(ISC_DATE);
834 case QMetaType::QTime:
835 for (
const auto &elem :
list) {
837 buffer +=
sizeof(ISC_TIME);
840 case QMetaType::QDateTime:
841 for (
const auto &elem :
list) {
842 switch (arrayDesc->array_desc_dtype) {
845 buffer +=
sizeof(ISC_TIMESTAMP);
847#if (FB_API_VER >= 40)
848 case blr_timestamp_tz:
849 *((ISC_TIMESTAMP_TZ*)
buffer) = toTimeStampTz(elem.toDateTime());
850 buffer +=
sizeof(ISC_TIMESTAMP_TZ);
858 case QMetaType::Bool:
872 ISC_QUAD *arrayId = (ISC_QUAD*)
inda->sqlvar[
column].sqldata;
878 isc_array_lookup_bounds(
status, &
ibase, &
trans, relname.data(), sqlname.data(), &desc);
886 short dimensions = desc.array_desc_dimensions;
887 for(
int i = 0;
i < dimensions; ++
i) {
888 arraySize *= (desc.array_desc_bounds[
i].array_bound_upper -
889 desc.array_desc_bounds[
i].array_bound_lower + 1);
895 if (desc.array_desc_dtype == blr_varying ||
896 desc.array_desc_dtype == blr_varying2)
897 desc.array_desc_length += 2;
899 bufLen = desc.array_desc_length * arraySize;
904 error =
"Array size mismatch: size of %1 is %2, size of provided list is %3"_L1;
919 if (desc.array_desc_dtype == blr_varying
920 || desc.array_desc_dtype == blr_varying2)
921 desc.array_desc_length -= 2;
931 char qType = isc_info_sql_stmt_type;
932 isc_dsql_sql_info(
status, &
stmt, 1, &qType,
sizeof(acBuffer), acBuffer);
936 int iLength = isc_vax_integer(&acBuffer[1], 2);
937 queryType = isc_vax_integer(&acBuffer[3], iLength);
938 return (
queryType == isc_info_sql_stmt_select ||
queryType == isc_info_sql_stmt_exec_procedure);
945 if (drv_d_func()->
trans) {
947 trans = drv_d_func()->trans;
994 if (
d->sqlda == (XSQLDA*)0) {
995 qCWarning(lcIbase) <<
"QIOBaseResult: createDA(): failed to allocate memory";
1000 if (
d->inda == (XSQLDA*)0){
1001 qCWarning(lcIbase) <<
"QIOBaseResult: createDA(): failed to allocate memory";
1005 if (!
d->transaction())
1008 isc_dsql_allocate_statement(
d->status, &
d->ibase, &
d->stmt);
1012 isc_dsql_prepare(
d->status, &
d->trans, &
d->stmt, 0,
1018 isc_dsql_describe_bind(
d->status, &
d->stmt,
FBVERSION,
d->inda);
1022 if (
d->inda->sqld >
d->inda->sqln) {
1024 if (
d->inda == (XSQLDA*)0) {
1025 qCWarning(lcIbase) <<
"QIOBaseResult: enlargeDA(): failed to allocate memory";
1029 isc_dsql_describe_bind(
d->status, &
d->stmt,
FBVERSION,
d->inda);
1035 if (
d->sqlda->sqld >
d->sqlda->sqln) {
1038 if (
d->sqlda == (XSQLDA*)0) {
1039 qCWarning(lcIbase) <<
"QIOBaseResult: enlargeDA(): failed to allocate memory";
1043 isc_dsql_describe(
d->status, &
d->stmt,
FBVERSION,
d->sqlda);
1074 if (
values.count() >
d->inda->sqld) {
1075 qCWarning(lcIbase) <<
"QIBaseResult::exec: Parameter mismatch, expected"_L1
1076 <<
d->inda->sqld <<
", got"_L1 <<
values.count()
1081 if (!
d->inda->sqlvar[para].sqldata)
1085 if (
d->inda->sqlvar[para].sqltype & 1) {
1088 *(
d->inda->sqlvar[para].sqlind) = -1;
1095 *(
d->inda->sqlvar[para].sqlind) = 0;
1098 qCWarning(lcIbase) <<
"QIBaseResult::exec: Null value replaced by default (zero)"_L1
1099 <<
"value for type of column"_L1 <<
d->inda->sqlvar[para].ownname
1100 <<
", which is not nullable."_L1;
1103 switch(
d->inda->sqlvar[para].sqltype & ~1) {
1105 if (
d->inda->sqlvar[para].sqlscale < 0)
1106 *((
qint64*)
d->inda->sqlvar[para].sqldata) =
1107 (
qint64)floor(0.5 +
val.toDouble() * pow(10.0,
d->inda->sqlvar[para].sqlscale * -1));
1109 *((
qint64*)
d->inda->sqlvar[para].sqldata) =
val.toLongLong();
1112 if (
d->inda->sqlvar[para].sqllen == 4) {
1113 if (
d->inda->sqlvar[para].sqlscale < 0)
1114 *((
qint32*)
d->inda->sqlvar[para].sqldata) =
1115 (
qint32)floor(0.5 +
val.toDouble() * pow(10.0,
d->inda->sqlvar[para].sqlscale * -1));
1119 *((
qint64*)
d->inda->sqlvar[para].sqldata) =
val.toLongLong();
1123 if (
d->inda->sqlvar[para].sqlscale < 0)
1124 *((
short*)
d->inda->sqlvar[para].sqldata) =
1125 (short)floor(0.5 +
val.toDouble() * pow(10.0,
d->inda->sqlvar[para].sqlscale * -1));
1127 *((
short*)
d->inda->sqlvar[para].sqldata) = (short)
val.toInt();
1130 *((
float*)
d->inda->sqlvar[para].sqldata) = (float)
val.toDouble();
1133 *((
double*)
d->inda->sqlvar[para].sqldata) =
val.toDouble();
1136 *((ISC_TIMESTAMP*)
d->inda->sqlvar[para].sqldata) =
toTimeStamp(
val.toDateTime());
1138#if (FB_API_VER >= 40)
1139 case SQL_TIMESTAMP_TZ:
1140 *((ISC_TIMESTAMP_TZ*)
d->inda->sqlvar[para].sqldata) = toTimeStampTz(
val.toDateTime());
1144 *((ISC_TIME*)
d->inda->sqlvar[para].sqldata) =
toTime(
val.toTime());
1147 *((ISC_DATE*)
d->inda->sqlvar[para].sqldata) =
toDate(
val.toDate());
1152 d->inda->sqlvar[para].sqllen,
1153 (
d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING,
false);
1156 ok &=
d->writeBlob(para,
val.toByteArray());
1159 ok &=
d->writeArray(para,
val.toList());
1162 *((
bool*)
d->inda->sqlvar[para].sqldata) =
val.toBool();
1165 qCWarning(lcIbase,
"QIBaseResult::exec: Unknown datatype %d",
1166 d->inda->sqlvar[para].sqltype & ~1);
1173 isc_dsql_free_statement(
d->status, &
d->stmt, DSQL_close);
1176 if (
getIBaseError(imsg,
d->status, sqlcode) && sqlcode != -501) {
1182 if (
colCount() &&
d->queryType != isc_info_sql_stmt_exec_procedure) {
1185 if (
d->queryType == isc_info_sql_stmt_exec_procedure)
1186 isc_dsql_execute2(
d->status, &
d->trans, &
d->stmt,
FBVERSION,
d->inda,
d->sqlda);
1188 isc_dsql_execute(
d->status, &
d->trans, &
d->stmt,
FBVERSION,
d->inda);
1193 if (
d->queryType == isc_info_sql_stmt_exec_procedure &&
d->sqlda &&
d->sqlda->sqld == 0)
1197 init(
d->sqlda->sqld);
1218 ISC_STATUS stat = 0;
1222 if (
d->queryType == isc_info_sql_stmt_exec_procedure) {
1228 stat = isc_dsql_fetch(
d->status, &
d->stmt,
FBVERSION,
d->sqlda);
1242 for (
int i = 0;
i <
d->sqlda->sqld; ++
i) {
1243 int idx = rowIdx +
i;
1244 char *
buf =
d->sqlda->sqlvar[
i].sqldata;
1245 int size =
d->sqlda->sqlvar[
i].sqllen;
1248 if ((
d->sqlda->sqlvar[
i].sqltype & 1) && *
d->sqlda->sqlvar[
i].sqlind) {
1252 d->sqlda->sqlvar[
i].sqlscale < 0)));
1253 if (
v.userType() == QMetaType::Double) {
1273 switch(
d->sqlda->sqlvar[
i].sqltype & ~1) {
1281 const auto scale =
d->sqlda->sqlvar[
i].sqlscale;
1286 if (
d->sqlda->sqlvar[
i].sqllen == 4) {
1288 const auto scale =
d->sqlda->sqlvar[
i].sqlscale;
1294 const auto val = *(
short *)
buf;
1295 const auto scale =
d->sqlda->sqlvar[
i].sqlscale;
1318 row[idx] =
d->fetchBlob((ISC_QUAD*)
buf);
1321 row[idx] =
d->fetchArray(
i, (ISC_QUAD*)
buf);
1326#if (FB_API_VER >= 40)
1327 case SQL_TIMESTAMP_TZ:
1328 row[idx] = fromTimeStampTz(
buf);
1333 qCWarning(lcIbase,
"gotoNext: unknown sqltype: %d",
1334 d->sqlda->sqlvar[
i].sqltype & ~1);
1348 static char sizeInfo[] = {isc_info_sql_records};
1359 isc_dsql_sql_info(
d->status, &
d->stmt,
sizeof(sizeInfo), sizeInfo,
sizeof(
buf),
buf);
1362 for(
int i = 0;
i < 66; ++
i)
1365 for (
char*
c =
buf + 3; *
c != isc_info_end; ) {
1367 len = isc_vax_integer(
c, 2);
1369 val = isc_vax_integer(
c,
len);
1372 if (ct == isc_info_req_select_count)
1378 unsigned int i, result_size;
1379 if (
buf[0] == isc_info_sql_records) {
1381 result_size = isc_vax_integer(&
buf[1],2);
1382 while (
buf[
i] != isc_info_end &&
i < result_size) {
1383 len = (short)isc_vax_integer(&
buf[
i+1],2);
1384 if (
buf[
i] == isc_info_req_select_count)
1385 return (isc_vax_integer(&
buf[
i+3],
len));
1397 static char acCountInfo[] = {isc_info_sql_records};
1399 bool bIsProcedure =
false;
1401 switch (
d->queryType) {
1402 case isc_info_sql_stmt_select:
1403 cCountType = isc_info_req_select_count;
1405 case isc_info_sql_stmt_update:
1406 cCountType = isc_info_req_update_count;
1408 case isc_info_sql_stmt_delete:
1409 cCountType = isc_info_req_delete_count;
1411 case isc_info_sql_stmt_insert:
1412 cCountType = isc_info_req_insert_count;
1414 case isc_info_sql_stmt_exec_procedure:
1415 bIsProcedure =
true;
1418 qCWarning(lcIbase) <<
"numRowsAffected: Unknown statement type (" <<
d->queryType <<
")";
1424 isc_dsql_sql_info(
d->status, &
d->stmt,
sizeof(acCountInfo), acCountInfo,
sizeof(acBuffer), acBuffer);
1428 for (
char *pcBuf = acBuffer + 3; *pcBuf != isc_info_end; ) {
1429 char cType = *pcBuf++;
1430 short sLength = isc_vax_integer (pcBuf, 2);
1432 int iValue = isc_vax_integer (pcBuf, sLength);
1435 if (cType == isc_info_req_insert_count || cType == isc_info_req_update_count
1436 || cType == isc_info_req_delete_count) {
1441 }
else if (cType == cCountType) {
1457 for (
int i = 0;
i <
d->sqlda->sqld; ++
i) {
1458 v =
d->sqlda->sqlvar[
i];
1462 f.setLength(
v.sqllen);
1463 f.setPrecision(
qAbs(
v.sqlscale));
1465 if (
v.sqlscale < 0) {
1467 q.setForwardOnly(
true);
1468 q.exec(
"select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
1469 "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
1470 "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
1474 if (
v.sqlscale < 0) {
1475 f.setLength(
q.value(0).toInt());
1476 f.setPrecision(
qAbs(
q.value(1).toInt()));
1478 f.setLength(
q.value(2).toInt());
1492 return QVariant(QMetaType::fromType<isc_stmt_handle>(), &
d->stmt);
1553 for (
const auto &
opt : opts) {
1554 const auto tmp(
opt.trimmed());
1556 if ((idx = tmp.indexOf(u
'=')) != -1) {
1557 const auto val = tmp.mid(idx + 1).trimmed();
1558 const auto opt = tmp.left(idx).trimmed().toString();
1559 if (
opt.toUpper() ==
"ISC_DPB_SQL_ROLE_NAME"_L1) {
1560 role =
val.toLocal8Bit();
1575 ba.
append(
char(isc_dpb_user_name));
1577 ba.
append(usr.data(), usr.length());
1583 ba.
append(enc.data(), enc.length());
1586 ba.
append(
char(isc_dpb_sql_role_name));
1597 ldb += host + portString + u
':';
1599 isc_attach_database(
d->status, 0,
const_cast<char *
>(ldb.toLocal8Bit().constData()),
1609#if (FB_API_VER >= 40)
1610 std::call_once(initTZMappingFlag, [
d](){
d->initTZMappingCache(); });
1625 if (
d->eventBuffers.size()) {
1626 ISC_STATUS status[20];
1628 for (
i =
d->eventBuffers.constBegin();
i !=
d->eventBuffers.constEnd(); ++
i) {
1631 isc_cancel_events(status, &
d->ibase, &eBuffer->eventId);
1634 d->eventBuffers.clear();
1637 isc_detach_database(
d->status, &
d->ibase);
1657 isc_start_transaction(
d->status, &
d->trans, 1, &
d->ibase, 0, NULL);
1670 isc_commit_transaction(
d->status, &
d->trans);
1672 return !
d->isError(
QT_TRANSLATE_NOOP(
"QIBaseDriver",
"Unable to commit transaction"),
1684 isc_rollback_transaction(
d->status, &
d->trans);
1686 return !
d->isError(
QT_TRANSLATE_NOOP(
"QIBaseDriver",
"Unable to rollback transaction"),
1699 typeFilter +=
"RDB$SYSTEM_FLAG != 0"_L1;
1701 typeFilter +=
"RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL"_L1;
1704 typeFilter +=
"RDB$SYSTEM_FLAG = 0 AND "_L1;
1706 typeFilter +=
"RDB$VIEW_BLR IS NULL AND "_L1;
1708 typeFilter +=
"RDB$VIEW_BLR IS NOT NULL AND "_L1;
1709 if (!typeFilter.isEmpty())
1712 if (!typeFilter.isEmpty())
1713 typeFilter.prepend(
"where "_L1);
1716 q.setForwardOnly(
true);
1717 if (!
q.exec(
"select rdb$relation_name from rdb$relations "_L1 + typeFilter))
1720 res <<
q.value(0).toString().simplified();
1733 q.setForwardOnly(
true);
1734 q.exec(
"SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
1735 "b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
1736 "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
1737 "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
1738 "AND a.RDB$RELATION_NAME = '"_L1 +
table +
"' "
1739 "ORDER BY a.RDB$FIELD_POSITION"_L1);
1742 int type =
q.value(1).toInt();
1743 bool hasScale =
q.value(3).toInt() < 0;
1746 f.setLength(
q.value(4).toInt());
1747 f.setPrecision(
qAbs(
q.value(3).toInt()));
1749 f.setLength(
q.value(2).toInt());
1752 f.setRequired(
q.value(5).toInt() > 0);
1767 q.setForwardOnly(
true);
1768 q.exec(
"SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
1769 "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d "
1770 "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
1771 "AND a.RDB$RELATION_NAME = '"_L1 + tablename +
1772 " 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
1773 "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME "
1774 "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME "
1775 "AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE "
1776 "ORDER BY b.RDB$FIELD_POSITION"_L1);
1779 QSqlField field(
q.value(1).toString().simplified(),
1782 index.append(field);
1783 index.setName(
q.value(0).toString());
1792 case QMetaType::QDateTime: {
1806 case QMetaType::QTime: {
1817 case QMetaType::QDate: {
1834 return QVariant(QMetaType::fromType<isc_db_handle>(), &
d->ibase);
1860 qCWarning(lcIbase,
"QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
1864 if (
d->eventBuffers.contains(
name)) {
1865 qCWarning(lcIbase,
"QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%ls'.",
1872 eBuffer->bufferLength = isc_event_block(&eBuffer->eventBuffer,
1873 &eBuffer->resultBuffer,
1875 name.toLocal8Bit().constData());
1878 qBufferDriverMap()->insert(eBuffer->resultBuffer,
this);
1881 d->eventBuffers.insert(
name, eBuffer);
1883 ISC_STATUS status[20];
1884 isc_que_events(status,
1887 eBuffer->bufferLength,
1888 eBuffer->eventBuffer,
1889 reinterpret_cast<ISC_EVENT_CALLBACK
>(
reinterpret_cast<void *
>
1891 eBuffer->resultBuffer);
1893 if (status[0] == 1 && status[1]) {
1895 d->eventBuffers.remove(
name);
1907 qCWarning(lcIbase,
"QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
1911 if (!
d->eventBuffers.contains(
name)) {
1912 qCWarning(lcIbase,
"QIBaseDriver::QIBaseSubscriptionState not subscribed to '%ls'.",
1918 ISC_STATUS status[20];
1920 isc_cancel_events(status, &
d->ibase, &eBuffer->eventId);
1922 if (status[0] == 1 && status[1]) {
1927 d->eventBuffers.remove(
name);
1939void QIBaseDriver::qHandleEventNotification(
void *updatedResultBuffer)
1943 for (
i =
d->eventBuffers.constBegin();
i !=
d->eventBuffers.constEnd(); ++
i) {
1945 if (
reinterpret_cast<void *
>(eBuffer->resultBuffer) != updatedResultBuffer)
1948 ISC_ULONG counts[20];
1949 memset(counts, 0,
sizeof(counts));
1950 isc_event_counts(counts, eBuffer->bufferLength, eBuffer->eventBuffer, eBuffer->resultBuffer);
1958 ISC_STATUS status[20];
1959 isc_que_events(status,
1962 eBuffer->bufferLength,
1963 eBuffer->eventBuffer,
1964 reinterpret_cast<ISC_EVENT_CALLBACK
>(
reinterpret_cast<void *
>
1966 eBuffer->resultBuffer);
1967 if (
Q_UNLIKELY(status[0] == 1 && status[1])) {
1968 qCritical(
"QIBaseDriver::qHandleEventNotification: could not resubscribe to '%ls'",
1996#include "moc_qsql_ibase_p.cpp"
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
qsizetype length() const noexcept
Same as size().
void truncate(qsizetype pos)
Truncates the byte array at index position pos.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
QTime time() const
Returns the time part of the datetime.
bool isValid() const
Returns true if this datetime represents a definite moment, otherwise false.
QDate date() const
Returns the date part of the datetime.
\inmodule QtCore \reentrant
qint64 daysTo(QDate d) const
Returns the number of days from this date to d (which is negative if d is earlier than this date).
constexpr bool isValid() const
Returns true if this date is valid; otherwise returns false.
int month() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int day() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QDate addDays(qint64 days) const
Returns a QDate object containing a date ndays later than the date of this object (or earlier if nday...
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isError(const char *msg, QSqlError::ErrorType typ=QSqlError::UnknownError)
QMap< QString, QIBaseEventBuffer * > eventBuffers
QString escapeIdentifier(const QString &identifier, IdentifierType type) const override
Returns the identifier escaped according to the database rules.
QSqlResult * createResult() const override
Creates an empty SQL result on the database.
QStringList subscribedToNotifications() const override
Returns a list of the names of the event notifications that are currently subscribed to.
QVariant handle() const override
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
QSqlRecord record(const QString &tablename) const override
Returns a QSqlRecord populated with the names of the fields in table tableName.
int maximumIdentifierLength(IdentifierType type) const override
QStringList tables(QSql::TableType) const override
Returns a list of the names of the tables in the database.
bool hasFeature(DriverFeature f) const override
Returns true if the driver supports feature feature; otherwise returns false.
QString formatValue(const QSqlField &field, bool trimStrings) const override
Returns a string representation of the field value for the database.
bool rollbackTransaction() override
This function is called to rollback a transaction.
bool unsubscribeFromNotification(const QString &name) override
This function is called to unsubscribe from event notifications from the database.
QIBaseDriver(QObject *parent=nullptr)
void close() override
Derived classes must reimplement this pure virtual function in order to close the database connection...
bool beginTransaction() override
This function is called to begin a transaction.
bool subscribeToNotification(const QString &name) override
This function is called to subscribe to event notifications from the database.
bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, const QString &connOpts) override
Derived classes must reimplement this pure virtual function to open a database connection on database...
bool commitTransaction() override
This function is called to commit a transaction.
QSqlIndex primaryIndex(const QString &table) const override
Returns the primary index for table tableName.
QVariant fetchArray(int pos, ISC_QUAD *arr)
bool isError(const char *msg, QSqlError::ErrorType typ=QSqlError::UnknownError)
QIBaseResultPrivate(QIBaseResult *q, const QIBaseDriver *drv)
bool writeBlob(qsizetype iPos, const QByteArray &ba)
QVariant fetchBlob(ISC_QUAD *bId)
bool writeArray(qsizetype i, const QList< QVariant > &list)
bool prepare(const QString &query) override
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
QSqlRecord record() const override
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
bool gotoNext(QSqlCachedResult::ValueCache &row, int rowIdx) override
bool reset(const QString &query) override
Sets the result to use the SQL statement query for subsequent data retrieval.
QVariant applyScale(T val, int scale) const
QVariant handle() const override
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
bool exec() override
Executes the query, returning true if successful; otherwise returns false.
int size() override
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
QIBaseResult(const QIBaseDriver *db)
int numRowsAffected() override
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
qsizetype size() const noexcept
void append(parameter_type t)
QSqlDriver::DbmsType dbmsType
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
virtual QString formatValue(const QSqlField &field, bool trimStrings=false) const
Returns a string representation of the field value for the database.
IdentifierType
This enum contains a list of SQL identifier types.
virtual QString stripDelimiters(const QString &identifier, IdentifierType type) const
Returns the identifier with the leading and trailing delimiters removed, identifier can either be a t...
QSqlError lastError() const
Returns a QSqlError object which contains information about the last error that occurred on the datab...
DriverFeature
This enum contains a list of features a driver might support.
bool isOpenError() const
Returns true if the there was an error opening the database connection; otherwise returns false.
virtual void setLastError(const QSqlError &e)
This function is used to set the value of the last error, error, that occurred on the database.
void notification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload)
virtual bool isOpen() const
Returns true if the database connection is open; otherwise returns false.
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
virtual void setOpen(bool o)
This function sets the open state of the database to open.
The QSqlError class provides SQL database error information.
ErrorType
This enum type describes the context in which the error occurred, e.g., a connection error,...
The QSqlField class manipulates the fields in SQL database tables and views.
The QSqlIndex class provides functions to manipulate and describe database indexes.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
The QSqlRecord class encapsulates a database record.
void append(const QSqlField &field)
Append a copy of field field to the end of the record.
static bool isVariantNull(const QVariant &variant)
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases.
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index.
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active.
QVariantList & boundValues(QT6_DECL_NEW_OVERLOAD)
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
const QSqlDriver * driver() const
Returns the driver associated with the result.
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
void chop(qsizetype n)
Removes n characters from the end of the string.
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
void clear()
Clears the contents of the string and makes it null.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString leftJustified(qsizetype width, QChar fill=u' ', bool trunc=false) const
Returns a string of size width that contains this string padded by the fill character.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
QByteArray toLocal8Bit() const &
QChar * data()
Returns a pointer to the data stored in the QString.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
qsizetype length() const noexcept
Returns the number of characters in this string.
\inmodule QtCore \reentrant
int hour() const
Returns the hour part (0 to 23) of the time.
int minute() const
Returns the minute part (0 to 59) of the time.
bool isValid() const
Returns true if the time is valid; otherwise returns false.
int msec() const
Returns the millisecond part (0 to 999) of the time.
int second() const
Returns the second part (0 to 59) of the time.
bool convert(QMetaType type)
Casts the variant to the requested type, targetType.
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has userType() \l QMetaType::QDateTime,...
QTime toTime() const
Returns the variant as a QTime if the variant has userType() \l QMetaType::QTime, \l QMetaType::QDate...
QDate toDate() const
Returns the variant as a QDate if the variant has userType() \l QMetaType::QDate, \l QMetaType::QDate...
Combined button and popup list for selecting options.
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError * error
DBusConnection * connection
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr T qAbs(const T &t)
#define Q_ARG(Type, data)
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLenum GLsizei void GLsizei void * column
GLdouble GLdouble GLdouble GLdouble q
GLenum GLenum GLsizei void * row
GLenum GLenum GLenum GLenum GLenum scale
GLenum GLenum GLsizei void * table
static void split(QT_FT_Vector *b)
static void delDA(XSQLDA *&sqlda)
static void qFreeEventBuffer(QIBaseEventBuffer *eBuffer)
static void initDA(XSQLDA *sqlda)
static ISC_DATE toDate(QDate t)
static bool getIBaseError(QString &msg, const ISC_STATUS *status, ISC_LONG &sqlcode)
static void enlargeDA(XSQLDA *&sqlda, int n)
static QTime fromTime(char *buffer)
static char * createArrayBuffer(char *buffer, const QList< QVariant > &list, QMetaType::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc, QString &error)
static void createDA(XSQLDA *&sqlda)
static char * qFillBufferWithString(char *buffer, const QString &string, short buflen, bool varying, bool array)
static QDateTime fromTimeStamp(char *buffer)
static QMetaType::Type qIBaseTypeName(int iType, bool hasScale)
#define blr_boolean_dtype
static char * fillList(char *buffer, const QList< QVariant > &list, T *=nullptr)
static QList< QVariant > toList(char **buf, int count)
constexpr qsizetype QIBaseChunkSize
static QMetaType::Type qIBaseTypeName2(int iType, bool hasScale)
char * fillList< float >(char *buffer, const QList< QVariant > &list, float *)
static ISC_TIME toTime(QTime t)
static ISC_EVENT_CALLBACK qEventCallback(char *result, ISC_USHORT length, const ISC_UCHAR *updated)
#define SQLDA_CURRENT_VERSION
QMap< void *, QIBaseDriver * > QIBaseBufferDriverMap
static QDate fromDate(char *buffer)
static char * readArrayBuffer(QList< QVariant > &list, char *buffer, short curDim, short *numElements, ISC_ARRAY_DESC *arrayDesc)
static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
#define Q_DECLARE_SQLDRIVER_PRIVATE(Class)
#define qUtf16Printable(string)
#define QStringLiteral(str)
static const QTextHtmlElement elements[Html_NumElements]
#define QT_TRANSLATE_NOOP(scope, x)
ReturnedValue read(const char *data)
QIBaseSubscriptionState subscriptionState