OCI: allow accessing results of PL/SQL procedure calls returning a REF CURSOR
Move the QOCIResult implementation of QSqlCachedResult into the private qsql_oci_p.h header, and register it as a meta type that we can pass through QVariant. Add a field that indicates whether that results represents a cursor variable, and bind it to the statement handle if so. Fixes: QTBUG-166 Fixes: QTBUG-44643 Change-Id: Iafbf5474ad7efc6d24eb52a5c5a1b3d2b6842387 Reviewed-by: Andy Shaw <andy.shaw@qt.io>
This commit is contained in:
parent
334d4c7b69
commit
82681fd8a2
@ -45,9 +45,11 @@
|
||||
|
||||
//#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
|
||||
@ -203,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
|
||||
{
|
||||
@ -435,6 +412,18 @@ 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 {
|
||||
qCWarning(lcOci, "Unknown bind variable");
|
||||
r = OCI_ERROR;
|
||||
@ -1831,6 +1820,7 @@ QOCIResultPrivate::~QOCIResultPrivate()
|
||||
QOCIResult::QOCIResult(const QOCIDriver *db)
|
||||
: QSqlCachedResult(*new QOCIResultPrivate(this, db))
|
||||
{
|
||||
isCursor = false;
|
||||
}
|
||||
|
||||
QOCIResult::~QOCIResult()
|
||||
@ -1923,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;
|
||||
@ -1940,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,
|
||||
@ -1953,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,
|
||||
@ -2013,23 +2016,25 @@ bool QOCIResult::exec()
|
||||
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
|
||||
qCDebug(lcOci) << "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) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
//
|
||||
|
||||
#include <QtSql/qsqldriver.h>
|
||||
#include <QtSql/private/qsqlcachedresult_p.h>
|
||||
|
||||
#ifdef QT_PLUGIN
|
||||
#define Q_EXPORT_SQLDRIVER_OCI
|
||||
@ -25,6 +26,7 @@
|
||||
|
||||
typedef struct OCIEnv OCIEnv;
|
||||
typedef struct OCISvcCtx OCISvcCtx;
|
||||
struct QOCIResultPrivate;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -66,6 +68,34 @@ protected:
|
||||
bool rollbackTransaction() override;
|
||||
};
|
||||
|
||||
class Q_EXPORT_SQLDRIVER_OCI QOCIResult : public QSqlCachedResult
|
||||
{
|
||||
friend class QOCIDriver;
|
||||
friend struct QOCIResultPrivate;
|
||||
friend class QOCICols;
|
||||
public:
|
||||
QOCIResult(const QOCIDriver * db, const QOCIDriverPrivate* p);
|
||||
~QOCIResult();
|
||||
bool prepare(const QString& query);
|
||||
bool exec();
|
||||
QVariant handle() const;
|
||||
|
||||
protected:
|
||||
bool gotoNext(ValueCache &values, int index);
|
||||
bool reset (const QString& query);
|
||||
int size();
|
||||
int numRowsAffected();
|
||||
QSqlRecord record() const;
|
||||
QVariant lastInsertId() const;
|
||||
bool execBatch(bool arrayBind = false);
|
||||
void virtual_hook(int id, void *data);
|
||||
bool isCursor;
|
||||
bool internal_prepare();
|
||||
|
||||
private:
|
||||
QOCIResultPrivate *d;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSQL_OCI_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user