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
|
//#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_METATYPE(OCIEnv*)
|
||||||
Q_DECLARE_OPAQUE_POINTER(OCIStmt*);
|
Q_DECLARE_OPAQUE_POINTER(OCIStmt*)
|
||||||
Q_DECLARE_METATYPE(OCIStmt*)
|
Q_DECLARE_METATYPE(OCIStmt*)
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -203,31 +205,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class QOCICols;
|
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
|
class QOCIResultPrivate: public QSqlCachedResultPrivate
|
||||||
{
|
{
|
||||||
@ -435,6 +412,18 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
|
|||||||
const_cast<OCIRowid **>(&rptr->id),
|
const_cast<OCIRowid **>(&rptr->id),
|
||||||
-1,
|
-1,
|
||||||
SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
|
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 {
|
} else {
|
||||||
qCWarning(lcOci, "Unknown bind variable");
|
qCWarning(lcOci, "Unknown bind variable");
|
||||||
r = OCI_ERROR;
|
r = OCI_ERROR;
|
||||||
@ -1831,6 +1820,7 @@ QOCIResultPrivate::~QOCIResultPrivate()
|
|||||||
QOCIResult::QOCIResult(const QOCIDriver *db)
|
QOCIResult::QOCIResult(const QOCIDriver *db)
|
||||||
: QSqlCachedResult(*new QOCIResultPrivate(this, db))
|
: QSqlCachedResult(*new QOCIResultPrivate(this, db))
|
||||||
{
|
{
|
||||||
|
isCursor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QOCIResult::~QOCIResult()
|
QOCIResult::~QOCIResult()
|
||||||
@ -1923,11 +1913,12 @@ int QOCIResult::numRowsAffected()
|
|||||||
return rowCount;
|
return rowCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QOCIResult::prepare(const QString& query)
|
+bool QOCIResult::internal_prepare()
|
||||||
{
|
{
|
||||||
Q_D(QOCIResult);
|
Q_D(QOCIResult);
|
||||||
int r = 0;
|
int r = 0;
|
||||||
QSqlResult::prepare(query);
|
QString noStr;
|
||||||
|
QSqlResult::prepare(noStr);
|
||||||
|
|
||||||
delete d->cols;
|
delete d->cols;
|
||||||
d->cols = nullptr;
|
d->cols = nullptr;
|
||||||
@ -1940,8 +1931,7 @@ bool QOCIResult::prepare(const QString& query)
|
|||||||
else
|
else
|
||||||
qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
|
qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
|
||||||
}
|
}
|
||||||
if (query.isEmpty())
|
|
||||||
return false;
|
|
||||||
r = OCIHandleAlloc(d->env,
|
r = OCIHandleAlloc(d->env,
|
||||||
reinterpret_cast<void **>(&d->sql),
|
reinterpret_cast<void **>(&d->sql),
|
||||||
OCI_HTYPE_STMT,
|
OCI_HTYPE_STMT,
|
||||||
@ -1953,6 +1943,19 @@ bool QOCIResult::prepare(const QString& query)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
d->setStatementAttributes();
|
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 OraText *txt = reinterpret_cast<const OraText *>(query.utf16());
|
||||||
const int len = query.length() * sizeof(QChar);
|
const int len = query.length() * sizeof(QChar);
|
||||||
r = OCIStmtPrepare(d->sql,
|
r = OCIStmtPrepare(d->sql,
|
||||||
@ -2013,23 +2016,25 @@ bool QOCIResult::exec()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute
|
if (!isCursor()) {
|
||||||
r = OCIStmtExecute(d->svc,
|
// execute
|
||||||
d->sql,
|
r = OCIStmtExecute(d->svc,
|
||||||
d->err,
|
d->sql,
|
||||||
iters,
|
d->err,
|
||||||
0,
|
iters,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
mode);
|
0,
|
||||||
if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
|
mode);
|
||||||
qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
|
if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
|
||||||
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
|
qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
|
||||||
"Unable to execute statement"), QSqlError::StatementError, d->err));
|
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
|
||||||
#ifdef QOCI_DEBUG
|
"Unable to execute statement"), QSqlError::StatementError, d->err));
|
||||||
qCDebug(lcOci) << "lastQuery()" << lastQuery();
|
#ifdef QOCI_DEBUG
|
||||||
#endif
|
qCDebug(lcOci) << "lastQuery()" << lastQuery();
|
||||||
return false;
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmtType == OCI_STMT_SELECT) {
|
if (stmtType == OCI_STMT_SELECT) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <QtSql/qsqldriver.h>
|
#include <QtSql/qsqldriver.h>
|
||||||
|
#include <QtSql/private/qsqlcachedresult_p.h>
|
||||||
|
|
||||||
#ifdef QT_PLUGIN
|
#ifdef QT_PLUGIN
|
||||||
#define Q_EXPORT_SQLDRIVER_OCI
|
#define Q_EXPORT_SQLDRIVER_OCI
|
||||||
@ -25,6 +26,7 @@
|
|||||||
|
|
||||||
typedef struct OCIEnv OCIEnv;
|
typedef struct OCIEnv OCIEnv;
|
||||||
typedef struct OCISvcCtx OCISvcCtx;
|
typedef struct OCISvcCtx OCISvcCtx;
|
||||||
|
struct QOCIResultPrivate;
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -66,6 +68,34 @@ protected:
|
|||||||
bool rollbackTransaction() override;
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QSQL_OCI_H
|
#endif // QSQL_OCI_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user