748 SQLRETURN r = SQL_SUCCESS;
749 percentEncodePassword =
false;
750 for (
const auto connOpt : QStringTokenizer{connOpts, u';', Qt::SkipEmptyParts}) {
752 if ((idx = connOpt.indexOf(u'=')) == -1) {
753 qSqlWarning((
"QODBCDriver::open: Illegal connect option value '%1'"_L1)
754 .arg(connOpt),
this);
757 const auto opt(connOpt.left(idx));
758 const auto val(connOpt.mid(idx + 1).trimmed());
762 if (opt ==
"SQL_ATTR_ACCESS_MODE"_L1) {
763 if (val ==
"SQL_MODE_READ_ONLY"_L1) {
764 v = SQL_MODE_READ_ONLY;
765 }
else if (val ==
"SQL_MODE_READ_WRITE"_L1) {
766 v = SQL_MODE_READ_WRITE;
768 qSqlWarning((
"QODBCDriver::open: Unknown option value '%1'"_L1)
772 r = SQLSetConnectAttr(hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) size_t(v), 0);
773 }
else if (opt ==
"SQL_ATTR_CONNECTION_TIMEOUT"_L1) {
775 r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) size_t(v), 0);
776 }
else if (opt ==
"SQL_ATTR_LOGIN_TIMEOUT"_L1) {
778 r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
779 }
else if (opt ==
"SQL_ATTR_CURRENT_CATALOG"_L1) {
780 r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val);
781 }
else if (opt ==
"SQL_ATTR_METADATA_ID"_L1) {
782 if (val ==
"SQL_TRUE"_L1) {
784 }
else if (val ==
"SQL_FALSE"_L1) {
787 qSqlWarning((
"QODBCDriver::open: Unknown option value '%1'"_L1)
791 r = SQLSetConnectAttr(hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) size_t(v), 0);
792 }
else if (opt ==
"SQL_ATTR_PACKET_SIZE"_L1) {
794 r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
795 }
else if (opt ==
"SQL_ATTR_TRACEFILE"_L1) {
796 r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val);
797 }
else if (opt ==
"SQL_ATTR_TRACE"_L1) {
798 if (val ==
"SQL_OPT_TRACE_OFF"_L1) {
799 v = SQL_OPT_TRACE_OFF;
800 }
else if (val ==
"SQL_OPT_TRACE_ON"_L1) {
801 v = SQL_OPT_TRACE_ON;
803 qSqlWarning((
"QODBCDriver::open: Unknown option value '%1'"_L1)
807 r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACE, (SQLPOINTER) size_t(v), 0);
808 }
else if (opt ==
"SQL_ATTR_CONNECTION_POOLING"_L1) {
809 if (val ==
"SQL_CP_OFF"_L1)
811 else if (val ==
"SQL_CP_ONE_PER_DRIVER"_L1)
812 v = SQL_CP_ONE_PER_DRIVER;
813 else if (val ==
"SQL_CP_ONE_PER_HENV"_L1)
814 v = SQL_CP_ONE_PER_HENV;
815 else if (val ==
"SQL_CP_DEFAULT"_L1)
818 qSqlWarning((
"QODBCDriver::open: Unknown option value '%1'"_L1)
822 r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER) size_t(v), 0);
823 }
else if (opt ==
"SQL_ATTR_CP_MATCH"_L1) {
824 if (val ==
"SQL_CP_STRICT_MATCH"_L1)
825 v = SQL_CP_STRICT_MATCH;
826 else if (val ==
"SQL_CP_RELAXED_MATCH"_L1)
827 v = SQL_CP_RELAXED_MATCH;
828 else if (val ==
"SQL_CP_MATCH_DEFAULT"_L1)
829 v = SQL_CP_MATCH_DEFAULT;
831 qSqlWarning((
"QODBCDriver::open: Unknown option value '%1'"_L1)
835 r = SQLSetConnectAttr(hDbc, SQL_ATTR_CP_MATCH, (SQLPOINTER) size_t(v), 0);
836 }
else if (opt ==
"SQL_ATTR_ODBC_VERSION"_L1) {
839 }
else if (opt ==
"SQL_PERCENT_ENCODE_PASSWORD"_L1) {
840 percentEncodePassword =
true;
843 qSqlWarning((
"QODBCDriver::open: Unknown connection attribute '%1'"_L1)
846 if (!SQL_SUCCEEDED(r))
847 qSqlWarning((
"QODBCDriver::open: Unable to set connection attribute '%1'"_L1)
956 setAt(QSql::BeforeFirstRow);
958 d->fieldCache.clear();
959 d->fieldCacheIdx = 0;
964 if (d->hStmt && d->isStmtHandleValid()) {
965 r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
966 if (r != SQL_SUCCESS) {
967 qSqlWarning(
"QODBCResult::reset: Unable to free statement handle"_L1, d);
971 r = SQLAllocHandle(SQL_HANDLE_STMT,
974 if (r != SQL_SUCCESS) {
975 qSqlWarning(
"QODBCResult::reset: Unable to allocate statement handle"_L1, d);
979 d->updateStmtHandleState();
982 uint64_t sqlStmtVal = isForwardOnly() ? SQL_NONSCROLLABLE : SQL_SCROLLABLE;
983 r = SQLSetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, SQLPOINTER(sqlStmtVal), SQL_IS_UINTEGER);
984 if (!SQL_SUCCEEDED(r)) {
986 sqlStmtVal = isForwardOnly() ? SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
987 r = SQLSetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_TYPE, SQLPOINTER(sqlStmtVal), SQL_IS_UINTEGER);
988 if (!SQL_SUCCEEDED(r)) {
989 setLastError(qMakeError(
990 QCoreApplication::translate(
"QODBCResult",
991 "QODBCResult::reset: Unable to set 'SQL_ATTR_CURSOR_TYPE' "
992 "as statement attribute. "
993 "Please check your ODBC driver configuration"),
994 QSqlError::StatementError, d));
1000 auto encoded = toSQLTCHAR(query);
1001 r = SQLExecDirect(d->hStmt,
1003 SQLINTEGER(encoded.size()));
1005 if (!SQL_SUCCEEDED(r) && r!= SQL_NO_DATA) {
1006 setLastError(qMakeError(QCoreApplication::translate(
"QODBCResult",
1007 "Unable to execute statement"), QSqlError::StatementError, d));
1011 SQLULEN isScrollable = 0;
1012 r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
1013 if (SQL_SUCCEEDED(r))
1014 setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
1016 SQLSMALLINT count = 0;
1017 SQLNumResultCols(d->hStmt, &count);
1020 for (SQLSMALLINT i = 0; i < count; ++i)
1021 d->rInf.append(qMakeFieldInfo(d, i));
1022 d->fieldCache.resize(count);
1177 if (field >= d->rInf.count() || field < 0) {
1178 qSqlWarning((
"QODBCResult::data: column %1 out of range"_L1)
1179 .arg(QString::number(field)), d);
1182 if (field < d->fieldCacheIdx)
1183 return d->fieldCache.at(field);
1186 SQLLEN lengthIndicator = 0;
1188 for (
int i = d->fieldCacheIdx; i <= field; ++i) {
1191 const QSqlField info = d->rInf.field(i);
1192 const auto metaTypeId = info.metaType().id();
1193 switch (metaTypeId) {
1194 case QMetaType::LongLong:
1195 d->fieldCache[i] = qGetIntData<int64_t>(d->hStmt, i);
1197 case QMetaType::Int:
1198 d->fieldCache[i] = qGetIntData<int32_t>(d->hStmt, i);
1200 case QMetaType::Short:
1201 d->fieldCache[i] = qGetIntData<int16_t>(d->hStmt, i);
1203 case QMetaType::ULongLong:
1204 d->fieldCache[i] = qGetIntData<uint64_t>(d->hStmt, i);
1206 case QMetaType::UInt:
1207 d->fieldCache[i] = qGetIntData<uint32_t>(d->hStmt, i);
1209 case QMetaType::UShort:
1210 d->fieldCache[i] = qGetIntData<uint16_t>(d->hStmt, i);
1212 case QMetaType::QDate:
1214 r = SQLGetData(d->hStmt,
1220 if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
1221 d->fieldCache[i] = QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
1223 d->fieldCache[i] = QVariant(QMetaType::fromType<QDate>());
1225 case QMetaType::QTime:
1227 r = SQLGetData(d->hStmt,
1233 if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
1234 d->fieldCache[i] = QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
1236 d->fieldCache[i] = QVariant(QMetaType::fromType<QTime>());
1238 case QMetaType::QDateTime:
1239 TIMESTAMP_STRUCT dtbuf;
1240 r = SQLGetData(d->hStmt,
1246 if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
1247 d->fieldCache[i] = QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
1248 QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
1250 d->fieldCache[i] = QVariant(QMetaType::fromType<QDateTime>());
1252 case QMetaType::QByteArray:
1253 d->fieldCache[i] = qGetBinaryData(d->hStmt, i);
1255 case QMetaType::QString:
1256 d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), d->unicode);
1258 case QMetaType::Float:
1259 case QMetaType::Double:
1260 switch (numericalPrecisionPolicy()) {
1261 case QSql::LowPrecisionInt32:
1262 d->fieldCache[i] = qGetIntData<int32_t>(d->hStmt, i);
1264 case QSql::LowPrecisionInt64:
1265 d->fieldCache[i] = qGetIntData<int64_t>(d->hStmt, i);
1267 case QSql::LowPrecisionDouble:
1268 if (metaTypeId == QMetaType::Float)
1269 d->fieldCache[i] = qGetFloatingPointData<
float>(d->hStmt, i);
1271 d->fieldCache[i] = qGetFloatingPointData<
double>(d->hStmt, i);
1273 case QSql::HighPrecision:
1274 d->fieldCache[i] = qGetStringData(d->hStmt, i, -1,
false);
1279 d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(),
false);
1282 d->fieldCacheIdx = field + 1;
1284 return d->fieldCache[field];
1382 setAt(QSql::BeforeFirstRow);
1384 d->fieldCache.clear();
1385 d->fieldCacheIdx = 0;
1388 qSqlWarning(
"QODBCResult::exec: No statement handle available"_L1, d);
1393 SQLCloseCursor(d->hStmt);
1395 QVariantList &values = boundValues();
1396 QByteArrayList tmpStorage(values.count(), QByteArray());
1397 QVarLengthArray<SQLLEN, 32> indicators(values.count(), 0);
1401 for (qsizetype i = 0; i < values.count(); ++i) {
1402 if (bindValueType(i) & QSql::Out)
1404 const QVariant &val = values.at(i);
1405 SQLLEN *ind = &indicators[i];
1406 if (QSqlResultPrivate::isVariantNull(val))
1407 *ind = SQL_NULL_DATA;
1408 switch (val.typeId()) {
1409 case QMetaType::QDate: {
1410 QByteArray &ba = tmpStorage[i];
1411 ba.resize(
sizeof(DATE_STRUCT));
1412 DATE_STRUCT *dt = (DATE_STRUCT *)
const_cast<
char *>(ba.constData());
1413 QDate qdt = val.toDate();
1414 dt->year = qdt.year();
1415 dt->month = qdt.month();
1416 dt->day = qdt.day();
1417 r = SQLBindParameter(d->hStmt,
1419 qParamType[bindValueType(i) & QSql::InOut],
1426 *ind == SQL_NULL_DATA ? ind : NULL);
1428 case QMetaType::QTime: {
1429 QByteArray &ba = tmpStorage[i];
1430 ba.resize(
sizeof(TIME_STRUCT));
1431 TIME_STRUCT *dt = (TIME_STRUCT *)
const_cast<
char *>(ba.constData());
1432 QTime qdt = val.toTime();
1433 dt->hour = qdt.hour();
1434 dt->minute = qdt.minute();
1435 dt->second = qdt.second();
1436 r = SQLBindParameter(d->hStmt,
1438 qParamType[bindValueType(i) & QSql::InOut],
1445 *ind == SQL_NULL_DATA ? ind : NULL);
1447 case QMetaType::QDateTime: {
1448 QByteArray &ba = tmpStorage[i];
1449 ba.resize(
sizeof(TIMESTAMP_STRUCT));
1450 TIMESTAMP_STRUCT *dt =
reinterpret_cast<TIMESTAMP_STRUCT *>(
const_cast<
char *>(ba.constData()));
1451 const QDateTime qdt = val.toDateTime();
1452 const QDate qdate = qdt.date();
1453 const QTime qtime = qdt.time();
1454 dt->year = qdate.year();
1455 dt->month = qdate.month();
1456 dt->day = qdate.day();
1457 dt->hour = qtime.hour();
1458 dt->minute = qtime.minute();
1459 dt->second = qtime.second();
1461 const int precision = d->drv_d_func()->datetimePrecision - 20;
1462 if (precision <= 0) {
1465 dt->fraction = qtime.msec() * 1000000;
1468 int keep = (
int)qPow(10.0, 9 - qMin(9, precision));
1469 dt->fraction = (dt->fraction / keep) * keep;
1472 r = SQLBindParameter(d->hStmt,
1474 qParamType[bindValueType(i) & QSql::InOut],
1477 d->drv_d_func()->datetimePrecision,
1481 *ind == SQL_NULL_DATA ? ind : NULL);
1483 case QMetaType::Int:
1484 r = SQLBindParameter(d->hStmt,
1486 qParamType[bindValueType(i) & QSql::InOut],
1491 const_cast<
void *>(val.constData()),
1493 *ind == SQL_NULL_DATA ? ind : NULL);
1495 case QMetaType::UInt:
1496 r = SQLBindParameter(d->hStmt,
1498 qParamType[bindValueType(i) & QSql::InOut],
1503 const_cast<
void *>(val.constData()),
1505 *ind == SQL_NULL_DATA ? ind : NULL);
1507 case QMetaType::Short:
1508 r = SQLBindParameter(d->hStmt,
1510 qParamType[bindValueType(i) & QSql::InOut],
1515 const_cast<
void *>(val.constData()),
1517 *ind == SQL_NULL_DATA ? ind : NULL);
1519 case QMetaType::UShort:
1520 r = SQLBindParameter(d->hStmt,
1522 qParamType[bindValueType(i) & QSql::InOut],
1527 const_cast<
void *>(val.constData()),
1529 *ind == SQL_NULL_DATA ? ind : NULL);
1531 case QMetaType::Double:
1532 r = SQLBindParameter(d->hStmt,
1534 qParamType[bindValueType(i) & QSql::InOut],
1539 const_cast<
void *>(val.constData()),
1541 *ind == SQL_NULL_DATA ? ind : NULL);
1543 case QMetaType::Float:
1544 r = SQLBindParameter(d->hStmt,
1546 qParamType[bindValueType(i) & QSql::InOut],
1551 const_cast<
void *>(val.constData()),
1553 *ind == SQL_NULL_DATA ? ind : NULL);
1555 case QMetaType::LongLong:
1556 r = SQLBindParameter(d->hStmt,
1558 qParamType[bindValueType(i) & QSql::InOut],
1563 const_cast<
void *>(val.constData()),
1565 *ind == SQL_NULL_DATA ? ind : NULL);
1567 case QMetaType::ULongLong:
1568 r = SQLBindParameter(d->hStmt,
1570 qParamType[bindValueType(i) & QSql::InOut],
1575 const_cast<
void *>(val.constData()),
1577 *ind == SQL_NULL_DATA ? ind : NULL);
1579 case QMetaType::QByteArray:
1580 if (*ind != SQL_NULL_DATA) {
1581 *ind = val.toByteArray().size();
1583 r = SQLBindParameter(d->hStmt,
1585 qParamType[bindValueType(i) & QSql::InOut],
1588 val.toByteArray().size(),
1590 const_cast<
char *>(val.toByteArray().constData()),
1591 val.toByteArray().size(),
1594 case QMetaType::Bool:
1595 r = SQLBindParameter(d->hStmt,
1597 qParamType[bindValueType(i) & QSql::InOut],
1602 const_cast<
void *>(val.constData()),
1604 *ind == SQL_NULL_DATA ? ind : NULL);
1606 case QMetaType::QString:
1608 QByteArray &ba = tmpStorage[i];
1610 const auto encoded = toSQLTCHAR(val.toString());
1611 ba = QByteArray(
reinterpret_cast<
const char *>(encoded.data()),
1612 encoded.size() *
sizeof(SQLTCHAR));
1615 if (*ind != SQL_NULL_DATA)
1618 if (bindValueType(i) & QSql::Out) {
1619 r = SQLBindParameter(d->hStmt,
1621 qParamType[bindValueType(i) & QSql::InOut],
1623 ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
1626 const_cast<
char *>(ba.constData()),
1631 r = SQLBindParameter(d->hStmt,
1633 qParamType[bindValueType(i) & QSql::InOut],
1635 ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
1638 const_cast<
char *>(ba.constData()),
1645 QByteArray &str = tmpStorage[i];
1646 str = val.toString().toUtf8();
1647 if (*ind != SQL_NULL_DATA)
1648 *ind = str.length();
1649 int strSize = str.length();
1651 r = SQLBindParameter(d->hStmt,
1653 qParamType[bindValueType(i) & QSql::InOut],
1655 strSize > 254 ? SQL_LONGVARCHAR : SQL_VARCHAR,
1658 const_cast<
char *>(str.constData()),
1665 QByteArray &ba = tmpStorage[i];
1666 if (*ind != SQL_NULL_DATA)
1668 r = SQLBindParameter(d->hStmt,
1670 qParamType[bindValueType(i) & QSql::InOut],
1675 const_cast<
char *>(ba.constData()),
1680 if (r != SQL_SUCCESS) {
1681 qSqlWarning(
"QODBCResult::exec: unable to bind variable:"_L1, d);
1682 setLastError(qMakeError(QCoreApplication::translate(
"QODBCResult",
1683 "Unable to bind variable"), QSqlError::StatementError, d));
1687 r = SQLExecute(d->hStmt);
1688 if (!SQL_SUCCEEDED(r) && r != SQL_NO_DATA) {
1689 qSqlWarning(
"QODBCResult::exec: Unable to execute statement:"_L1, d);
1690 setLastError(qMakeError(QCoreApplication::translate(
"QODBCResult",
1691 "Unable to execute statement"), QSqlError::StatementError, d));
1695 SQLULEN isScrollable = 0;
1696 r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
1697 if (SQL_SUCCEEDED(r))
1698 setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
1700 SQLSMALLINT count = 0;
1701 SQLNumResultCols(d->hStmt, &count);
1704 for (SQLSMALLINT i = 0; i < count; ++i)
1705 d->rInf.append(qMakeFieldInfo(d, i));
1706 d->fieldCache.resize(count);
1714 if (!hasOutValues())
1717 for (qsizetype i = 0; i < values.count(); ++i) {
1718 switch (values.at(i).typeId()) {
1719 case QMetaType::QDate: {
1720 DATE_STRUCT ds = *((DATE_STRUCT *)
const_cast<
char *>(tmpStorage.at(i).constData()));
1721 values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
1723 case QMetaType::QTime: {
1724 TIME_STRUCT dt = *((TIME_STRUCT *)
const_cast<
char *>(tmpStorage.at(i).constData()));
1725 values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
1727 case QMetaType::QDateTime: {
1728 TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT*)
1729 const_cast<
char *>(tmpStorage.at(i).constData()));
1730 values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
1731 QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
1733 case QMetaType::Bool:
1734 case QMetaType::Short:
1735 case QMetaType::UShort:
1736 case QMetaType::Int:
1737 case QMetaType::UInt:
1738 case QMetaType::Float:
1739 case QMetaType::Double:
1740 case QMetaType::QByteArray:
1741 case QMetaType::LongLong:
1742 case QMetaType::ULongLong:
1745 case QMetaType::QString:
1747 if (bindValueType(i) & QSql::Out) {
1748 const QByteArray &bytes = tmpStorage.at(i);
1749 const auto strSize = bytes.size() /
sizeof(SQLTCHAR);
1750 QVarLengthArray<SQLTCHAR> string(strSize);
1751 memcpy(string.data(), bytes.data(), strSize *
sizeof(SQLTCHAR));
1752 values[i] = fromSQLTCHAR(string);
1758 if (bindValueType(i) & QSql::Out)
1759 values[i] = tmpStorage.at(i);
1762 if (indicators[i] == SQL_NULL_DATA)
1763 values[i] = QVariant(values[i].metaType());