diff options
Diffstat (limited to 'src/sql/drivers/oci/qsql_oci.cpp')
-rw-r--r-- | src/sql/drivers/oci/qsql_oci.cpp | 262 |
1 files changed, 150 insertions, 112 deletions
diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index f0c0b224bd..47d6db7ea4 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtSql module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -155,42 +161,62 @@ QT_BEGIN_INCLUDE_NAMESPACE Q_DECLARE_METATYPE(QOCIRowIdPointer) QT_END_INCLUDE_NAMESPACE +class QOCIDriverPrivate : public QSqlDriverPrivate +{ + Q_DECLARE_PUBLIC(QOCIDriver) + +public: + QOCIDriverPrivate(); + + OCIEnv *env; + OCISvcCtx *svc; + OCIServer *srvhp; + OCISession *authp; + OCIError *err; + bool transaction; + int serverVersion; + int prefetchRows; + int prefetchMem; + QString user; + + void allocErrorHandle(); +}; + class QOCICols; -struct QOCIResultPrivate; +class QOCIResultPrivate; -class Q_EXPORT_SQLDRIVER_OCI QOCIResult : public QSqlCachedResult +class QOCIResult: public QSqlCachedResult { + Q_DECLARE_PRIVATE(QOCIResult) friend class QOCIDriver; - friend struct QOCIResultPrivate; friend class QOCICols; public: - QOCIResult(const QOCIDriver * db, const QOCIDriverPrivate* p); + QOCIResult(const QOCIDriver *db); ~QOCIResult(); - bool prepare(const QString& query); - bool exec(); - QVariant handle() const; + bool prepare(const QString &query) Q_DECL_OVERRIDE; + bool exec() Q_DECL_OVERRIDE; + QVariant handle() const Q_DECL_OVERRIDE; 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); - -private: - QOCIResultPrivate *d; + bool gotoNext(ValueCache &values, int index) Q_DECL_OVERRIDE; + bool reset(const QString &query) Q_DECL_OVERRIDE; + int size() Q_DECL_OVERRIDE; + int numRowsAffected() Q_DECL_OVERRIDE; + QSqlRecord record() const Q_DECL_OVERRIDE; + QVariant lastInsertId() const Q_DECL_OVERRIDE; + bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE; + void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; }; -struct QOCIResultPrivate +class QOCIResultPrivate: public QSqlCachedResultPrivate { - QOCIResultPrivate(QOCIResult *result, const QOCIDriverPrivate *driver); +public: + Q_DECLARE_PUBLIC(QOCIResult) + Q_DECLARE_SQLDRIVER_PRIVATE(QOCIDriver) + QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv); ~QOCIResultPrivate(); QOCICols *cols; - QOCIResult *q; OCIEnv *env; OCIError *err; OCISvcCtx *&svc; @@ -207,9 +233,9 @@ struct QOCIResultPrivate void outValues(QVector<QVariant> &values, IndicatorArray &indicators, QList<QByteArray> &tmpStorage); inline bool isOutValue(int i) const - { return q->bindValueType(i) & QSql::Out; } + { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Out; } inline bool isBinaryValue(int i) const - { return q->bindValueType(i) & QSql::Binary; } + { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Binary; } void setCharset(dvoid* handle, ub4 type) const { @@ -485,25 +511,6 @@ void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &ind } -class QOCIDriverPrivate : public QSqlDriverPrivate -{ -public: - QOCIDriverPrivate(); - - OCIEnv *env; - OCISvcCtx *svc; - OCIServer *srvhp; - OCISession *authp; - OCIError *err; - bool transaction; - int serverVersion; - ub4 prefetchRows; - ub2 prefetchMem; - QString user; - - void allocErrorHandle(); -}; - QOCIDriverPrivate::QOCIDriverPrivate() : QSqlDriverPrivate(), env(0), svc(0), srvhp(0), authp(0), err(0), transaction(false), serverVersion(-1), prefetchRows(-1), prefetchMem(QOCI_PREFETCH_MEM) @@ -1221,7 +1228,7 @@ OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param if (r != 0) qOraWarning("qMakeOraField:", p->err); - type = qDecodeOCIType(colType, p->q->numericalPrecisionPolicy()); + type = qDecodeOCIType(colType, p->q_func()->numericalPrecisionPolicy()); if (type == QVariant::Int) { if (colLength == 22 && colPrecision == 0 && colScale == 0) @@ -1232,16 +1239,16 @@ OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param // bind as double if the precision policy asks for it if (((colType == SQLT_FLT) || (colType == SQLT_NUM)) - && (p->q->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)) { + && (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)) { type = QVariant::Double; } // bind as int32 or int64 if the precision policy asks for it if ((colType == SQLT_NUM) || (colType == SQLT_VNU) || (colType == SQLT_UIN) || (colType == SQLT_INT)) { - if (p->q->numericalPrecisionPolicy() == QSql::LowPrecisionInt64) + if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64) type = QVariant::LongLong; - else if (p->q->numericalPrecisionPolicy() == QSql::LowPrecisionInt32) + else if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32) type = QVariant::Int; } @@ -1336,7 +1343,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err); - d->q->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", + d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind column for batch execute"), QSqlError::StatementError, d->err)); return false; @@ -1530,7 +1537,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err); - d->q->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", + d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind column for batch execute"), QSqlError::StatementError, d->err)); return false; @@ -1545,7 +1552,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err); - d->q->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", + d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind column for batch execute"), QSqlError::StatementError, d->err)); return false; @@ -1560,7 +1567,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) { qOraWarning("QOCIPrivate::execBatch: unable to execute batch statement:", d->err); - d->q->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", + d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to execute batch statement"), QSqlError::StatementError, d->err)); return false; @@ -1635,9 +1642,9 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b } } - d->q->setSelect(false); - d->q->setAt(QSql::BeforeFirstRow); - d->q->setActive(true); + d->q_func()->setSelect(false); + d->q_func()->setAt(QSql::BeforeFirstRow); + d->q_func()->setActive(true); return true; } @@ -1752,12 +1759,12 @@ void QOCICols::getValues(QVector<QVariant> &v, int index) case QVariant::Double: case QVariant::Int: case QVariant::LongLong: - if (d->q->numericalPrecisionPolicy() != QSql::HighPrecision) { - if ((d->q->numericalPrecisionPolicy() == QSql::LowPrecisionDouble) + if (d->q_func()->numericalPrecisionPolicy() != QSql::HighPrecision) { + if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble) && (fld.typ == QVariant::Double)) { v[index + i] = *reinterpret_cast<double *>(fld.data); break; - } else if ((d->q->numericalPrecisionPolicy() == QSql::LowPrecisionInt64) + } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64) && (fld.typ == QVariant::LongLong)) { qint64 qll = 0; int r = OCINumberToInt(d->err, reinterpret_cast<OCINumber *>(fld.data), sizeof(qint64), @@ -1767,7 +1774,7 @@ void QOCICols::getValues(QVector<QVariant> &v, int index) else v[index + i] = QVariant(); break; - } else if ((d->q->numericalPrecisionPolicy() == QSql::LowPrecisionInt32) + } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32) && (fld.typ == QVariant::Int)) { v[index + i] = *reinterpret_cast<int *>(fld.data); break; @@ -1790,10 +1797,17 @@ void QOCICols::getValues(QVector<QVariant> &v, int index) } } -QOCIResultPrivate::QOCIResultPrivate(QOCIResult *result, const QOCIDriverPrivate *driver) - : cols(0), q(result), env(driver->env), err(0), svc(const_cast<OCISvcCtx*&>(driver->svc)), - sql(0), transaction(driver->transaction), serverVersion(driver->serverVersion), - prefetchRows(driver->prefetchRows), prefetchMem(driver->prefetchMem) +QOCIResultPrivate::QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv) + : QSqlCachedResultPrivate(q, drv), + cols(0), + env(drv_d_func()->env), + err(0), + svc(const_cast<OCISvcCtx*&>(drv_d_func()->svc)), + sql(0), + transaction(drv_d_func()->transaction), + serverVersion(drv_d_func()->serverVersion), + prefetchRows(drv_d_func()->prefetchRows), + prefetchMem(drv_d_func()->prefetchMem) { int r = OCIHandleAlloc(env, reinterpret_cast<void **>(&err), @@ -1816,24 +1830,24 @@ QOCIResultPrivate::~QOCIResultPrivate() //////////////////////////////////////////////////////////////////////////// -QOCIResult::QOCIResult(const QOCIDriver * db, const QOCIDriverPrivate* p) - : QSqlCachedResult(db) +QOCIResult::QOCIResult(const QOCIDriver *db) + : QSqlCachedResult(*new QOCIResultPrivate(this, db)) { - d = new QOCIResultPrivate(this, p); } QOCIResult::~QOCIResult() { + Q_D(QOCIResult); if (d->sql) { int r = OCIHandleFree(d->sql, OCI_HTYPE_STMT); if (r != 0) qWarning("~QOCIResult: unable to free statement handle"); } - delete d; } QVariant QOCIResult::handle() const { + Q_D(const QOCIResult); return QVariant::fromValue(d->sql); } @@ -1846,6 +1860,7 @@ bool QOCIResult::reset (const QString& query) bool QOCIResult::gotoNext(QSqlCachedResult::ValueCache &values, int index) { + Q_D(QOCIResult); if (at() == QSql::AfterLastRow) return false; @@ -1905,6 +1920,7 @@ int QOCIResult::size() int QOCIResult::numRowsAffected() { + Q_D(QOCIResult); int rowCount; OCIAttrGet(d->sql, OCI_HTYPE_STMT, @@ -1917,6 +1933,7 @@ int QOCIResult::numRowsAffected() bool QOCIResult::prepare(const QString& query) { + Q_D(QOCIResult); int r = 0; QSqlResult::prepare(query); @@ -1962,6 +1979,7 @@ bool QOCIResult::prepare(const QString& query) bool QOCIResult::exec() { + Q_D(QOCIResult); int r = 0; ub2 stmtType=0; ub4 iters; @@ -2043,6 +2061,7 @@ bool QOCIResult::exec() QSqlRecord QOCIResult::record() const { + Q_D(const QOCIResult); QSqlRecord inf; if (!isActive() || !isSelect() || !d->cols) return inf; @@ -2051,6 +2070,7 @@ QSqlRecord QOCIResult::record() const QVariant QOCIResult::lastInsertId() const { + Q_D(const QOCIResult); if (isActive()) { QOCIRowIdPointer ptr(new QOCIRowId(d->env)); @@ -2064,6 +2084,7 @@ QVariant QOCIResult::lastInsertId() const bool QOCIResult::execBatch(bool arrayBind) { + Q_D(QOCIResult); QOCICols::execBatch(d, boundValues(), arrayBind); resetBindCount(); return lastError().type() == QSqlError::NoError; @@ -2301,8 +2322,7 @@ void QOCIDriver::close() QSqlResult *QOCIDriver::createResult() const { - Q_D(const QOCIDriver); - return new QOCIResult(this, d); + return new QOCIResult(this); } bool QOCIDriver::beginTransaction() @@ -2366,17 +2386,46 @@ bool QOCIDriver::rollbackTransaction() return true; } +enum Expression { + OrExpression, + AndExpression +}; + +static QString make_where_clause(const QString &user, Expression e) +{ + static const char sysUsers[][8] = { + "MDSYS", + "LBACSYS", + "SYS", + "SYSTEM", + "WKSYS", + "CTXSYS", + "WMSYS", + }; + static const char joinC[][4] = { "or" , "and" }; + static Q_CONSTEXPR QLatin1Char bang[] = { QLatin1Char(' '), QLatin1Char('!') }; + + const QLatin1String join(joinC[e], -1); // -1: force strlen call + + QString result; + result.reserve(sizeof sysUsers / sizeof *sysUsers * + // max-sizeof(owner != <sysuser> and ) + (9 + sizeof *sysUsers + 5)); + for (const auto &sysUser : sysUsers) { + const QLatin1String l1(sysUser, -1); // -1: force strlen call + if (l1 != user) + result += QLatin1String("owner ") + bang[e] + QLatin1String("= '") + l1 + QLatin1Char(' ') + join + QLatin1Char(' '); + } + + result.chop(join.size() + 2); // remove final " <join> " + + return result; +} + QStringList QOCIDriver::tables(QSql::TableType type) const { Q_D(const QOCIDriver); QStringList tl; - QStringList sysUsers = QStringList() << QLatin1String("MDSYS") - << QLatin1String("LBACSYS") - << QLatin1String("SYS") - << QLatin1String("SYSTEM") - << QLatin1String("WKSYS") - << QLatin1String("CTXSYS") - << QLatin1String("WMSYS"); QString user = d->user; if ( isIdentifierEscaped(user, QSqlDriver::TableName)) @@ -2384,21 +2433,15 @@ QStringList QOCIDriver::tables(QSql::TableType type) const else user = user.toUpper(); - if(sysUsers.contains(user)) - sysUsers.removeAll(user);; - if (!isOpen()) return tl; QSqlQuery t(createResult()); t.setForwardOnly(true); if (type & QSql::Tables) { - QString query = QLatin1String("select owner, table_name from all_tables where "); - QStringList whereList; - foreach(const QString &sysUserName, sysUsers) - whereList << QLatin1String("owner != '") + sysUserName + QLatin1String("' "); - t.exec(query + whereList.join(QLatin1String(" and "))); - + const QLatin1String tableQuery("select owner, table_name from all_tables where "); + const QString where = make_where_clause(user, AndExpression); + t.exec(tableQuery + where); while (t.next()) { if (t.value(0).toString().toUpper() != user.toUpper()) tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); @@ -2407,8 +2450,8 @@ QStringList QOCIDriver::tables(QSql::TableType type) const } // list all table synonyms as well - query = QLatin1String("select owner, synonym_name from all_synonyms where "); - t.exec(query + whereList.join(QLatin1String(" and "))); + const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where "); + t.exec(synonymQuery + where); while (t.next()) { if (t.value(0).toString() != d->user) tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); @@ -2417,11 +2460,9 @@ QStringList QOCIDriver::tables(QSql::TableType type) const } } if (type & QSql::Views) { - QString query = QLatin1String("select owner, view_name from all_views where "); - QStringList whereList; - foreach(const QString &sysUserName, sysUsers) - whereList << QLatin1String("owner != '") + sysUserName + QLatin1String("' "); - t.exec(query + whereList.join(QLatin1String(" and "))); + const QLatin1String query("select owner, view_name from all_views where "); + const QString where = make_where_clause(user, AndExpression); + t.exec(query + where); while (t.next()) { if (t.value(0).toString().toUpper() != d->user.toUpper()) tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); @@ -2434,12 +2475,9 @@ QStringList QOCIDriver::tables(QSql::TableType type) const while (t.next()) { tl.append(t.value(0).toString()); } - QString query = QLatin1String("select owner, table_name from all_tables where "); - QStringList whereList; - foreach(const QString &sysUserName, sysUsers) - whereList << QLatin1String("owner = '") + sysUserName + QLatin1String("' "); - t.exec(query + whereList.join(QLatin1String(" or "))); - + const QLatin1String tableQuery("select owner, table_name from all_tables where "); + const QString where = make_where_clause(user, OrExpression); + t.exec(tableQuery + where); while (t.next()) { if (t.value(0).toString().toUpper() != user.toUpper()) tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); @@ -2448,8 +2486,8 @@ QStringList QOCIDriver::tables(QSql::TableType type) const } // list all table synonyms as well - query = QLatin1String("select owner, synonym_name from all_synonyms where "); - t.exec(query + whereList.join(QLatin1String(" or "))); + const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where "); + t.exec(synonymQuery + where); while (t.next()) { if (t.value(0).toString() != d->user) tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString()); |