diff options
author | Thierry Bastian <thierry.bastian@nokia.com> | 2010-11-16 00:00:11 (GMT) |
---|---|---|
committer | Thierry Bastian <thierry.bastian@nokia.com> | 2010-11-16 00:00:11 (GMT) |
commit | 70e9090b13f828b048caadf305d405bdf9098d70 (patch) | |
tree | ee41264c5c0766786313261049a3fa5c70578906 /src/sql | |
parent | 2e36c20f3039b94b02b49567edf4470fe73cceb8 (diff) | |
parent | b36e357b982ba01cbf905fb1d0340e87030b0a95 (diff) | |
download | Qt-70e9090b13f828b048caadf305d405bdf9098d70.zip Qt-70e9090b13f828b048caadf305d405bdf9098d70.tar.gz Qt-70e9090b13f828b048caadf305d405bdf9098d70.tar.bz2 |
Merge branch 'master-upstream' into master-water
Diffstat (limited to 'src/sql')
-rw-r--r-- | src/sql/drivers/oci/qsql_oci.cpp | 239 |
1 files changed, 172 insertions, 67 deletions
diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index 6870055..a4614bf 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -93,11 +93,13 @@ enum { QOCIEncoding = 2002 }; // AL16UTF16LE enum { QOCIEncoding = 2000 }; // AL16UTF16 #endif +#ifdef OCI_ATTR_CHARSET_FORM // Always set the OCI_ATTR_CHARSET_FORM to SQLCS_NCHAR is safe // because Oracle server will deal with the implicit Conversion // Between CHAR and NCHAR. // see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705 static const ub1 qOraCharsetForm = SQLCS_NCHAR; +#endif #if defined (OCI_UTF16ID) static const ub2 qOraCharset = OCI_UTF16ID; @@ -110,13 +112,23 @@ typedef QVarLengthArray<ub2, 32> SizeArray; static QByteArray qMakeOraDate(const QDateTime& dt); static QDateTime qMakeDate(const char* oraDate); + +static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err); +static QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err); + +static qlonglong qMakeLongLong(const char* ociNumber, OCIError* err); +static qulonglong qMakeULongLong(const char* ociNumber, OCIError* err); + static QString qOraWarn(OCIError *err, int *errorCode = 0); + #ifndef Q_CC_SUN static // for some reason, Sun CC can't use qOraWarning when it's declared static #endif void qOraWarning(const char* msg, OCIError *err); static QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err); + + class QOCIRowId: public QSharedData { public: @@ -164,7 +176,6 @@ struct QOCIResultPrivate int serverVersion; int prefetchRows, prefetchMem; - void setCharset(OCIBind* hbnd); void setStatementAttributes(); int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage); @@ -176,6 +187,41 @@ struct QOCIResultPrivate { return q->bindValueType(i) & QSql::Out; } inline bool isBinaryValue(int i) const { return q->bindValueType(i) & QSql::Binary; } + + void setCharset(dvoid* handle, ub4 type) const + { + int r = 0; + Q_ASSERT(handle); + +#ifdef OCI_ATTR_CHARSET_FORM + r = OCIAttrSet(handle, + type, + // this const cast is safe since OCI doesn't touch + // the charset. + const_cast<void *>(static_cast<const void *>(&qOraCharsetForm)), + 0, + OCI_ATTR_CHARSET_FORM, + //Strange Oracle bug: some Oracle servers crash the server process with non-zero error handle (mostly for 10g). + //So ignore the error message here. + 0); + #ifdef QOCI_DEBUG + if (r != 0) + qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM."); + #endif +#endif + + r = OCIAttrSet(handle, + type, + // this const cast is safe since OCI doesn't touch + // the charset. + const_cast<void *>(static_cast<const void *>(&qOraCharset)), + 0, + OCI_ATTR_CHARSET_ID, + err); + if (r != 0) + qOraWarning("QOCIResultPrivate::setCharsetI Couldn't set OCI_ATTR_CHARSET_ID: ", err); + + } }; void QOCIResultPrivate::setStatementAttributes() @@ -208,36 +254,6 @@ void QOCIResultPrivate::setStatementAttributes() } } -void QOCIResultPrivate::setCharset(OCIBind* hbnd) -{ - int r = 0; - - Q_ASSERT(hbnd); - - r = OCIAttrSet(hbnd, - OCI_HTYPE_BIND, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast<void *>(static_cast<const void *>(&qOraCharsetForm)), - 0, - OCI_ATTR_CHARSET_FORM, - err); - if (r != 0) - qOraWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM: ", err); - - r = OCIAttrSet(hbnd, - OCI_HTYPE_BIND, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast<void *>(static_cast<const void *>(&qOraCharset)), - 0, - OCI_ATTR_CHARSET_ID, - err); - if (r != 0) - qOraWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_ID: ", err); - -} - int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage) { @@ -283,6 +299,28 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in sizeof(uint), SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT); break; + case QVariant::LongLong: + { + QByteArray ba = qMakeOCINumber(val.toLongLong(), err); + r = OCIBindByPos(sql, hbnd, err, + pos + 1, + ba.data(), + ba.size(), + SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + tmpStorage.append(ba); + break; + } + case QVariant::ULongLong: + { + QByteArray ba = qMakeOCINumber(val.toULongLong(), err); + r = OCIBindByPos(sql, hbnd, err, + pos + 1, + ba.data(), + ba.size(), + SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + tmpStorage.append(ba); + break; + } case QVariant::Double: r = OCIBindByPos(sql, hbnd, err, pos + 1, @@ -325,7 +363,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in (s.length() + 1) * sizeof(QChar), SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT); if (r == OCI_SUCCESS) - setCharset(*hbnd); + setCharset(*hbnd, OCI_HTYPE_BIND); break; } } // fall through for OUT values @@ -349,7 +387,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT); } if (r == OCI_SUCCESS) - setCharset(*hbnd); + setCharset(*hbnd, OCI_HTYPE_BIND); tmpStorage.append(ba); break; } // default case @@ -378,7 +416,7 @@ int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &ind } // will assign out value and remove its temp storage. -static void qOraOutValue(QVariant &value, QList<QByteArray> &storage) +static void qOraOutValue(QVariant &value, QList<QByteArray> &storage, OCIError* err) { switch (value.type()) { case QVariant::Time: @@ -390,6 +428,12 @@ static void qOraOutValue(QVariant &value, QList<QByteArray> &storage) case QVariant::DateTime: value = qMakeDate(storage.takeFirst()); break; + case QVariant::LongLong: + value = qMakeLongLong(storage.takeFirst(), err); + break; + case QVariant::ULongLong: + value = qMakeULongLong(storage.takeFirst(), err); + break; case QVariant::String: value = QString( reinterpret_cast<const QChar *>(storage.takeFirst().constData())); @@ -407,7 +451,7 @@ void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &ind if (!isOutValue(i)) continue; - qOraOutValue(values[i], tmpStorage); + qOraOutValue(values[i], tmpStorage, err); QVariant::Type typ = values.at(i).type(); if (indicators[i] == -1) // NULL @@ -667,6 +711,56 @@ QByteArray qMakeOraDate(const QDateTime& dt) return ba; } +/*! + \internal + + Convert qlonglong to the internal Oracle OCINumber format. + */ +QByteArray qMakeOCINumber(const qlonglong& ll, OCIError* err) +{ + QByteArray ba(sizeof(OCINumber), 0); + + OCINumberFromInt(err, + &ll, + sizeof(qlonglong), + OCI_NUMBER_SIGNED, + reinterpret_cast<OCINumber*>(ba.data())); + return ba; +} + +/*! + \internal + + Convert qulonglong to the internal Oracle OCINumber format. + */ +QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err) +{ + QByteArray ba(sizeof(OCINumber), 0); + + OCINumberFromInt(err, + &ull, + sizeof(qlonglong), + OCI_NUMBER_UNSIGNED, + reinterpret_cast<OCINumber*>(ba.data())); + return ba; +} + +qlonglong qMakeLongLong(const char* ociNumber, OCIError* err) +{ + qlonglong qll = 0; + OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qlonglong), + OCI_NUMBER_SIGNED, &qll); + return qll; +} + +qulonglong qMakeULongLong(const char* ociNumber, OCIError* err) +{ + qulonglong qull = 0; + OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qulonglong), + OCI_NUMBER_UNSIGNED, &qull); + return qull; +} + QDateTime qMakeDate(const char* oraDate) { int century = uchar(oraDate[0]); @@ -688,7 +782,6 @@ class QOCICols public: QOCICols(int size, QOCIResultPrivate* dp); ~QOCICols(); - void setCharset(OCIDefine* dfn); int readPiecewise(QVector<QVariant> &values, int index = 0); int readLOBs(QVector<QVariant> &values, int index = 0); int fieldFromDefine(OCIDefine* d); @@ -890,7 +983,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp) &(fieldInf[idx].ind), 0, 0, OCI_DEFAULT); if (r == 0) - setCharset(dfn); + d->setCharset(dfn, OCI_HTYPE_DEFINE); } break; default: @@ -950,35 +1043,6 @@ OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env) return &lob; } -void QOCICols::setCharset(OCIDefine* dfn) -{ - int r = 0; - - Q_ASSERT(dfn); - - r = OCIAttrSet(dfn, - OCI_HTYPE_DEFINE, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast<void *>(static_cast<const void *>(&qOraCharsetForm)), - 0, - OCI_ATTR_CHARSET_FORM, - d->err); - if (r != 0) - qOraWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM: ", d->err); - - r = OCIAttrSet(dfn, - OCI_HTYPE_DEFINE, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast<void *>(static_cast<const void *>(&qOraCharset)), - 0, - OCI_ATTR_CHARSET_ID, - d->err); - if (r != 0) - qOraWarning("QOCICols::setCharset: Couldn't set OCI_ATTR_CHARSET_ID: ", d->err); -} - int QOCICols::readPiecewise(QVector<QVariant> &values, int index) { OCIDefine* dfn; @@ -1281,6 +1345,16 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b col.maxLen = sizeof(uint); break; + case QVariant::LongLong: + col.bindAs = SQLT_VNU; + col.maxLen = sizeof(OCINumber); + break; + + case QVariant::ULongLong: + col.bindAs = SQLT_VNU; + col.maxLen = sizeof(OCINumber); + break; + case QVariant::Double: col.bindAs = SQLT_FLT; col.maxLen = sizeof(double); @@ -1352,6 +1426,22 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b *reinterpret_cast<uint*>(dataPtr) = val.toUInt(); break; + case QVariant::LongLong: + { + columns[i].lengths[row] = columns[i].maxLen; + const QByteArray ba = qMakeOCINumber(val.toLongLong(), d->err); + Q_ASSERT(ba.size() == int(columns[i].maxLen)); + memcpy(dataPtr, ba.constData(), columns[i].maxLen); + break; + } + case QVariant::ULongLong: + { + columns[i].lengths[row] = columns[i].maxLen; + const QByteArray ba = qMakeOCINumber(val.toULongLong(), d->err); + Q_ASSERT(ba.size() == int(columns[i].maxLen)); + memcpy(dataPtr, ba.constData(), columns[i].maxLen); + break; + } case QVariant::Double: columns[i].lengths[row] = columns[i].maxLen; *reinterpret_cast<double*>(dataPtr) = val.toDouble(); @@ -1459,7 +1549,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b QVariant::Type tp = boundValues.at(i).type(); if (tp != QVariant::List) { - qOraOutValue(boundValues[i], tmpStorage); + qOraOutValue(boundValues[i], tmpStorage, d->err); if (*columns[i].indicators == -1) boundValues[i] = QVariant(tp); continue; @@ -1489,6 +1579,21 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b (*list)[r] = *reinterpret_cast<uint*>(data + r * columns[i].maxLen); break; + case SQLT_VNU: + { + switch (boundValues.at(i).type()) { + case QVariant::LongLong: + (*list)[r] = qMakeLongLong(data + r * columns[i].maxLen, d->err); + break; + case QVariant::ULongLong: + (*list)[r] = qMakeULongLong(data + r * columns[i].maxLen, d->err); + break; + default: + break; + } + break; + } + case SQLT_FLT: (*list)[r] = *reinterpret_cast<double*>(data + r * columns[i].maxLen); break; |