diff options
Diffstat (limited to 'src/plugins/sqldrivers/oci/qsql_oci.cpp')
-rw-r--r-- | src/plugins/sqldrivers/oci/qsql_oci.cpp | 191 |
1 files changed, 94 insertions, 97 deletions
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp index b670efc15b..9af1342e5b 100644 --- a/src/plugins/sqldrivers/oci/qsql_oci.cpp +++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp @@ -7,6 +7,7 @@ #include <qdatetime.h> #include <qdebug.h> #include <qlist.h> +#include <qloggingcategory.h> #include <qmetatype.h> #if QT_CONFIG(regularexpression) #include <qregularexpression.h> @@ -30,14 +31,7 @@ #define _int64 __int64 #endif - #include <oci.h> -#ifdef max -#undef max -#endif -#ifdef min -#undef min -#endif #include <stdlib.h> @@ -51,13 +45,17 @@ //#define QOCI_DEBUG -Q_DECLARE_OPAQUE_POINTER(OCIEnv*); +Q_DECLARE_OPAQUE_POINTER(QOCIResult*) +Q_DECLARE_METATYPE(QOCIResult*) +Q_DECLARE_OPAQUE_POINTER(OCIEnv*) Q_DECLARE_METATYPE(OCIEnv*) -Q_DECLARE_OPAQUE_POINTER(OCIStmt*); +Q_DECLARE_OPAQUE_POINTER(OCIStmt*) Q_DECLARE_METATYPE(OCIStmt*) QT_BEGIN_NAMESPACE +Q_STATIC_LOGGING_CATEGORY(lcOci, "qt.sql.oci") + using namespace Qt::StringLiterals; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN @@ -207,31 +205,6 @@ public: }; class QOCICols; -class QOCIResultPrivate; - -class QOCIResult: public QSqlCachedResult -{ - Q_DECLARE_PRIVATE(QOCIResult) - friend class QOCIDriver; - friend class QOCICols; -public: - QOCIResult(const QOCIDriver *db); - ~QOCIResult(); - bool prepare(const QString &query) override; - bool exec() override; - QVariant handle() const override; - -protected: - bool gotoNext(ValueCache &values, int index) override; - bool reset(const QString &query) override; - int size() override; - int numRowsAffected() override; - QSqlRecord record() const override; - QVariant lastInsertId() const override; - bool execBatch(bool arrayBind = false) override; - void virtual_hook(int id, void *data) override; - bool fetchNext() override; -}; class QOCIResultPrivate: public QSqlCachedResultPrivate { @@ -280,7 +253,7 @@ public: 0); #ifdef QOCI_DEBUG if (r != 0) - qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM."); + qCWarning(lcOci, "QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM."); #endif #endif @@ -439,8 +412,20 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in const_cast<OCIRowid **>(&rptr->id), -1, SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + } else if (val.canConvert<QOCIResult *>() && isOutValue(pos)) { + QOCIResult *res = qvariant_cast<QOCIResult *>(val); + + if (res->internal_prepare()) { + r = OCIBindByPos(sql, hbnd, err, + pos + 1, + const_cast<OCIStmt **>(&res->d->sql), + (sb4)0, + SQLT_RSET, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + + res->isCursor = true; + } } else { - qWarning("Unknown bind variable"); + qCWarning(lcOci, "Unknown bind variable"); r = OCI_ERROR; } } else { @@ -556,7 +541,7 @@ void QOCIDriverPrivate::allocErrorHandle() OCI_HTYPE_ERROR, 0, nullptr); if (r != OCI_SUCCESS) - qWarning("QOCIDriver: unable to allocate error handle"); + qCWarning(lcOci, "QOCIDriver: unable to allocate error handle"); } struct OraFieldInfo @@ -592,12 +577,7 @@ QString qOraWarn(OCIError *err, int *errorCode) void qOraWarning(const char* msg, OCIError *err) { -#ifdef QOCI_DEBUG - qWarning("%s %s", msg, qPrintable(qOraWarn(err))); -#else - Q_UNUSED(msg); - Q_UNUSED(err); -#endif + qCWarning(lcOci, "%s %ls", msg, qUtf16Printable(qOraWarn(err))); } static int qOraErrorNumber(OCIError *err) @@ -660,7 +640,7 @@ QMetaType qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy else if (ocitype == "UNDEFINED"_L1) type = QMetaType::UnknownType; if (type == QMetaType::UnknownType) - qWarning("qDecodeOCIType: unknown type: %s", ocitype.toLocal8Bit().constData()); + qCWarning(lcOci, "qDecodeOCIType: unknown type: %ls", qUtf16Printable(ocitype)); return QMetaType(type); } @@ -728,7 +708,7 @@ QMetaType qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precisionPo type = QMetaType::QDateTime; break; default: - qWarning("qDecodeOCIType: unknown OCI datatype: %d", ocitype); + qCWarning(lcOci, "qDecodeOCIType: unknown OCI datatype: %d", ocitype); break; } return QMetaType(type); @@ -745,7 +725,6 @@ static QSqlField qFromOraInf(const OraFieldInfo &ofi) f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision)); f.setPrecision(ofi.oraScale); - f.setSqlType(int(ofi.oraType)); return f; } @@ -844,7 +823,7 @@ QOCICols::OraFieldInf::~OraFieldInf() if (lob) { int r = OCIDescriptorFree(lob, OCI_DTYPE_LOB); if (r != 0) - qWarning("QOCICols: Cannot free LOB descriptor"); + qCWarning(lcOci, "QOCICols: Cannot free LOB descriptor"); } if (dataPtr) { switch (typ.id()) { @@ -853,7 +832,7 @@ QOCICols::OraFieldInf::~OraFieldInf() case QMetaType::QDateTime: { int r = OCIDescriptorFree(dataPtr, OCI_DTYPE_TIMESTAMP_TZ); if (r != OCI_SUCCESS) - qWarning("QOCICols: Cannot free OCIDateTime descriptor"); + qCWarning(lcOci, "QOCICols: Cannot free OCIDateTime descriptor"); break; } default: @@ -908,7 +887,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp) case QMetaType::QDateTime: r = OCIDescriptorAlloc(d->env, (void **)&fieldInf[idx].dataPtr, OCI_DTYPE_TIMESTAMP_TZ, 0, 0); if (r != OCI_SUCCESS) { - qWarning("QOCICols: Unable to allocate the OCIDateTime descriptor"); + qCWarning(lcOci, "QOCICols: Unable to allocate the OCIDateTime descriptor"); break; } r = OCIDefineByPos(d->sql, @@ -1079,7 +1058,7 @@ OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env) 0, 0); if (r != 0) { - qWarning("QOCICols: Cannot create LOB locator"); + qCWarning(lcOci, "QOCICols: Cannot create LOB locator"); lob = 0; } return &lob; @@ -1317,7 +1296,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a return false; #ifdef QOCI_DEBUG - qDebug() << "columnCount:" << columnCount << boundValues; + qCDebug(lcOci) << "columnCount:" << columnCount << boundValues; #endif int i; @@ -1436,7 +1415,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a // we may now populate column with data for (uint row = 0; row < col.recordCount; ++row) { - const QVariant &val = boundValues.at(i).toList().at(row); + const QVariant val = boundValues.at(i).toList().at(row); if (QSqlResultPrivate::isVariantNull(val) && !d->isOutValue(i)) { columns[i].indicators[row] = -1; @@ -1514,13 +1493,13 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a QOCIBatchColumn &bindColumn = columns[i]; #ifdef QOCI_DEBUG - qDebug("OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)", + qCDebug(lcOci, "OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)", d->sql, &bindColumn.bindh, d->err, i + 1, bindColumn.data, bindColumn.maxLen, bindColumn.bindAs, bindColumn.indicators, bindColumn.lengths, arrayBind ? bindColumn.maxarr_len : 0, arrayBind ? &bindColumn.curelep : 0); for (int ii = 0; ii < (int)bindColumn.recordCount; ++ii) { - qDebug(" record %d: indicator %d, length %d", ii, bindColumn.indicators[ii], + qCDebug(lcOci, " record %d: indicator %d, length %d", ii, bindColumn.indicators[ii], bindColumn.lengths[ii]); } #endif @@ -1540,7 +1519,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a OCI_DEFAULT); #ifdef QOCI_DEBUG - qDebug("After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh); + qCDebug(lcOci, "After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh); #endif if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { @@ -1800,7 +1779,7 @@ void QOCICols::getValues(QVariantList &v, int index) v[index + i] = QVariant(QMetaType(QMetaType::QByteArray)); break; default: - qWarning("QOCICols::value: unknown data type"); + qCWarning(lcOci, "QOCICols::value: unknown data type"); break; } } @@ -1821,7 +1800,7 @@ QOCIResultPrivate::QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv) OCI_HTYPE_ERROR, 0, nullptr); if (r != OCI_SUCCESS) - qWarning("QOCIResult: unable to alloc error handle"); + qCWarning(lcOci, "QOCIResult: unable to alloc error handle"); } QOCIResultPrivate::~QOCIResultPrivate() @@ -1829,10 +1808,10 @@ QOCIResultPrivate::~QOCIResultPrivate() delete cols; if (sql && OCIHandleFree(sql, OCI_HTYPE_STMT) != OCI_SUCCESS) - qWarning("~QOCIResult: unable to free statement handle"); + qCWarning(lcOci, "~QOCIResult: unable to free statement handle"); if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) - qWarning("~QOCIResult: unable to free error report handle"); + qCWarning(lcOci, "~QOCIResult: unable to free error report handle"); } @@ -1841,6 +1820,7 @@ QOCIResultPrivate::~QOCIResultPrivate() QOCIResult::QOCIResult(const QOCIDriver *db) : QSqlCachedResult(*new QOCIResultPrivate(this, db)) { + isCursor = false; } QOCIResult::~QOCIResult() @@ -1889,7 +1869,7 @@ bool QOCIResult::gotoNext(QSqlCachedResult::ValueCache &values, int index) break; case OCI_ERROR: if (qOraErrorNumber(d->err) == 1406) { - qWarning("QOCI Warning: data truncated for %s", lastQuery().toLocal8Bit().constData()); + qCWarning(lcOci, "QOCI Warning: data truncated for %ls", qUtf16Printable(lastQuery())); r = OCI_SUCCESS; /* ignore it */ break; } @@ -1933,11 +1913,12 @@ int QOCIResult::numRowsAffected() return rowCount; } -bool QOCIResult::prepare(const QString& query) ++bool QOCIResult::internal_prepare() { Q_D(QOCIResult); int r = 0; - QSqlResult::prepare(query); + QString noStr; + QSqlResult::prepare(noStr); delete d->cols; d->cols = nullptr; @@ -1950,8 +1931,7 @@ bool QOCIResult::prepare(const QString& query) else qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err); } - if (query.isEmpty()) - return false; + r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->sql), OCI_HTYPE_STMT, @@ -1963,6 +1943,19 @@ bool QOCIResult::prepare(const QString& query) return false; } d->setStatementAttributes(); + + return true; +} + +bool QOCIResult::prepare(const QString& query) +{ + if (query.isEmpty()) + return false; + + if (!internal_prepare()) + return false; + + int r; const OraText *txt = reinterpret_cast<const OraText *>(query.utf16()); const int len = query.length() * sizeof(QChar); r = OCIStmtPrepare(d->sql, @@ -2003,7 +1996,7 @@ bool QOCIResult::exec() setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to get statement type"), QSqlError::StatementError, d->err)); #ifdef QOCI_DEBUG - qDebug() << "lastQuery()" << lastQuery(); + qCDebug(lcOci) << "lastQuery()" << lastQuery(); #endif return false; } @@ -2018,28 +2011,30 @@ bool QOCIResult::exec() setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind value"), QSqlError::StatementError, d->err)); #ifdef QOCI_DEBUG - qDebug() << "lastQuery()" << lastQuery(); + qCDebug(lcOci) << "lastQuery()" << lastQuery(); #endif return false; } - // execute - r = OCIStmtExecute(d->svc, - d->sql, - d->err, - iters, - 0, - 0, - 0, - mode); - if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { - qOraWarning("QOCIResult::exec: unable to execute statement:", d->err); - setLastError(qMakeError(QCoreApplication::translate("QOCIResult", - "Unable to execute statement"), QSqlError::StatementError, d->err)); -#ifdef QOCI_DEBUG - qDebug() << "lastQuery()" << lastQuery(); -#endif - return false; + if (!isCursor()) { + // execute + r = OCIStmtExecute(d->svc, + d->sql, + d->err, + iters, + 0, + 0, + 0, + mode); + if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { + qOraWarning("QOCIResult::exec: unable to execute statement:", d->err); + setLastError(qMakeError(QCoreApplication::translate("QOCIResult", + "Unable to execute statement"), QSqlError::StatementError, d->err)); + #ifdef QOCI_DEBUG + qCDebug(lcOci) << "lastQuery()" << lastQuery(); + #endif + return false; + } } if (stmtType == OCI_STMT_SELECT) { @@ -2129,7 +2124,7 @@ QOCIDriver::QOCIDriver(QObject* parent) 0, NULL); if (r != 0) { - qWarning("QOCIDriver: unable to create environment"); + qCWarning(lcOci, "QOCIDriver: unable to create environment"); setLastError(qMakeError(tr("Unable to initialize", "QOCIDriver"), QSqlError::ConnectionError, d->err)); return; @@ -2160,10 +2155,10 @@ QOCIDriver::~QOCIDriver() close(); int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR); if (r != OCI_SUCCESS) - qWarning("Unable to free Error handle: %d", r); + qCWarning(lcOci, "Unable to free Error handle: %d", r); r = OCIHandleFree(d->env, OCI_HTYPE_ENV); if (r != OCI_SUCCESS) - qWarning("Unable to free Environment handle: %d", r); + qCWarning(lcOci, "Unable to free Environment handle: %d", r); } bool QOCIDriver::hasFeature(DriverFeature f) const @@ -2198,8 +2193,8 @@ static void qParseOpts(const QString &options, QOCIDriverPrivate *d) for (const auto tmp : opts) { qsizetype idx; if ((idx = tmp.indexOf(u'=')) == -1) { - qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'", - tmp.toLocal8Bit().constData()); + qCWarning(lcOci, "QOCIDriver::parseArgs: Invalid parameter: '%ls'", + qUtf16Printable(tmp.toString())); continue; } const QStringView opt = tmp.left(idx); @@ -2219,12 +2214,12 @@ static void qParseOpts(const QString &options, QOCIDriverPrivate *d) } else if (val == "OCI_SYSOPER"_L1) { d->authMode = OCI_SYSOPER; } else if (val != "OCI_DEFAULT"_L1) { - qWarning("QOCIDriver::parseArgs: Unsupported value for OCI_AUTH_MODE: '%s'", - val.toLocal8Bit().constData()); + qCWarning(lcOci, "QOCIDriver::parseArgs: Unsupported value for OCI_AUTH_MODE: '%ls'", + qUtf16Printable(val.toString())); } } else { - qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'", - opt.toLocal8Bit().constData()); + qCWarning(lcOci, "QOCIDriver::parseArgs: Invalid parameter: '%ls'", + qUtf16Printable(opt.toString())); } } } @@ -2321,7 +2316,7 @@ bool QOCIDriver::open(const QString & db, sizeof(vertxt), OCI_HTYPE_SVCCTX); if (r != 0) { - qWarning("QOCIDriver::open: could not get Oracle server version."); + qCWarning(lcOci, "QOCIDriver::open: could not get Oracle server version."); } else { QString versionStr; versionStr = QString(reinterpret_cast<const QChar *>(vertxt)); @@ -2370,7 +2365,7 @@ bool QOCIDriver::beginTransaction() { Q_D(QOCIDriver); if (!isOpen()) { - qWarning("QOCIDriver::beginTransaction: Database not open"); + qCWarning(lcOci, "QOCIDriver::beginTransaction: Database not open"); return false; } int r = OCITransStart(d->svc, @@ -2391,7 +2386,7 @@ bool QOCIDriver::commitTransaction() { Q_D(QOCIDriver); if (!isOpen()) { - qWarning("QOCIDriver::commitTransaction: Database not open"); + qCWarning(lcOci, "QOCIDriver::commitTransaction: Database not open"); return false; } int r = OCITransCommit(d->svc, @@ -2411,7 +2406,7 @@ bool QOCIDriver::rollbackTransaction() { Q_D(QOCIDriver); if (!isOpen()) { - qWarning("QOCIDriver::rollbackTransaction: Database not open"); + qCWarning(lcOci, "QOCIDriver::rollbackTransaction: Database not open"); return false; } int r = OCITransRollback(d->svc, @@ -2691,7 +2686,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const { - switch (field.typeID()) { + switch (field.metaType().id()) { case QMetaType::QDateTime: { QDateTime datetime = field.value().toDateTime(); QString datestring; @@ -2767,3 +2762,5 @@ int QOCIDriver::maximumIdentifierLength(IdentifierType type) const } QT_END_NAMESPACE + +#include "moc_qsql_oci_p.cpp" |