summaryrefslogtreecommitdiffstats
path: root/src/sql/drivers/oci/qsql_oci.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql/drivers/oci/qsql_oci.cpp')
-rw-r--r--src/sql/drivers/oci/qsql_oci.cpp239
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 e11cf75..1bf59bf 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;