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/qmap.h>
12#include <QtCore/qmutex.h>
13#include <QtCore/qvariant.h>
14#include <QtCore/qvarlengtharray.h>
15#include <QtSql/qsqlerror.h>
16#include <QtSql/qsqlfield.h>
17#include <QtSql/qsqlindex.h>
18#include <QtSql/qsqlquery.h>
19#include <QtSql/private/qsqlcachedresult_p.h>
20#include <QtSql/private/qsqldriver_p.h>
30#define FBVERSION SQL_DIALECT_V6
32#ifndef SQLDA_CURRENT_VERSION
33#define SQLDA_CURRENT_VERSION SQLDA_VERSION1
37#ifndef blr_boolean_dtype
38#define blr_boolean_dtype blr_bool
48std::once_flag initTZMappingFlag;
53 if (status[0] != 1 || status[1] <= 0)
57 sqlcode = isc_sqlcode(status);
59 while(fb_interpret(
buf, 512, &status)) {
69 sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));
70 if (sqlda == (XSQLDA*)0)
return;
74 sqlda->sqlvar[0].sqlind = 0;
75 sqlda->sqlvar[0].sqldata = 0;
80 if (sqlda != (XSQLDA*)0)
82 sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(
n));
83 if (sqlda == (XSQLDA*)0)
return;
90 for (
int i = 0;
i < sqlda->sqld; ++
i) {
91 switch (sqlda->sqlvar[
i].sqltype & ~1) {
99 case SQL_TIMESTAMP_TZ:
106 sqlda->sqlvar[
i].sqldata =
new char[sqlda->sqlvar[
i].sqllen];
109 sqlda->sqlvar[
i].sqldata =
new char[
sizeof(ISC_QUAD)];
110 memset(sqlda->sqlvar[
i].sqldata, 0,
sizeof(ISC_QUAD));
113 sqlda->sqlvar[
i].sqldata =
new char[sqlda->sqlvar[
i].sqllen +
sizeof(short)];
117 sqlda->sqlvar[
i].sqldata = 0;
120 if (sqlda->sqlvar[
i].sqltype & 1) {
121 sqlda->sqlvar[
i].sqlind =
new short[1];
122 *(sqlda->sqlvar[
i].sqlind) = 0;
124 sqlda->sqlvar[
i].sqlind = 0;
133 for (
int i = 0;
i < sqlda->sqld; ++
i) {
134 delete [] sqlda->sqlvar[
i].sqlind;
135 delete [] sqlda->sqlvar[
i].sqldata;
149 return QMetaType::QString;
151 return QMetaType::QTime;
153 return QMetaType::QDate;
155#if (FB_API_VER >= 40)
156 case blr_timestamp_tz:
158 return QMetaType::QDateTime;
160 return QMetaType::QByteArray;
164 return (hasScale ? QMetaType::Double : QMetaType::Int);
166 return (hasScale ? QMetaType::Double : QMetaType::LongLong);
170 return QMetaType::Double;
172 return QMetaType::Bool;
174 qWarning(
"qIBaseTypeName: unknown datatype: %d", iType);
183 return QMetaType::QString;
186 return (hasScale ? QMetaType::Double : QMetaType::Int);
188 return (hasScale ? QMetaType::Double : QMetaType::LongLong);
191 return QMetaType::Double;
193#if (FB_API_VER >= 40)
194 case SQL_TIMESTAMP_TZ:
196 return QMetaType::QDateTime;
198 return QMetaType::QTime;
200 return QMetaType::QDate;
202 return QMetaType::QVariantList;
204 return QMetaType::QByteArray;
206 return QMetaType::Bool;
214 static const QTime midnight(0, 0, 0, 0);
215 static const QDate basedate(1858, 11, 17);
217 ts.timestamp_time = midnight.
msecsTo(dt.
time()) * 10;
218 ts.timestamp_date = basedate.
daysTo(dt.
date());
224 static const QDate bd(1858, 11, 17);
230 auto timebuf =
reinterpret_cast<ISC_TIMESTAMP*
>(
buffer);
231 t =
t.addMSecs(
static_cast<int>(timebuf->timestamp_time / 10));
232 d = bd.
addDays(timebuf->timestamp_date);
236#if (FB_API_VER >= 40)
239 static const QDate bd(1858, 11, 17);
245 auto timebuf =
reinterpret_cast<ISC_TIMESTAMP_TZ*
>(
buffer);
246 t =
t.addMSecs(
static_cast<int>(timebuf->utc_timestamp.timestamp_time / 10));
247 d = bd.addDays(timebuf->utc_timestamp.timestamp_date);
248 quint16 fpTzID = timebuf->time_zone;
250 QByteArray timeZoneName = qFbTzIdToIanaIdMap()->value(fpTzID);
257ISC_TIMESTAMP_TZ toTimeStampTz(
const QDateTime &dt)
259 static const QTime midnight(0, 0, 0, 0);
260 static const QDate basedate(1858, 11, 17);
262 ts.utc_timestamp.timestamp_time = midnight.msecsTo(dt.
time()) * 10;
263 ts.utc_timestamp.timestamp_date = basedate.daysTo(dt.
date());
264 ts.time_zone = qIanaIdToFbTzIdMap()->value(dt.timeZone().id().simplified(), 0);
271 static const QTime midnight(0, 0, 0, 0);
272 return (ISC_TIME)midnight.
msecsTo(
t) * 10;
280 t =
t.addMSecs(
int((*(ISC_TIME*)
buffer) / 10));
287 static const QDate basedate(1858, 11, 17);
296 static const QDate bd(1858, 11, 17);
337#if (FB_API_VER >= 40)
338 void initTZMappingCache()
342 qry.setForwardOnly(
true);
343 qry.exec(
QString(
"select * from RDB$TIME_ZONES"_L1));
344 if (qry.lastError().type()) {
347 "failed to query time zone mapping from system table"),
348 qry.lastError().databaseText(),
350 qry.lastError().nativeErrorCode()));
356 auto record = qry.record();
359 qFbTzIdToIanaIdMap()->insert(fbTzId, ianaId);
360 qIanaIdToFbTzIdMap()->insert(ianaId, fbTzId);
379 qBufferDriverMap()->remove(
reinterpret_cast<void *
>(eBuffer->resultBuffer));
394 bool exec()
override;
454 localTransaction(!drv_d_func()->ibase),
456 ibase(drv_d_func()->ibase),
471 isc_dsql_free_statement(
status, &
stmt, DSQL_drop);
484 isc_blob_handle
handle = 0;
485 ISC_QUAD *bId = (ISC_QUAD*)
inda->sqlvar[iPos].sqldata;
504 isc_blob_handle
handle = 0;
511 unsigned short len = 0;
522 bool isErr = (
status[1] == isc_segstr_eof ?
false :
524 "Unable to read BLOB"),
548 short* numElements, ISC_ARRAY_DESC *arrayDesc)
550 const short dim = arrayDesc->array_desc_dimensions - 1;
551 const unsigned char dataType = arrayDesc->array_desc_dtype;
553 unsigned short strLen = arrayDesc->array_desc_length;
556 for(
int i = 0;
i < numElements[curDim]; ++
i)
567 for (
int i = 0;
i < numElements[dim]; ++
i) {
576 valList = toList<int>(&
buffer, numElements[dim]);
579 valList = toList<short>(&
buffer, numElements[dim]);
582 valList = toList<qint64>(&
buffer, numElements[dim]);
585 valList = toList<float>(&
buffer, numElements[dim]);
588 valList = toList<double>(&
buffer, numElements[dim]);
591 for(
int i = 0;
i < numElements[dim]; ++
i) {
593 buffer +=
sizeof(ISC_TIMESTAMP);
596#if (FB_API_VER >= 40)
597 case blr_timestamp_tz:
598 for (
int i = 0;
i < numElements[dim]; ++
i) {
600 buffer +=
sizeof(ISC_TIMESTAMP_TZ);
605 for (
int i = 0;
i < numElements[dim]; ++
i) {
607 buffer +=
sizeof(ISC_TIME);
611 for(
int i = 0;
i < numElements[dim]; ++
i) {
613 buffer +=
sizeof(ISC_DATE);
617 valList = toList<bool>(&
buffer, numElements[dim]);
645 int arraySize = 1, subArraySize;
646 short dimensions =
desc.array_desc_dimensions;
649 for(
int i = 0;
i < dimensions; ++
i) {
650 subArraySize = (
desc.array_desc_bounds[
i].array_bound_upper -
651 desc.array_desc_bounds[
i].array_bound_lower + 1);
652 numElements[
i] = subArraySize;
653 arraySize = subArraySize * arraySize;
661 if (
desc.array_desc_dtype == blr_varying
662 ||
desc.array_desc_dtype == blr_varying2) {
663 desc.array_desc_length += 2;
664 bufLen =
desc.array_desc_length * arraySize *
sizeof(short);
666 bufLen =
desc.array_desc_length * arraySize;
684 for (
const auto &elem :
list) {
685 T
val = qvariant_cast<T>(elem);
695 for (
const auto &elem :
list) {
696 double val = qvariant_cast<double>(elem);
697 float val2 = (float)
val;
698 memcpy(
buffer, &val2,
sizeof(
float));
705 short buflen,
bool varying,
bool array)
709 short tmpBuflen = buflen;
714 memset(
buffer + buflen, 0, tmpBuflen - buflen);
732 ISC_ARRAY_BOUND *bounds = arrayDesc->array_desc_bounds;
733 short dim = arrayDesc->array_desc_dimensions - 1;
735 int elements = (bounds[curDim].array_bound_upper -
736 bounds[curDim].array_bound_lower + 1);
739 error =
"Expected size: %1. Supplied size: %2"_L1;
740 error =
"Array size mismatch. Fieldname: %1 "_L1
746 for (
const auto &elem :
list) {
748 if (elem.typeId() != QMetaType::QVariantList) {
749 error =
"Array dimensons mismatch. Fieldname: %1"_L1;
761 case QMetaType::UInt:
762 if (arrayDesc->array_desc_dtype == blr_short)
767 case QMetaType::Double:
768 if (arrayDesc->array_desc_dtype == blr_float)
773 case QMetaType::LongLong:
776 case QMetaType::ULongLong:
779 case QMetaType::QString:
780 for (
const auto &elem :
list)
782 arrayDesc->array_desc_length,
783 arrayDesc->array_desc_dtype == blr_varying,
786 case QMetaType::QDate:
787 for (
const auto &elem :
list) {
789 buffer +=
sizeof(ISC_DATE);
792 case QMetaType::QTime:
793 for (
const auto &elem :
list) {
795 buffer +=
sizeof(ISC_TIME);
798 case QMetaType::QDateTime:
799 for (
const auto &elem :
list) {
800 switch (arrayDesc->array_desc_dtype) {
803 buffer +=
sizeof(ISC_TIMESTAMP);
805#if (FB_API_VER >= 40)
806 case blr_timestamp_tz:
807 *((ISC_TIMESTAMP_TZ*)
buffer) = toTimeStampTz(elem.toDateTime());
808 buffer +=
sizeof(ISC_TIMESTAMP_TZ);
816 case QMetaType::Bool:
830 ISC_QUAD *arrayId = (ISC_QUAD*)
inda->sqlvar[
column].sqldata;
844 short dimensions =
desc.array_desc_dimensions;
845 for(
int i = 0;
i < dimensions; ++
i) {
846 arraySize *= (
desc.array_desc_bounds[
i].array_bound_upper -
847 desc.array_desc_bounds[
i].array_bound_lower + 1);
853 if (
desc.array_desc_dtype == blr_varying ||
854 desc.array_desc_dtype == blr_varying2)
855 desc.array_desc_length += 2;
857 bufLen =
desc.array_desc_length * arraySize;
862 error =
"Array size mismatch: size of %1 is %2, size of provided list is %3"_L1;
877 if (
desc.array_desc_dtype == blr_varying
878 ||
desc.array_desc_dtype == blr_varying2)
879 desc.array_desc_length -= 2;
889 char qType = isc_info_sql_stmt_type;
890 isc_dsql_sql_info(
status, &
stmt, 1, &qType,
sizeof(acBuffer), acBuffer);
894 int iLength = isc_vax_integer(&acBuffer[1], 2);
895 queryType = isc_vax_integer(&acBuffer[3], iLength);
896 return (
queryType == isc_info_sql_stmt_select ||
queryType == isc_info_sql_stmt_exec_procedure);
903 if (drv_d_func()->
trans) {
905 trans = drv_d_func()->trans;
952 if (
d->sqlda == (XSQLDA*)0) {
953 qWarning()<<
"QIOBaseResult: createDA(): failed to allocate memory";
958 if (
d->inda == (XSQLDA*)0){
959 qWarning()<<
"QIOBaseResult: createDA(): failed to allocate memory";
963 if (!
d->transaction())
966 isc_dsql_allocate_statement(
d->status, &
d->ibase, &
d->stmt);
970 isc_dsql_prepare(
d->status, &
d->trans, &
d->stmt, 0,
976 isc_dsql_describe_bind(
d->status, &
d->stmt,
FBVERSION,
d->inda);
980 if (
d->inda->sqld >
d->inda->sqln) {
982 if (
d->inda == (XSQLDA*)0) {
983 qWarning()<<
"QIOBaseResult: enlargeDA(): failed to allocate memory";
987 isc_dsql_describe_bind(
d->status, &
d->stmt,
FBVERSION,
d->inda);
993 if (
d->sqlda->sqld >
d->sqlda->sqln) {
996 if (
d->sqlda == (XSQLDA*)0) {
997 qWarning()<<
"QIOBaseResult: enlargeDA(): failed to allocate memory";
1001 isc_dsql_describe(
d->status, &
d->stmt,
FBVERSION,
d->sqlda);
1032 if (
values.count() >
d->inda->sqld) {
1033 qWarning() <<
"QIBaseResult::exec: Parameter mismatch, expected"_L1 <<
1034 d->inda->sqld <<
", got"_L1 <<
values.count() <<
1039 if (!
d->inda->sqlvar[
para].sqldata)
1043 if (
d->inda->sqlvar[
para].sqltype & 1) {
1046 *(
d->inda->sqlvar[
para].sqlind) = -1;
1053 *(
d->inda->sqlvar[
para].sqlind) = 0;
1056 qWarning() <<
"QIBaseResult::exec: Null value replaced by default (zero)"_L1
1057 <<
"value for type of column"_L1 <<
d->inda->sqlvar[
para].ownname
1058 <<
", which is not nullable."_L1;
1061 switch(
d->inda->sqlvar[
para].sqltype & ~1) {
1063 if (
d->inda->sqlvar[
para].sqlscale < 0)
1065 (
qint64)floor(0.5 +
val.toDouble() * pow(10.0,
d->inda->sqlvar[
para].sqlscale * -1));
1070 if (
d->inda->sqlvar[
para].sqllen == 4) {
1071 if (
d->inda->sqlvar[
para].sqlscale < 0)
1073 (
qint32)floor(0.5 +
val.toDouble() * pow(10.0,
d->inda->sqlvar[
para].sqlscale * -1));
1081 if (
d->inda->sqlvar[
para].sqlscale < 0)
1082 *((
short*)
d->inda->sqlvar[
para].sqldata) =
1083 (short)floor(0.5 +
val.toDouble() * pow(10.0,
d->inda->sqlvar[
para].sqlscale * -1));
1085 *((
short*)
d->inda->sqlvar[
para].sqldata) = (short)
val.toInt();
1088 *((
float*)
d->inda->sqlvar[
para].sqldata) = (float)
val.toDouble();
1091 *((
double*)
d->inda->sqlvar[
para].sqldata) =
val.toDouble();
1096#if (FB_API_VER >= 40)
1097 case SQL_TIMESTAMP_TZ:
1098 *((ISC_TIMESTAMP_TZ*)
d->inda->sqlvar[
para].sqldata) = toTimeStampTz(
val.toDateTime());
1102 *((ISC_TIME*)
d->inda->sqlvar[
para].sqldata) =
toTime(
val.toTime());
1105 *((ISC_DATE*)
d->inda->sqlvar[
para].sqldata) =
toDate(
val.toDate());
1110 d->inda->sqlvar[
para].sqllen,
1111 (
d->inda->sqlvar[
para].sqltype & ~1) == SQL_VARYING,
false);
1120 *((
bool*)
d->inda->sqlvar[
para].sqldata) =
val.toBool();
1123 qWarning(
"QIBaseResult::exec: Unknown datatype %d",
1124 d->inda->sqlvar[
para].sqltype & ~1);
1131 isc_dsql_free_statement(
d->status, &
d->stmt, DSQL_close);
1134 if (
getIBaseError(imsg,
d->status, sqlcode) && sqlcode != -501) {
1140 if (
colCount() &&
d->queryType != isc_info_sql_stmt_exec_procedure) {
1143 if (
d->queryType == isc_info_sql_stmt_exec_procedure)
1144 isc_dsql_execute2(
d->status, &
d->trans, &
d->stmt,
FBVERSION,
d->inda,
d->sqlda);
1146 isc_dsql_execute(
d->status, &
d->trans, &
d->stmt,
FBVERSION,
d->inda);
1151 if (
d->queryType == isc_info_sql_stmt_exec_procedure &&
d->sqlda &&
d->sqlda->sqld == 0)
1155 init(
d->sqlda->sqld);
1176 ISC_STATUS stat = 0;
1180 if (
d->queryType == isc_info_sql_stmt_exec_procedure) {
1186 stat = isc_dsql_fetch(
d->status, &
d->stmt,
FBVERSION,
d->sqlda);
1200 for (
int i = 0;
i <
d->sqlda->sqld; ++
i) {
1201 int idx = rowIdx +
i;
1202 char *
buf =
d->sqlda->sqlvar[
i].sqldata;
1203 int size =
d->sqlda->sqlvar[
i].sqllen;
1206 if ((
d->sqlda->sqlvar[
i].sqltype & 1) && *
d->sqlda->sqlvar[
i].sqlind) {
1210 d->sqlda->sqlvar[
i].sqlscale < 0)));
1211 if (
v.userType() == QMetaType::Double) {
1231 switch(
d->sqlda->sqlvar[
i].sqltype & ~1) {
1237 if (
d->sqlda->sqlvar[
i].sqlscale < 0)
1238 row[idx] = *(
qint64*)
buf * pow(10.0,
d->sqlda->sqlvar[
i].sqlscale);
1243 if (
d->sqlda->sqlvar[
i].sqllen == 4)
1244 if (
d->sqlda->sqlvar[
i].sqlscale < 0)
1252 if (
d->sqlda->sqlvar[
i].sqlscale < 0)
1253 row[idx] =
QVariant(
long((*(
short*)
buf)) * pow(10.0,
d->sqlda->sqlvar[
i].sqlscale));
1276 row[idx] =
d->fetchBlob((ISC_QUAD*)
buf);
1279 row[idx] =
d->fetchArray(
i, (ISC_QUAD*)
buf);
1284#if (FB_API_VER >= 40)
1285 case SQL_TIMESTAMP_TZ:
1286 row[idx] = fromTimeStampTz(
buf);
1294 if (
d->sqlda->sqlvar[
i].sqlscale < 0) {
1302 if (
v.convert(
QMetaType(QMetaType::LongLong)))
1310 if (
v.convert(
QMetaType(QMetaType::QString)))
1325 static char sizeInfo[] = {isc_info_sql_records};
1336 isc_dsql_sql_info(
d->status, &
d->stmt,
sizeof(sizeInfo), sizeInfo,
sizeof(
buf),
buf);
1339 for(
int i = 0;
i < 66; ++
i)
1342 for (
char*
c =
buf + 3; *
c != isc_info_end; ) {
1344 len = isc_vax_integer(
c, 2);
1346 val = isc_vax_integer(
c,
len);
1349 if (ct == isc_info_req_select_count)
1355 unsigned int i, result_size;
1356 if (
buf[0] == isc_info_sql_records) {
1358 result_size = isc_vax_integer(&
buf[1],2);
1359 while (
buf[
i] != isc_info_end &&
i < result_size) {
1360 len = (short)isc_vax_integer(&
buf[
i+1],2);
1361 if (
buf[
i] == isc_info_req_select_count)
1362 return (isc_vax_integer(&
buf[
i+3],
len));
1374 static char acCountInfo[] = {isc_info_sql_records};
1376 bool bIsProcedure =
false;
1378 switch (
d->queryType) {
1379 case isc_info_sql_stmt_select:
1380 cCountType = isc_info_req_select_count;
1382 case isc_info_sql_stmt_update:
1383 cCountType = isc_info_req_update_count;
1385 case isc_info_sql_stmt_delete:
1386 cCountType = isc_info_req_delete_count;
1388 case isc_info_sql_stmt_insert:
1389 cCountType = isc_info_req_insert_count;
1391 case isc_info_sql_stmt_exec_procedure:
1392 bIsProcedure =
true;
1395 qWarning() <<
"numRowsAffected: Unknown statement type (" <<
d->queryType <<
")";
1401 isc_dsql_sql_info(
d->status, &
d->stmt,
sizeof(acCountInfo), acCountInfo,
sizeof(acBuffer), acBuffer);
1405 for (
char *pcBuf = acBuffer + 3; *pcBuf != isc_info_end; ) {
1406 char cType = *pcBuf++;
1407 short sLength = isc_vax_integer (pcBuf, 2);
1409 int iValue = isc_vax_integer (pcBuf, sLength);
1412 if (cType == isc_info_req_insert_count || cType == isc_info_req_update_count
1413 || cType == isc_info_req_delete_count) {
1418 }
else if (cType == cCountType) {
1434 for (
int i = 0;
i <
d->sqlda->sqld; ++
i) {
1435 v =
d->sqlda->sqlvar[
i];
1439 f.setLength(
v.sqllen);
1440 f.setPrecision(
qAbs(
v.sqlscale));
1442 if (
v.sqlscale < 0) {
1444 q.setForwardOnly(
true);
1445 q.exec(
"select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
1446 "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
1447 "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
1451 if (
v.sqlscale < 0) {
1452 f.setLength(
q.value(0).toInt());
1453 f.setPrecision(
qAbs(
q.value(1).toInt()));
1455 f.setLength(
q.value(2).toInt());
1461 f.setSqlType(
v.sqltype);
1470 return QVariant(QMetaType::fromType<isc_stmt_handle>(), &
d->stmt);
1531 for (
const auto &
opt : opts) {
1532 const auto tmp(
opt.trimmed());
1534 if ((idx = tmp.indexOf(u
'=')) != -1) {
1535 const auto val = tmp.mid(idx + 1).trimmed();
1536 const auto opt = tmp.left(idx).trimmed().toString();
1537 if (
opt.toUpper() ==
"ISC_DPB_SQL_ROLE_NAME"_L1) {
1538 role =
val.toLocal8Bit();
1553 ba.
append(
char(isc_dpb_user_name));
1564 ba.
append(
char(isc_dpb_sql_role_name));
1575 ldb += host + portString + u
':';
1587#if (FB_API_VER >= 40)
1588 std::call_once(initTZMappingFlag, [
d](){
d->initTZMappingCache(); });
1603 if (
d->eventBuffers.size()) {
1604 ISC_STATUS status[20];
1606 for (
i =
d->eventBuffers.constBegin();
i !=
d->eventBuffers.constEnd(); ++
i) {
1609 isc_cancel_events(status, &
d->ibase, &eBuffer->
eventId);
1612 d->eventBuffers.clear();
1615 isc_detach_database(
d->status, &
d->ibase);
1635 isc_start_transaction(
d->status, &
d->trans, 1, &
d->ibase, 0, NULL);
1648 isc_commit_transaction(
d->status, &
d->trans);
1650 return !
d->isError(
QT_TRANSLATE_NOOP(
"QIBaseDriver",
"Unable to commit transaction"),
1662 isc_rollback_transaction(
d->status, &
d->trans);
1664 return !
d->isError(
QT_TRANSLATE_NOOP(
"QIBaseDriver",
"Unable to rollback transaction"),
1677 typeFilter +=
"RDB$SYSTEM_FLAG != 0"_L1;
1679 typeFilter +=
"RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL"_L1;
1682 typeFilter +=
"RDB$SYSTEM_FLAG = 0 AND "_L1;
1684 typeFilter +=
"RDB$VIEW_BLR IS NULL AND "_L1;
1686 typeFilter +=
"RDB$VIEW_BLR IS NOT NULL AND "_L1;
1691 typeFilter.
prepend(
"where "_L1);
1694 q.setForwardOnly(
true);
1695 if (!
q.exec(
"select rdb$relation_name from rdb$relations "_L1 + typeFilter))
1698 res <<
q.value(0).toString().simplified();
1711 q.setForwardOnly(
true);
1712 q.exec(
"SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
1713 "b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
1714 "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
1715 "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
1716 "AND a.RDB$RELATION_NAME = '"_L1 +
table +
"' "
1717 "ORDER BY a.RDB$FIELD_POSITION"_L1);
1720 int type =
q.value(1).toInt();
1721 bool hasScale =
q.value(3).toInt() < 0;
1724 f.setLength(
q.value(4).toInt());
1725 f.setPrecision(
qAbs(
q.value(3).toInt()));
1727 f.setLength(
q.value(2).toInt());
1730 f.setRequired(
q.value(5).toInt() > 0);
1746 q.setForwardOnly(
true);
1747 q.exec(
"SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
1748 "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d "
1749 "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
1750 "AND a.RDB$RELATION_NAME = '"_L1 + tablename +
1751 " 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
1752 "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME "
1753 "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME "
1754 "AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE "
1755 "ORDER BY b.RDB$FIELD_POSITION"_L1);
1758 QSqlField field(
q.value(1).toString().simplified(),
1761 index.append(field);
1762 index.setName(
q.value(0).toString());
1771 case QMetaType::QDateTime: {
1785 case QMetaType::QTime: {
1796 case QMetaType::QDate: {
1813 return QVariant(QMetaType::fromType<isc_db_handle>(), &
d->ibase);
1839 qWarning(
"QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
1843 if (
d->eventBuffers.contains(
name)) {
1844 qWarning(
"QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%ls'.",
1854 name.toLocal8Bit().constData());
1857 qBufferDriverMap()->insert(eBuffer->
resultBuffer,
this);
1860 d->eventBuffers.insert(
name, eBuffer);
1862 ISC_STATUS status[20];
1863 isc_que_events(status,
1868 reinterpret_cast<ISC_EVENT_CALLBACK
>(
reinterpret_cast<void *
>
1872 if (status[0] == 1 && status[1]) {
1874 d->eventBuffers.remove(
name);
1886 qWarning(
"QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
1890 if (!
d->eventBuffers.contains(
name)) {
1891 qWarning(
"QIBaseDriver::QIBaseSubscriptionState not subscribed to '%ls'.",
1897 ISC_STATUS status[20];
1899 isc_cancel_events(status, &
d->ibase, &eBuffer->
eventId);
1901 if (status[0] == 1 && status[1]) {
1906 d->eventBuffers.remove(
name);
1918void QIBaseDriver::qHandleEventNotification(
void *updatedResultBuffer)
1922 for (
i =
d->eventBuffers.constBegin();
i !=
d->eventBuffers.constEnd(); ++
i) {
1924 if (
reinterpret_cast<void *
>(eBuffer->
resultBuffer) != updatedResultBuffer)
1927 ISC_ULONG counts[20];
1928 memset(counts, 0,
sizeof(counts));
1937 ISC_STATUS status[20];
1938 isc_que_events(status,
1943 reinterpret_cast<ISC_EVENT_CALLBACK
>(
reinterpret_cast<void *
>
1946 if (
Q_UNLIKELY(status[0] == 1 && status[1])) {
1947 qCritical(
"QIBaseDriver::qHandleEventNotification: could not resubscribe to '%ls'",
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.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
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 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.
QMetaType metaType() const
Returns the field's type as stored in the database.
QVariant value() const
Returns the value of the field as a QVariant.
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)
QString rightJustified(qsizetype width, QChar fill=u' ', bool trunc=false) const
Returns a string of size() width that contains the fill character followed by the string.
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...
void clear()
Clears the contents of the string and makes it null.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString simplified() const &
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.
bool isEmpty() const
Returns true if the string has no characters; 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 &
QString & prepend(QChar c)
qsizetype length() const
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 msecsTo(QTime t) const
Returns the number of milliseconds from this time to t.
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.
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.
DBusConnection const char DBusError * error
DBusConnection * connection
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
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 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
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent