Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsql_oci.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsql_oci_p.h"
5
6#include <qcoreapplication.h>
7#include <qdatetime.h>
8#include <qdebug.h>
9#include <qlist.h>
10#include <qmetatype.h>
11#if QT_CONFIG(regularexpression)
12#include <qregularexpression.h>
13#endif
14#include <qshareddata.h>
15#include <qsqlerror.h>
16#include <qsqlfield.h>
17#include <qsqlindex.h>
18#include <qsqlquery.h>
19#include <QtSql/private/qsqlcachedresult_p.h>
20#include <QtSql/private/qsqldriver_p.h>
21#include <qstringlist.h>
22#if QT_CONFIG(timezone)
23#include <qtimezone.h>
24#endif
25#include <qvariant.h>
26#include <qvarlengtharray.h>
27
28// This is needed for oracle oci when compiling with mingw-w64 headers
29#if defined(__MINGW64_VERSION_MAJOR) && defined(_WIN64)
30#define _int64 __int64
31#endif
32
33#include <oci.h>
34
35#include <stdlib.h>
36
37#define QOCI_DYNAMIC_CHUNK_SIZE 65535
38#define QOCI_PREFETCH_MEM 10240
39
40// setting this define will allow using a query from a different
41// thread than its database connection.
42// warning - this is not fully tested and can lead to race conditions
43#define QOCI_THREADED
44
45//#define QOCI_DEBUG
46
50Q_DECLARE_METATYPE(OCIStmt*)
51
53
54using namespace Qt::StringLiterals;
55
56#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
57enum { QOCIEncoding = 2002 }; // AL16UTF16LE
58#else
59enum { QOCIEncoding = 2000 }; // AL16UTF16
60#endif
61
62#ifdef OCI_ATTR_CHARSET_FORM
63// Always set the OCI_ATTR_CHARSET_FORM to SQLCS_NCHAR is safe
64// because Oracle server will deal with the implicit Conversion
65// Between CHAR and NCHAR.
66// see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705
67static const ub1 qOraCharsetForm = SQLCS_NCHAR;
68#endif
69
70#if defined (OCI_UTF16ID)
71static const ub2 qOraCharset = OCI_UTF16ID;
72#else
73static const ub2 qOraCharset = OCI_UCS2ID;
74#endif
75
78
79static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err);
80static QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err);
81
82static qlonglong qMakeLongLong(const char* ociNumber, OCIError* err);
83static qulonglong qMakeULongLong(const char* ociNumber, OCIError* err);
84
85static QString qOraWarn(OCIError *err, int *errorCode = 0);
86
87#ifndef Q_CC_SUN
88static // for some reason, Sun CC can't use qOraWarning when it's declared static
89#endif
90void qOraWarning(const char* msg, OCIError *err);
91static QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err);
92
93
94
96{
97public:
98 QOCIRowId(OCIEnv *env);
99 ~QOCIRowId();
100
101 OCIRowid *id;
102
103private:
104 QOCIRowId(const QOCIRowId &other): QSharedData(other) { Q_ASSERT(false); }
105};
106
108 : id(0)
109{
110 OCIDescriptorAlloc (env, reinterpret_cast<dvoid **>(&id),
111 OCI_DTYPE_ROWID, 0, 0);
112}
113
115{
116 if (id)
117 OCIDescriptorFree(id, OCI_DTYPE_ROWID);
118}
119
121{
122public:
123 QOCIDateTime(OCIEnv *env, OCIError *err, const QDateTime &dt = QDateTime());
125 OCIDateTime *dateTime;
126 static QDateTime fromOCIDateTime(OCIEnv *env, OCIError *err, OCIDateTime *dt);
127};
128
129QOCIDateTime::QOCIDateTime(OCIEnv *env, OCIError *err, const QDateTime &dt)
131{
132 OCIDescriptorAlloc(env, reinterpret_cast<void**>(&dateTime), OCI_DTYPE_TIMESTAMP_TZ, 0, 0);
133 if (dt.isValid()) {
134 const QDate date = dt.date();
135 const QTime time = dt.time();
136 // Zone in +hh:mm format
137 const QString timeZone = dt.toString("ttt"_L1);
138 const OraText *tz = reinterpret_cast<const OraText *>(timeZone.utf16());
139 OCIDateTimeConstruct(env, err, dateTime, date.year(), date.month(), date.day(), time.hour(),
140 time.minute(), time.second(), time.msec() * 1000000,
141 const_cast<OraText *>(tz), timeZone.length() * sizeof(QChar));
142 }
143}
144
146{
147 if (dateTime != nullptr)
148 OCIDescriptorFree(dateTime, OCI_DTYPE_TIMESTAMP_TZ);
149}
150
151QDateTime QOCIDateTime::fromOCIDateTime(OCIEnv *env, OCIError *err, OCIDateTime *dateTime)
152{
153 sb2 year;
154 ub1 month, day, hour, minute, second;
155 ub4 nsec;
156 sb1 tzHour, tzMinute;
157
158 OCIDateTimeGetDate(env, err, dateTime, &year, &month, &day);
159 OCIDateTimeGetTime(env, err, dateTime, &hour, &minute, &second, &nsec);
160 OCIDateTimeGetTimeZoneOffset(env, err, dateTime, &tzHour, &tzMinute);
161 int secondsOffset = (qAbs(tzHour) * 60 + tzMinute) * 60;
162 if (tzHour < 0)
163 secondsOffset = -secondsOffset;
164 // OCIDateTimeGetTime gives "fractions of second" as nanoseconds
165 return QDateTime(QDate(year, month, day), QTime(hour, minute, second, nsec / 1000000),
166 QTimeZone::fromSecondsAheadOfUtc(secondsOffset));
167}
168
172};
173
178
180{
181 Q_DECLARE_PUBLIC(QOCIDriver)
182
183public:
185
186 OCIEnv *env = nullptr;
187 OCISvcCtx *svc = nullptr;
188 OCIServer *srvhp = nullptr;
189 OCISession *authp = nullptr;
190 OCITrans *trans = nullptr;
191 OCIError *err = nullptr;
192 ub4 authMode = OCI_DEFAULT;
193 bool transaction = false;
195 int prefetchRows = -1;
198
199 void allocErrorHandle();
200};
201
202class QOCICols;
204
206{
207 Q_DECLARE_PRIVATE(QOCIResult)
208 friend class QOCIDriver;
209 friend class QOCICols;
210public:
211 QOCIResult(const QOCIDriver *db);
212 ~QOCIResult();
213 bool prepare(const QString &query) override;
214 bool exec() override;
215 QVariant handle() const override;
216
217protected:
218 bool gotoNext(ValueCache &values, int index) override;
219 bool reset(const QString &query) override;
220 int size() override;
221 int numRowsAffected() override;
222 QSqlRecord record() const override;
223 QVariant lastInsertId() const override;
224 bool execBatch(bool arrayBind = false) override;
225 void virtual_hook(int id, void *data) override;
226 bool fetchNext() override;
227};
228
230{
231public:
232 Q_DECLARE_PUBLIC(QOCIResult)
236
237 QOCICols *cols = nullptr;
239 OCIError *err = nullptr;
241 OCIStmt *sql = nullptr;
244 int prefetchRows, prefetchMem;
245
246 void setStatementAttributes();
247 int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
248 const QVariant &val, dvoid *indPtr, ub2 *tmpSize, TempStorage &tmpStorage);
249 int bindValues(QVariantList &values, IndicatorArray &indicators, SizeArray &tmpSizes,
250 TempStorage &tmpStorage);
251 void outValues(QVariantList &values, IndicatorArray &indicators,
252 TempStorage &tmpStorage);
253 inline bool isOutValue(int i) const
254 { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Out; }
255 inline bool isBinaryValue(int i) const
256 { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Binary; }
257
258 void setCharset(dvoid* handle, ub4 type) const
259 {
260 int r = 0;
262
263#ifdef OCI_ATTR_CHARSET_FORM
264 r = OCIAttrSet(handle,
265 type,
266 // this const cast is safe since OCI doesn't touch
267 // the charset.
268 const_cast<void *>(static_cast<const void *>(&qOraCharsetForm)),
269 0,
270 OCI_ATTR_CHARSET_FORM,
271 //Strange Oracle bug: some Oracle servers crash the server process with non-zero error handle (mostly for 10g).
272 //So ignore the error message here.
273 0);
274 #ifdef QOCI_DEBUG
275 if (r != 0)
276 qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
277 #endif
278#endif
279
280 r = OCIAttrSet(handle,
281 type,
282 // this const cast is safe since OCI doesn't touch
283 // the charset.
284 const_cast<void *>(static_cast<const void *>(&qOraCharset)),
285 0,
286 OCI_ATTR_CHARSET_ID,
287 err);
288 if (r != 0)
289 qOraWarning("QOCIResultPrivate::setCharsetI Couldn't set OCI_ATTR_CHARSET_ID: ", err);
290
291 }
292};
293
295{
296 Q_ASSERT(sql);
297
298 int r = 0;
299
300 if (prefetchRows >= 0) {
301 r = OCIAttrSet(sql,
302 OCI_HTYPE_STMT,
303 &prefetchRows,
304 0,
305 OCI_ATTR_PREFETCH_ROWS,
306 err);
307 if (r != 0)
308 qOraWarning("QOCIResultPrivate::setStatementAttributes:"
309 " Couldn't set OCI_ATTR_PREFETCH_ROWS: ", err);
310 }
311 if (prefetchMem >= 0) {
312 r = OCIAttrSet(sql,
313 OCI_HTYPE_STMT,
314 &prefetchMem,
315 0,
316 OCI_ATTR_PREFETCH_MEMORY,
317 err);
318 if (r != 0)
319 qOraWarning("QOCIResultPrivate::setStatementAttributes:"
320 " Couldn't set OCI_ATTR_PREFETCH_MEMORY: ", err);
321 }
322}
323
324int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
325 const QVariant &val, dvoid *indPtr, ub2 *tmpSize, TempStorage &tmpStorage)
326{
327 int r = OCI_SUCCESS;
328 void *data = const_cast<void *>(val.constData());
329
330 switch (val.typeId()) {
331 case QMetaType::QByteArray:
332 r = OCIBindByPos(sql, hbnd, err,
333 pos + 1,
334 isOutValue(pos)
335 ? const_cast<char *>(reinterpret_cast<QByteArray *>(data)->constData())
336 : reinterpret_cast<QByteArray *>(data)->data(),
337 reinterpret_cast<QByteArray *>(data)->size(),
338 SQLT_BIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
339 break;
340 case QMetaType::QTime:
341 case QMetaType::QDate:
342 case QMetaType::QDateTime: {
343 QOCIDateTime *ptr = new QOCIDateTime(env, err, val.toDateTime());
344 r = OCIBindByPos(sql, hbnd, err,
345 pos + 1,
346 &ptr->dateTime,
347 sizeof(OCIDateTime *),
348 SQLT_TIMESTAMP_TZ, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
349 tmpStorage.dateTimes.append(ptr);
350 break;
351 }
352 case QMetaType::Int:
353 r = OCIBindByPos(sql, hbnd, err,
354 pos + 1,
355 // if it's an out value, the data is already detached
356 // so the const cast is safe.
357 const_cast<void *>(data),
358 sizeof(int),
359 SQLT_INT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
360 break;
361 case QMetaType::UInt:
362 r = OCIBindByPos(sql, hbnd, err,
363 pos + 1,
364 // if it's an out value, the data is already detached
365 // so the const cast is safe.
366 const_cast<void *>(data),
367 sizeof(uint),
368 SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
369 break;
370 case QMetaType::LongLong:
371 {
372 QByteArray ba = qMakeOCINumber(val.toLongLong(), err);
373 r = OCIBindByPos(sql, hbnd, err,
374 pos + 1,
375 ba.data(),
376 ba.size(),
377 SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
378 tmpStorage.rawData.append(ba);
379 break;
380 }
381 case QMetaType::ULongLong:
382 {
383 QByteArray ba = qMakeOCINumber(val.toULongLong(), err);
384 r = OCIBindByPos(sql, hbnd, err,
385 pos + 1,
386 ba.data(),
387 ba.size(),
388 SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
389 tmpStorage.rawData.append(ba);
390 break;
391 }
392 case QMetaType::Double:
393 r = OCIBindByPos(sql, hbnd, err,
394 pos + 1,
395 // if it's an out value, the data is already detached
396 // so the const cast is safe.
397 const_cast<void *>(data),
398 sizeof(double),
399 SQLT_FLT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
400 break;
401 case QMetaType::QString: {
402 const QString s = val.toString();
403 if (isBinaryValue(pos)) {
404 r = OCIBindByPos(sql, hbnd, err,
405 pos + 1,
406 const_cast<ushort *>(s.utf16()),
407 s.length() * sizeof(QChar),
408 SQLT_LNG, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
409 break;
410 } else if (!isOutValue(pos)) {
411 // don't detach the string
412 r = OCIBindByPos(sql, hbnd, err,
413 pos + 1,
414 // safe since oracle doesn't touch OUT values
415 const_cast<ushort *>(s.utf16()),
416 (s.length() + 1) * sizeof(QChar),
417 SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
418 if (r == OCI_SUCCESS)
419 setCharset(*hbnd, OCI_HTYPE_BIND);
420 break;
421 }
422 } // fall through for OUT values
424 default: {
425 if (val.typeId() >= QMetaType::User) {
426 if (val.canConvert<QOCIRowIdPointer>() && !isOutValue(pos)) {
427 // use a const pointer to prevent a detach
428 const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
429 r = OCIBindByPos(sql, hbnd, err,
430 pos + 1,
431 // it's an IN value, so const_cast is ok
432 const_cast<OCIRowid **>(&rptr->id),
433 -1,
434 SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
435 } else {
436 qWarning("Unknown bind variable");
437 r = OCI_ERROR;
438 }
439 } else {
440 const QString s = val.toString();
441 // create a deep-copy
442 QByteArray ba(reinterpret_cast<const char *>(s.utf16()), (s.length() + 1) * sizeof(QChar));
443 if (isOutValue(pos)) {
444 ba.reserve((s.capacity() + 1) * sizeof(QChar));
445 *tmpSize = ba.size();
446 r = OCIBindByPos(sql, hbnd, err,
447 pos + 1,
448 ba.data(),
449 ba.capacity(),
450 SQLT_STR, indPtr, tmpSize, 0, 0, 0, OCI_DEFAULT);
451 } else {
452 r = OCIBindByPos(sql, hbnd, err,
453 pos + 1,
454 ba.data(),
455 ba.size(),
456 SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
457 }
458 if (r == OCI_SUCCESS)
459 setCharset(*hbnd, OCI_HTYPE_BIND);
460 tmpStorage.rawData.append(ba);
461 }
462 break;
463 } // default case
464 } // switch
465 if (r != OCI_SUCCESS)
466 qOraWarning("QOCIResultPrivate::bindValue:", err);
467 return r;
468}
469
471 SizeArray &tmpSizes, TempStorage &tmpStorage)
472{
473 int r = OCI_SUCCESS;
474 for (int i = 0; i < values.count(); ++i) {
475 if (isOutValue(i))
476 values[i].detach();
477 const QVariant &val = values.at(i);
478
479 OCIBind * hbnd = nullptr; // Oracle handles these automatically
480 sb2 *indPtr = &indicators[i];
481 *indPtr = QSqlResultPrivate::isVariantNull(val) ? -1 : 0;
482
483 bindValue(sql, &hbnd, err, i, val, indPtr, &tmpSizes[i], tmpStorage);
484 }
485 return r;
486}
487
488// will assign out value and remove its temp storage.
489static void qOraOutValue(QVariant &value, TempStorage &tmpStorage, OCIEnv *env, OCIError* err)
490{
491 switch (value.typeId()) {
492 case QMetaType::QTime:
494 tmpStorage.dateTimes.takeFirst()->dateTime).time();
495 break;
496 case QMetaType::QDate:
498 tmpStorage.dateTimes.takeFirst()->dateTime).date();
499 break;
500 case QMetaType::QDateTime:
502 tmpStorage.dateTimes.takeFirst()->dateTime);
503 break;
504 case QMetaType::LongLong:
505 value = qMakeLongLong(tmpStorage.rawData.takeFirst(), err);
506 break;
507 case QMetaType::ULongLong:
508 value = qMakeULongLong(tmpStorage.rawData.takeFirst(), err);
509 break;
510 case QMetaType::QString:
511 value = QString(
512 reinterpret_cast<const QChar *>(tmpStorage.rawData.takeFirst().constData()));
513 break;
514 default:
515 break; //nothing
516 }
517}
518
520 TempStorage &tmpStorage)
521{
522 for (int i = 0; i < values.count(); ++i) {
523
524 if (!isOutValue(i))
525 continue;
526
527 qOraOutValue(values[i], tmpStorage, env, err);
528
529 auto typ = values.at(i).metaType();
530 if (indicators[i] == -1) // NULL
531 values[i] = QVariant(typ);
532 else
533 values[i] = QVariant(typ, values.at(i).constData());
534 }
535}
536
537
540{
542}
543
545{
546 Q_ASSERT(!err);
547 int r = OCIHandleAlloc(env,
548 reinterpret_cast<void **>(&err),
549 OCI_HTYPE_ERROR,
550 0, nullptr);
551 if (r != OCI_SUCCESS)
552 qWarning("QOCIDriver: unable to allocate error handle");
553}
554
556{
562 ub4 oraLength; // size in bytes
563 ub4 oraFieldLength; // amount of characters
565};
566
567QString qOraWarn(OCIError *err, int *errorCode)
568{
569 sb4 errcode;
570 text errbuf[1024];
571 errbuf[0] = 0;
572 errbuf[1] = 0;
573
574 OCIErrorGet(err,
575 1,
576 0,
577 &errcode,
578 errbuf,
579 sizeof(errbuf),
580 OCI_HTYPE_ERROR);
581 if (errorCode)
582 *errorCode = errcode;
583 return QString(reinterpret_cast<const QChar *>(errbuf));
584}
585
586void qOraWarning(const char* msg, OCIError *err)
587{
588#ifdef QOCI_DEBUG
589 qWarning("%s %s", msg, qPrintable(qOraWarn(err)));
590#else
591 Q_UNUSED(msg);
592 Q_UNUSED(err);
593#endif
594}
595
596static int qOraErrorNumber(OCIError *err)
597{
598 sb4 errcode;
599 OCIErrorGet(err,
600 1,
601 0,
602 &errcode,
603 0,
604 0,
605 OCI_HTYPE_ERROR);
606 return errcode;
607}
608
609QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err)
610{
611 int errorCode = 0;
612 const QString oraErrorString = qOraWarn(err, &errorCode);
613 return QSqlError(errString, oraErrorString, type,
614 errorCode != -1 ? QString::number(errorCode) : QString());
615}
616
618{
620 if (ocitype == "VARCHAR2"_L1 || ocitype == "VARCHAR"_L1
621 || ocitype.startsWith("INTERVAL"_L1)
622 || ocitype == "CHAR"_L1 || ocitype == "NVARCHAR2"_L1
623 || ocitype == "NCHAR"_L1)
624 type = QMetaType::QString;
625 else if (ocitype == "NUMBER"_L1
626 || ocitype == "FLOAT"_L1
627 || ocitype == "BINARY_FLOAT"_L1
628 || ocitype == "BINARY_DOUBLE"_L1) {
629 switch(precisionPolicy) {
631 type = QMetaType::Int;
632 break;
634 type = QMetaType::LongLong;
635 break;
637 type = QMetaType::Double;
638 break;
640 default:
641 type = QMetaType::QString;
642 break;
643 }
644 }
645 else if (ocitype == "LONG"_L1 || ocitype == "NCLOB"_L1 || ocitype == "CLOB"_L1)
646 type = QMetaType::QByteArray;
647 else if (ocitype == "RAW"_L1 || ocitype == "LONG RAW"_L1
648 || ocitype == "ROWID"_L1 || ocitype == "BLOB"_L1
649 || ocitype == "CFILE"_L1 || ocitype == "BFILE"_L1)
650 type = QMetaType::QByteArray;
651 else if (ocitype == "DATE"_L1 || ocitype.startsWith("TIME"_L1))
652 type = QMetaType::QDateTime;
653 else if (ocitype == "UNDEFINED"_L1)
656 qWarning("qDecodeOCIType: unknown type: %s", ocitype.toLocal8Bit().constData());
657 return QMetaType(type);
658}
659
661{
663 switch (ocitype) {
664 case SQLT_STR:
665 case SQLT_VST:
666 case SQLT_CHR:
667 case SQLT_AFC:
668 case SQLT_VCS:
669 case SQLT_AVC:
670 case SQLT_RDD:
671 case SQLT_LNG:
672#ifdef SQLT_INTERVAL_YM
673 case SQLT_INTERVAL_YM:
674#endif
675#ifdef SQLT_INTERVAL_DS
676 case SQLT_INTERVAL_DS:
677#endif
678 type = QMetaType::QString;
679 break;
680 case SQLT_INT:
681 type = QMetaType::Int;
682 break;
683 case SQLT_FLT:
684 case SQLT_NUM:
685 case SQLT_VNU:
686 case SQLT_UIN:
687 switch(precisionPolicy) {
689 type = QMetaType::Int;
690 break;
692 type = QMetaType::LongLong;
693 break;
695 type = QMetaType::Double;
696 break;
698 default:
699 type = QMetaType::QString;
700 break;
701 }
702 break;
703 case SQLT_VBI:
704 case SQLT_BIN:
705 case SQLT_LBI:
706 case SQLT_LVC:
707 case SQLT_LVB:
708 case SQLT_BLOB:
709 case SQLT_CLOB:
710 case SQLT_FILE:
711 case SQLT_NTY:
712 case SQLT_REF:
713 case SQLT_RID:
714 type = QMetaType::QByteArray;
715 break;
716 case SQLT_DAT:
717 case SQLT_ODT:
718 case SQLT_TIMESTAMP:
719 case SQLT_TIMESTAMP_TZ:
720 case SQLT_TIMESTAMP_LTZ:
721 type = QMetaType::QDateTime;
722 break;
723 default:
724 qWarning("qDecodeOCIType: unknown OCI datatype: %d", ocitype);
725 break;
726 }
727 return QMetaType(type);
728}
729
731{
732 QSqlField f(ofi.name, ofi.type);
733 f.setRequired(ofi.oraIsNull == 0);
734
735 if (ofi.type.id() == QMetaType::QString && ofi.oraType != SQLT_NUM && ofi.oraType != SQLT_VNU)
736 f.setLength(ofi.oraFieldLength);
737 else
738 f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision));
739
740 f.setPrecision(ofi.oraScale);
741 f.setSqlType(int(ofi.oraType));
742 return f;
743}
744
750QByteArray qMakeOCINumber(const qlonglong& ll, OCIError* err)
751{
752 QByteArray ba(sizeof(OCINumber), 0);
753
754 OCINumberFromInt(err,
755 &ll,
756 sizeof(qlonglong),
757 OCI_NUMBER_SIGNED,
758 reinterpret_cast<OCINumber*>(ba.data()));
759 return ba;
760}
761
767QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err)
768{
769 QByteArray ba(sizeof(OCINumber), 0);
770
771 OCINumberFromInt(err,
772 &ull,
773 sizeof(qlonglong),
774 OCI_NUMBER_UNSIGNED,
775 reinterpret_cast<OCINumber*>(ba.data()));
776 return ba;
777}
778
779qlonglong qMakeLongLong(const char* ociNumber, OCIError* err)
780{
781 qlonglong qll = 0;
782 OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qlonglong),
783 OCI_NUMBER_SIGNED, &qll);
784 return qll;
785}
786
787qulonglong qMakeULongLong(const char* ociNumber, OCIError* err)
788{
789 qulonglong qull = 0;
790 OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qulonglong),
791 OCI_NUMBER_UNSIGNED, &qull);
792 return qull;
793}
794
796{
797public:
799 ~QOCICols();
800 int readPiecewise(QVariantList &values, int index = 0);
801 int readLOBs(QVariantList &values, int index = 0);
802 int fieldFromDefine(OCIDefine* d);
803 void getValues(QVariantList &v, int index);
804 inline int size() { return fieldInf.size(); }
805 static bool execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool arrayBind);
806
808
809private:
810 char* create(int position, int size);
811 OCILobLocator ** createLobLocator(int position, OCIEnv* env);
812 OraFieldInfo qMakeOraField(const QOCIResultPrivate* p, OCIParam* param) const;
813
814 class OraFieldInf
815 {
816 public:
817 OraFieldInf() : data(0), len(0), ind(0), oraType(0), def(0), lob(0), dataPtr(nullptr)
818 {}
819 ~OraFieldInf();
820 char *data;
821 int len;
822 sb2 ind;
823 QMetaType typ;
824 ub4 oraType;
825 OCIDefine *def;
826 OCILobLocator *lob;
827 void *dataPtr;
828 };
829
830 QList<OraFieldInf> fieldInf;
831 const QOCIResultPrivate *const d;
832};
833
834QOCICols::OraFieldInf::~OraFieldInf()
835{
836 delete [] data;
837 if (lob) {
838 int r = OCIDescriptorFree(lob, OCI_DTYPE_LOB);
839 if (r != 0)
840 qWarning("QOCICols: Cannot free LOB descriptor");
841 }
842 if (dataPtr) {
843 switch (typ.id()) {
844 case QMetaType::QDate:
845 case QMetaType::QTime:
846 case QMetaType::QDateTime: {
847 int r = OCIDescriptorFree(dataPtr, OCI_DTYPE_TIMESTAMP_TZ);
848 if (r != OCI_SUCCESS)
849 qWarning("QOCICols: Cannot free OCIDateTime descriptor");
850 break;
851 }
852 default:
853 break;
854 }
855 }
856}
857
859 : fieldInf(size), d(dp)
860{
861 ub4 dataSize = 0;
862 OCIDefine *dfn = nullptr;
863 int r;
864
865 OCIParam *param = nullptr;
866 sb4 parmStatus = 0;
867 ub4 count = 1;
868 int idx = 0;
869 parmStatus = OCIParamGet(d->sql,
870 OCI_HTYPE_STMT,
871 d->err,
872 reinterpret_cast<void **>(&param),
873 count);
874
875 while (parmStatus == OCI_SUCCESS) {
876 OraFieldInfo ofi = qMakeOraField(d, param);
877 if (ofi.oraType == SQLT_RDD)
878 dataSize = 50;
879#ifdef SQLT_INTERVAL_YM
880#ifdef SQLT_INTERVAL_DS
881 else if (ofi.oraType == SQLT_INTERVAL_YM || ofi.oraType == SQLT_INTERVAL_DS)
882 // since we are binding interval datatype as string,
883 // we are not interested in the number of bytes but characters.
884 dataSize = 50; // magic number
885#endif //SQLT_INTERVAL_DS
886#endif //SQLT_INTERVAL_YM
887 else if (ofi.oraType == SQLT_NUM || ofi.oraType == SQLT_VNU){
888 if (ofi.oraPrecision > 0)
889 dataSize = (ofi.oraPrecision + 1) * sizeof(utext);
890 else
891 dataSize = (38 + 1) * sizeof(utext);
892 }
893 else
894 dataSize = ofi.oraLength;
895
896 fieldInf[idx].typ = ofi.type;
897 fieldInf[idx].oraType = ofi.oraType;
898 rec.append(qFromOraInf(ofi));
899
900 switch (ofi.type.id()) {
901 case QMetaType::QDateTime:
902 r = OCIDescriptorAlloc(d->env, (void **)&fieldInf[idx].dataPtr, OCI_DTYPE_TIMESTAMP_TZ, 0, 0);
903 if (r != OCI_SUCCESS) {
904 qWarning("QOCICols: Unable to allocate the OCIDateTime descriptor");
905 break;
906 }
907 r = OCIDefineByPos(d->sql,
908 &dfn,
909 d->err,
910 count,
911 &fieldInf[idx].dataPtr,
912 sizeof(OCIDateTime *),
913 SQLT_TIMESTAMP_TZ,
914 &(fieldInf[idx].ind),
915 0, 0, OCI_DEFAULT);
916 break;
917 case QMetaType::Double:
918 r = OCIDefineByPos(d->sql,
919 &dfn,
920 d->err,
921 count,
922 create(idx, sizeof(double) - 1),
923 sizeof(double),
924 SQLT_FLT,
925 &(fieldInf[idx].ind),
926 0, 0, OCI_DEFAULT);
927 break;
928 case QMetaType::Int:
929 r = OCIDefineByPos(d->sql,
930 &dfn,
931 d->err,
932 count,
933 create(idx, sizeof(qint32) - 1),
934 sizeof(qint32),
935 SQLT_INT,
936 &(fieldInf[idx].ind),
937 0, 0, OCI_DEFAULT);
938 break;
939 case QMetaType::LongLong:
940 r = OCIDefineByPos(d->sql,
941 &dfn,
942 d->err,
943 count,
944 create(idx, sizeof(OCINumber)),
945 sizeof(OCINumber),
946 SQLT_VNU,
947 &(fieldInf[idx].ind),
948 0, 0, OCI_DEFAULT);
949 break;
950 case QMetaType::QByteArray:
951 // RAW and LONG RAW fields can't be bound to LOB locators
952 if (ofi.oraType == SQLT_BIN) {
953// qDebug("binding SQLT_BIN");
954 r = OCIDefineByPos(d->sql,
955 &dfn,
956 d->err,
957 count,
958 create(idx, dataSize),
959 dataSize,
960 SQLT_BIN,
961 &(fieldInf[idx].ind),
962 0, 0, OCI_DYNAMIC_FETCH);
963 } else if (ofi.oraType == SQLT_LBI) {
964// qDebug("binding SQLT_LBI");
965 r = OCIDefineByPos(d->sql,
966 &dfn,
967 d->err,
968 count,
969 0,
970 SB4MAXVAL,
971 SQLT_LBI,
972 &(fieldInf[idx].ind),
973 0, 0, OCI_DYNAMIC_FETCH);
974 } else if (ofi.oraType == SQLT_CLOB) {
975 r = OCIDefineByPos(d->sql,
976 &dfn,
977 d->err,
978 count,
979 createLobLocator(idx, d->env),
980 -1,
981 SQLT_CLOB,
982 &(fieldInf[idx].ind),
983 0, 0, OCI_DEFAULT);
984 } else {
985// qDebug("binding SQLT_BLOB");
986 r = OCIDefineByPos(d->sql,
987 &dfn,
988 d->err,
989 count,
990 createLobLocator(idx, d->env),
991 -1,
992 SQLT_BLOB,
993 &(fieldInf[idx].ind),
994 0, 0, OCI_DEFAULT);
995 }
996 break;
997 case QMetaType::QString:
998 if (ofi.oraType == SQLT_LNG) {
999 r = OCIDefineByPos(d->sql,
1000 &dfn,
1001 d->err,
1002 count,
1003 0,
1004 SB4MAXVAL,
1005 SQLT_LNG,
1006 &(fieldInf[idx].ind),
1007 0, 0, OCI_DYNAMIC_FETCH);
1008 } else {
1009 dataSize += dataSize + sizeof(QChar);
1010 //qDebug("OCIDefineByPosStr(%d): %d", count, dataSize);
1011 r = OCIDefineByPos(d->sql,
1012 &dfn,
1013 d->err,
1014 count,
1015 create(idx, dataSize),
1016 dataSize,
1017 SQLT_STR,
1018 &(fieldInf[idx].ind),
1019 0, 0, OCI_DEFAULT);
1020 if (r == 0)
1021 d->setCharset(dfn, OCI_HTYPE_DEFINE);
1022 }
1023 break;
1024 default:
1025 // this should make enough space even with character encoding
1026 dataSize = (dataSize + 1) * sizeof(utext) ;
1027 //qDebug("OCIDefineByPosDef(%d): %d", count, dataSize);
1028 r = OCIDefineByPos(d->sql,
1029 &dfn,
1030 d->err,
1031 count,
1032 create(idx, dataSize),
1033 dataSize+1,
1034 SQLT_STR,
1035 &(fieldInf[idx].ind),
1036 0, 0, OCI_DEFAULT);
1037 break;
1038 }
1039 if (r != 0)
1040 qOraWarning("QOCICols::bind:", d->err);
1041 fieldInf[idx].def = dfn;
1042 ++count;
1043 ++idx;
1044 parmStatus = OCIParamGet(d->sql,
1045 OCI_HTYPE_STMT,
1046 d->err,
1047 reinterpret_cast<void **>(&param),
1048 count);
1049 }
1050}
1051
1053{
1054}
1055
1056char* QOCICols::create(int position, int size)
1057{
1058 char* c = new char[size+1];
1059 // Oracle may not fill fixed width fields
1060 memset(c, 0, size+1);
1061 fieldInf[position].data = c;
1062 fieldInf[position].len = size;
1063 return c;
1064}
1065
1066OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env)
1067{
1068 OCILobLocator *& lob = fieldInf[position].lob;
1069 int r = OCIDescriptorAlloc(env,
1070 reinterpret_cast<void **>(&lob),
1071 OCI_DTYPE_LOB,
1072 0,
1073 0);
1074 if (r != 0) {
1075 qWarning("QOCICols: Cannot create LOB locator");
1076 lob = 0;
1077 }
1078 return &lob;
1079}
1080
1082{
1083 OCIDefine* dfn;
1084 ub4 typep;
1085 ub1 in_outp;
1086 ub4 iterp;
1087 ub4 idxp;
1088 ub1 piecep;
1089 sword status;
1091 int fieldNum = -1;
1092 int r = 0;
1093 bool nullField;
1094
1095 do {
1096 r = OCIStmtGetPieceInfo(d->sql, d->err, reinterpret_cast<void **>(&dfn), &typep,
1097 &in_outp, &iterp, &idxp, &piecep);
1098 if (r != OCI_SUCCESS)
1099 qOraWarning("OCIResultPrivate::readPiecewise: unable to get piece info:", d->err);
1100 fieldNum = fieldFromDefine(dfn);
1101 bool isStringField = fieldInf.at(fieldNum).oraType == SQLT_LNG;
1102 ub4 chunkSize = QOCI_DYNAMIC_CHUNK_SIZE;
1103 nullField = false;
1104 r = OCIStmtSetPieceInfo(dfn, OCI_HTYPE_DEFINE,
1105 d->err, col,
1106 &chunkSize, piecep, NULL, NULL);
1107 if (r != OCI_SUCCESS)
1108 qOraWarning("OCIResultPrivate::readPiecewise: unable to set piece info:", d->err);
1109 status = OCIStmtFetch (d->sql, d->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
1110 if (status == -1) {
1111 sb4 errcode;
1112 OCIErrorGet(d->err, 1, 0, &errcode, 0, 0,OCI_HTYPE_ERROR);
1113 switch (errcode) {
1114 case 1405: /* NULL */
1115 nullField = true;
1116 break;
1117 default:
1118 qOraWarning("OCIResultPrivate::readPiecewise: unable to fetch next:", d->err);
1119 break;
1120 }
1121 }
1122 if (status == OCI_NO_DATA)
1123 break;
1124 if (nullField || !chunkSize) {
1125 fieldInf[fieldNum].ind = -1;
1126 } else {
1127 if (isStringField) {
1128 QString str = values.at(fieldNum + index).toString();
1129 str += QString(reinterpret_cast<const QChar *>(col), chunkSize / 2);
1130 values[fieldNum + index] = str;
1131 fieldInf[fieldNum].ind = 0;
1132 } else {
1133 QByteArray ba = values.at(fieldNum + index).toByteArray();
1134 int sz = ba.size();
1135 ba.resize(sz + chunkSize);
1136 memcpy(ba.data() + sz, reinterpret_cast<char *>(col), chunkSize);
1137 values[fieldNum + index] = ba;
1138 fieldInf[fieldNum].ind = 0;
1139 }
1140 }
1141 } while (status == OCI_SUCCESS_WITH_INFO || status == OCI_NEED_DATA);
1142 return r;
1143}
1144
1145OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param) const
1146{
1147 OraFieldInfo ofi;
1148 ub2 colType(0);
1149 text *colName = nullptr;
1150 ub4 colNameLen(0);
1151 sb1 colScale(0);
1152 ub2 colLength(0);
1153 ub2 colFieldLength(0);
1154 sb2 colPrecision(0);
1155 ub1 colIsNull(0);
1156 int r(0);
1157
1158 r = OCIAttrGet(param,
1159 OCI_DTYPE_PARAM,
1160 &colType,
1161 0,
1162 OCI_ATTR_DATA_TYPE,
1163 p->err);
1164 if (r != 0)
1165 qOraWarning("qMakeOraField:", p->err);
1166
1167 r = OCIAttrGet(param,
1168 OCI_DTYPE_PARAM,
1169 &colName,
1170 &colNameLen,
1171 OCI_ATTR_NAME,
1172 p->err);
1173 if (r != 0)
1174 qOraWarning("qMakeOraField:", p->err);
1175
1176 r = OCIAttrGet(param,
1177 OCI_DTYPE_PARAM,
1178 &colLength,
1179 0,
1180 OCI_ATTR_DATA_SIZE, /* in bytes */
1181 p->err);
1182 if (r != 0)
1183 qOraWarning("qMakeOraField:", p->err);
1184
1185#ifdef OCI_ATTR_CHAR_SIZE
1186 r = OCIAttrGet(param,
1187 OCI_DTYPE_PARAM,
1188 &colFieldLength,
1189 0,
1190 OCI_ATTR_CHAR_SIZE,
1191 p->err);
1192 if (r != 0)
1193 qOraWarning("qMakeOraField:", p->err);
1194#else
1195 // for Oracle8.
1196 colFieldLength = colLength;
1197#endif
1198
1199 r = OCIAttrGet(param,
1200 OCI_DTYPE_PARAM,
1201 &colPrecision,
1202 0,
1203 OCI_ATTR_PRECISION,
1204 p->err);
1205 if (r != 0)
1206 qOraWarning("qMakeOraField:", p->err);
1207
1208 r = OCIAttrGet(param,
1209 OCI_DTYPE_PARAM,
1210 &colScale,
1211 0,
1212 OCI_ATTR_SCALE,
1213 p->err);
1214 if (r != 0)
1215 qOraWarning("qMakeOraField:", p->err);
1216 r = OCIAttrGet(param,
1217 OCI_DTYPE_PARAM,
1218 &colType,
1219 0,
1220 OCI_ATTR_DATA_TYPE,
1221 p->err);
1222 if (r != 0)
1223 qOraWarning("qMakeOraField:", p->err);
1224 r = OCIAttrGet(param,
1225 OCI_DTYPE_PARAM,
1226 &colIsNull,
1227 0,
1228 OCI_ATTR_IS_NULL,
1229 p->err);
1230 if (r != 0)
1231 qOraWarning("qMakeOraField:", p->err);
1232
1233 QMetaType type = qDecodeOCIType(colType, p->q_func()->numericalPrecisionPolicy());
1234
1235 if (type.id() == QMetaType::Int) {
1236 if ((colLength == 22 && colPrecision == 0 && colScale == 0) || colScale > 0)
1237 type = QMetaType(QMetaType::QString);
1238 }
1239
1240 // bind as double if the precision policy asks for it
1241 if (((colType == SQLT_FLT) || (colType == SQLT_NUM))
1242 && (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)) {
1243 type = QMetaType(QMetaType::Double);
1244 }
1245
1246 // bind as int32 or int64 if the precision policy asks for it
1247 if ((colType == SQLT_NUM) || (colType == SQLT_VNU) || (colType == SQLT_UIN)
1248 || (colType == SQLT_INT)) {
1249 if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
1250 type = QMetaType(QMetaType::LongLong);
1251 else if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
1252 type = QMetaType(QMetaType::Int);
1253 }
1254
1255 if (colType == SQLT_BLOB)
1256 colLength = 0;
1257
1258 // colNameLen is length in bytes
1259 ofi.name = QString(reinterpret_cast<const QChar*>(colName), colNameLen / 2);
1260 ofi.type = type;
1261 ofi.oraType = colType;
1262 ofi.oraFieldLength = colFieldLength;
1263 ofi.oraLength = colLength;
1264 ofi.oraScale = colScale;
1265 ofi.oraPrecision = colPrecision;
1266 ofi.oraIsNull = colIsNull;
1267
1268 return ofi;
1269}
1270
1272{
1274 : bindh(0), bindAs(0), maxLen(0), recordCount(0),
1275 data(0), lengths(0), indicators(0), maxarr_len(0), curelep(0) {}
1276
1277 OCIBind* bindh;
1281 char* data;
1286};
1287
1289{
1291 : col(columns) {}
1292
1294 {
1295 // deleting storage, length and indicator arrays
1296 for ( int j = 0; j < col.count(); ++j){
1297 delete[] col[j].lengths;
1298 delete[] col[j].indicators;
1299 delete[] col[j].data;
1300 }
1301 }
1302
1304};
1305
1306bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool arrayBind)
1307{
1308 int columnCount = boundValues.count();
1309 if (boundValues.isEmpty() || columnCount == 0)
1310 return false;
1311
1312#ifdef QOCI_DEBUG
1313 qDebug() << "columnCount:" << columnCount << boundValues;
1314#endif
1315
1316 int i;
1317 sword r;
1318
1319 QVarLengthArray<QMetaType> fieldTypes;
1320 for (i = 0; i < columnCount; ++i) {
1321 QMetaType tp = boundValues.at(i).metaType();
1322 fieldTypes.append(tp.id() == QMetaType::QVariantList ? boundValues.at(i).toList().value(0).metaType() : tp);
1323 }
1324 SizeArray tmpSizes(columnCount);
1325 QList<QOCIBatchColumn> columns(columnCount);
1326 QOCIBatchCleanupHandler cleaner(columns);
1327 TempStorage tmpStorage;
1328
1329 // figuring out buffer sizes
1330 for (i = 0; i < columnCount; ++i) {
1331
1332 if (boundValues.at(i).typeId() != QMetaType::QVariantList) {
1333
1334 // not a list - create a deep-copy of the single value
1335 QOCIBatchColumn &singleCol = columns[i];
1336 singleCol.indicators = new sb2[1];
1337 *singleCol.indicators = QSqlResultPrivate::isVariantNull(boundValues.at(i)) ? -1 : 0;
1338
1339 r = d->bindValue(d->sql, &singleCol.bindh, d->err, i,
1340 boundValues.at(i), singleCol.indicators, &tmpSizes[i], tmpStorage);
1341
1342 if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
1343 qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
1344 d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
1345 "Unable to bind column for batch execute"),
1347 return false;
1348 }
1349 continue;
1350 }
1351
1352 QOCIBatchColumn &col = columns[i];
1353 col.recordCount = boundValues.at(i).toList().count();
1354
1355 col.lengths = new ub4[col.recordCount];
1356 col.indicators = new sb2[col.recordCount];
1357 col.maxarr_len = col.recordCount;
1358 col.curelep = col.recordCount;
1359
1360 switch (fieldTypes[i].id()) {
1361 case QMetaType::QTime:
1362 case QMetaType::QDate:
1363 case QMetaType::QDateTime:
1364 col.bindAs = SQLT_TIMESTAMP_TZ;
1365 col.maxLen = sizeof(OCIDateTime *);
1366 break;
1367
1368 case QMetaType::Int:
1369 col.bindAs = SQLT_INT;
1370 col.maxLen = sizeof(int);
1371 break;
1372
1373 case QMetaType::UInt:
1374 col.bindAs = SQLT_UIN;
1375 col.maxLen = sizeof(uint);
1376 break;
1377
1378 case QMetaType::LongLong:
1379 col.bindAs = SQLT_VNU;
1380 col.maxLen = sizeof(OCINumber);
1381 break;
1382
1383 case QMetaType::ULongLong:
1384 col.bindAs = SQLT_VNU;
1385 col.maxLen = sizeof(OCINumber);
1386 break;
1387
1388 case QMetaType::Double:
1389 col.bindAs = SQLT_FLT;
1390 col.maxLen = sizeof(double);
1391 break;
1392
1393 case QMetaType::QString: {
1394 col.bindAs = SQLT_STR;
1395 for (uint j = 0; j < col.recordCount; ++j) {
1396 uint len;
1397 if (d->isOutValue(i))
1398 len = boundValues.at(i).toList().at(j).toString().capacity() + 1;
1399 else
1400 len = boundValues.at(i).toList().at(j).toString().length() + 1;
1401 if (len > col.maxLen)
1402 col.maxLen = len;
1403 }
1404 col.maxLen *= sizeof(QChar);
1405 break; }
1406
1407 case QMetaType::QByteArray:
1408 default: {
1409 if (fieldTypes[i].id() >= QMetaType::User) {
1410 col.bindAs = SQLT_RDD;
1411 col.maxLen = sizeof(OCIRowid*);
1412 } else {
1413 col.bindAs = SQLT_LBI;
1414 for (uint j = 0; j < col.recordCount; ++j) {
1415 if (d->isOutValue(i))
1416 col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().capacity();
1417 else
1418 col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().size();
1419 if (col.lengths[j] > col.maxLen)
1420 col.maxLen = col.lengths[j];
1421 }
1422 }
1423 break;
1424 }
1425 }
1426
1427 col.data = new char[col.maxLen * col.recordCount];
1428 memset(col.data, 0, col.maxLen * col.recordCount);
1429
1430 // we may now populate column with data
1431 for (uint row = 0; row < col.recordCount; ++row) {
1432 const QVariant &val = boundValues.at(i).toList().at(row);
1433
1434 if (QSqlResultPrivate::isVariantNull(val) && !d->isOutValue(i)) {
1435 columns[i].indicators[row] = -1;
1436 columns[i].lengths[row] = 0;
1437 } else {
1438 columns[i].indicators[row] = 0;
1439 char *dataPtr = columns[i].data + (columns[i].maxLen * row);
1440 switch (fieldTypes[i].id()) {
1441 case QMetaType::QTime:
1442 case QMetaType::QDate:
1443 case QMetaType::QDateTime:{
1444 columns[i].lengths[row] = columns[i].maxLen;
1445 QOCIDateTime *date = new QOCIDateTime(d->env, d->err, val.toDateTime());
1446 *reinterpret_cast<OCIDateTime**>(dataPtr) = date->dateTime;
1447 tmpStorage.dateTimes.append(date);
1448 break;
1449 }
1450 case QMetaType::Int:
1451 columns[i].lengths[row] = columns[i].maxLen;
1452 *reinterpret_cast<int*>(dataPtr) = val.toInt();
1453 break;
1454
1455 case QMetaType::UInt:
1456 columns[i].lengths[row] = columns[i].maxLen;
1457 *reinterpret_cast<uint*>(dataPtr) = val.toUInt();
1458 break;
1459
1460 case QMetaType::LongLong:
1461 {
1462 columns[i].lengths[row] = columns[i].maxLen;
1463 const QByteArray ba = qMakeOCINumber(val.toLongLong(), d->err);
1464 Q_ASSERT(ba.size() == int(columns[i].maxLen));
1465 memcpy(dataPtr, ba.constData(), columns[i].maxLen);
1466 break;
1467 }
1468 case QMetaType::ULongLong:
1469 {
1470 columns[i].lengths[row] = columns[i].maxLen;
1471 const QByteArray ba = qMakeOCINumber(val.toULongLong(), d->err);
1472 Q_ASSERT(ba.size() == int(columns[i].maxLen));
1473 memcpy(dataPtr, ba.constData(), columns[i].maxLen);
1474 break;
1475 }
1476 case QMetaType::Double:
1477 columns[i].lengths[row] = columns[i].maxLen;
1478 *reinterpret_cast<double*>(dataPtr) = val.toDouble();
1479 break;
1480
1481 case QMetaType::QString: {
1482 const QString s = val.toString();
1483 columns[i].lengths[row] = (s.length() + 1) * sizeof(QChar);
1484 memcpy(dataPtr, s.utf16(), columns[i].lengths[row]);
1485 break;
1486 }
1487 case QMetaType::QByteArray:
1488 default: {
1489 if (fieldTypes[i].id() >= QMetaType::User) {
1490 if (val.canConvert<QOCIRowIdPointer>()) {
1491 const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
1492 *reinterpret_cast<OCIRowid**>(dataPtr) = rptr->id;
1493 columns[i].lengths[row] = 0;
1494 break;
1495 }
1496 } else {
1497 const QByteArray ba = val.toByteArray();
1498 columns[i].lengths[row] = ba.size();
1499 memcpy(dataPtr, ba.constData(), ba.size());
1500 }
1501 break;
1502 }
1503 }
1504 }
1505 }
1506
1507 QOCIBatchColumn &bindColumn = columns[i];
1508
1509#ifdef QOCI_DEBUG
1510 qDebug("OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
1511 d->sql, &bindColumn.bindh, d->err, i + 1, bindColumn.data,
1512 bindColumn.maxLen, bindColumn.bindAs, bindColumn.indicators, bindColumn.lengths,
1513 arrayBind ? bindColumn.maxarr_len : 0, arrayBind ? &bindColumn.curelep : 0);
1514
1515 for (int ii = 0; ii < (int)bindColumn.recordCount; ++ii) {
1516 qDebug(" record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
1517 bindColumn.lengths[ii]);
1518 }
1519#endif
1520
1521
1522 // binding the column
1523 r = OCIBindByPos2(
1524 d->sql, &bindColumn.bindh, d->err, i + 1,
1525 bindColumn.data,
1526 bindColumn.maxLen,
1527 bindColumn.bindAs,
1528 bindColumn.indicators,
1529 bindColumn.lengths,
1530 0,
1531 arrayBind ? bindColumn.maxarr_len : 0,
1532 arrayBind ? &bindColumn.curelep : 0,
1533 OCI_DEFAULT);
1534
1535#ifdef QOCI_DEBUG
1536 qDebug("After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
1537#endif
1538
1539 if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
1540 qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
1541 d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
1542 "Unable to bind column for batch execute"),
1544 return false;
1545 }
1546
1547 r = OCIBindArrayOfStruct (
1548 columns[i].bindh, d->err,
1549 columns[i].maxLen,
1550 sizeof(columns[i].indicators[0]),
1551 sizeof(columns[i].lengths[0]),
1552 0);
1553
1554 if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
1555 qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
1556 d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
1557 "Unable to bind column for batch execute"),
1559 return false;
1560 }
1561 }
1562
1563 //finally we can execute
1564 r = OCIStmtExecute(d->svc, d->sql, d->err,
1565 arrayBind ? 1 : columns[0].recordCount,
1566 0, NULL, NULL,
1567 d->transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS);
1568
1569 if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
1570 qOraWarning("QOCIPrivate::execBatch: unable to execute batch statement:", d->err);
1571 d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
1572 "Unable to execute batch statement"),
1574 return false;
1575 }
1576
1577 // for out parameters we copy data back to value list
1578 for (i = 0; i < columnCount; ++i) {
1579
1580 if (!d->isOutValue(i))
1581 continue;
1582
1583 if (auto tp = boundValues.at(i).metaType(); tp.id() != QMetaType::QVariantList) {
1584 qOraOutValue(boundValues[i], tmpStorage, d->env, d->err);
1585 if (*columns[i].indicators == -1)
1586 boundValues[i] = QVariant(tp);
1587 continue;
1588 }
1589
1590 QVariantList *list = static_cast<QVariantList *>(const_cast<void*>(boundValues.at(i).data()));
1591
1592 char* data = columns[i].data;
1593 for (uint r = 0; r < columns[i].recordCount; ++r){
1594
1595 if (columns[i].indicators[r] == -1) {
1596 (*list)[r] = QVariant(fieldTypes[i]);
1597 continue;
1598 }
1599
1600 switch(columns[i].bindAs) {
1601
1602 case SQLT_TIMESTAMP_TZ:
1603 (*list)[r] = QOCIDateTime::fromOCIDateTime(d->env, d->err,
1604 *reinterpret_cast<OCIDateTime **>(data + r * columns[i].maxLen));
1605 break;
1606 case SQLT_INT:
1607 (*list)[r] = *reinterpret_cast<int*>(data + r * columns[i].maxLen);
1608 break;
1609
1610 case SQLT_UIN:
1611 (*list)[r] = *reinterpret_cast<uint*>(data + r * columns[i].maxLen);
1612 break;
1613
1614 case SQLT_VNU:
1615 {
1616 switch (boundValues.at(i).typeId()) {
1617 case QMetaType::LongLong:
1618 (*list)[r] = qMakeLongLong(data + r * columns[i].maxLen, d->err);
1619 break;
1620 case QMetaType::ULongLong:
1621 (*list)[r] = qMakeULongLong(data + r * columns[i].maxLen, d->err);
1622 break;
1623 default:
1624 break;
1625 }
1626 break;
1627 }
1628
1629 case SQLT_FLT:
1630 (*list)[r] = *reinterpret_cast<double*>(data + r * columns[i].maxLen);
1631 break;
1632
1633 case SQLT_STR:
1634 (*list)[r] = QString(reinterpret_cast<const QChar *>(data
1635 + r * columns[i].maxLen));
1636 break;
1637
1638 default:
1639 (*list)[r] = QByteArray(data + r * columns[i].maxLen, columns[i].maxLen);
1640 break;
1641 }
1642 }
1643 }
1644
1645 d->q_func()->setSelect(false);
1646 d->q_func()->setAt(QSql::BeforeFirstRow);
1647 d->q_func()->setActive(true);
1648
1649 qDeleteAll(tmpStorage.dateTimes);
1650 return true;
1651}
1652
1653template<class T, int sz>
1654int qReadLob(T &buf, const QOCIResultPrivate *d, OCILobLocator *lob)
1655{
1656 ub1 csfrm;
1657 ub4 amount;
1658 int r;
1659
1660 // Read this from the database, don't assume we know what it is set to
1661 r = OCILobCharSetForm(d->env, d->err, lob, &csfrm);
1662 if (r != OCI_SUCCESS) {
1663 qOraWarning("OCIResultPrivate::readLobs: Couldn't get LOB char set form: ", d->err);
1664 csfrm = 0;
1665 }
1666
1667 // Get the length of the LOB (this is in characters)
1668 r = OCILobGetLength(d->svc, d->err, lob, &amount);
1669 if (r == OCI_SUCCESS) {
1670 if (amount == 0) {
1671 // Short cut for null LOBs
1672 buf.resize(0);
1673 return OCI_SUCCESS;
1674 }
1675 } else {
1676 qOraWarning("OCIResultPrivate::readLobs: Couldn't get LOB length: ", d->err);
1677 return r;
1678 }
1679
1680 // Resize the buffer to hold the LOB contents
1681 buf.resize(amount);
1682
1683 // Read the LOB into the buffer
1684 r = OCILobRead(d->svc,
1685 d->err,
1686 lob,
1687 &amount,
1688 1,
1689 buf.data(),
1690 buf.size() * sz, // this argument is in bytes, not characters
1691 0,
1692 0,
1693 // Extract the data from a CLOB in UTF-16 (ie. what QString uses internally)
1694 sz == 1 ? ub2(0) : ub2(QOCIEncoding),
1695 csfrm);
1696
1697 if (r != OCI_SUCCESS)
1698 qOraWarning("OCIResultPrivate::readLOBs: Cannot read LOB: ", d->err);
1699
1700 return r;
1701}
1702
1704{
1705 OCILobLocator *lob;
1706 int r = OCI_SUCCESS;
1707
1708 for (int i = 0; i < size(); ++i) {
1709 const OraFieldInf &fi = fieldInf.at(i);
1710 if (fi.ind == -1 || !(lob = fi.lob))
1711 continue;
1712
1713 bool isClob = fi.oraType == SQLT_CLOB;
1714 QVariant var;
1715
1716 if (isClob) {
1717 QString str;
1718 r = qReadLob<QString, sizeof(QChar)>(str, d, lob);
1719 var = str;
1720 } else {
1722 r = qReadLob<QByteArray, sizeof(char)>(buf, d, lob);
1723 var = buf;
1724 }
1725 if (r == OCI_SUCCESS)
1726 values[index + i] = var;
1727 else
1728 break;
1729 }
1730 return r;
1731}
1732
1734{
1735 for (int i = 0; i < fieldInf.count(); ++i) {
1736 if (fieldInf.at(i).def == d)
1737 return i;
1738 }
1739 return -1;
1740}
1741
1743{
1744 for (int i = 0; i < fieldInf.size(); ++i) {
1745 const OraFieldInf &fld = fieldInf.at(i);
1746
1747 if (fld.ind == -1) {
1748 // got a NULL value
1749 v[index + i] = QVariant(fld.typ);
1750 continue;
1751 }
1752
1753 if (fld.oraType == SQLT_BIN || fld.oraType == SQLT_LBI || fld.oraType == SQLT_LNG)
1754 continue; // already fetched piecewise
1755
1756 switch (fld.typ.id()) {
1757 case QMetaType::QDateTime:
1759 reinterpret_cast<OCIDateTime *>(fld.dataPtr)));
1760 break;
1761 case QMetaType::Double:
1762 case QMetaType::Int:
1763 case QMetaType::LongLong:
1764 if (d->q_func()->numericalPrecisionPolicy() != QSql::HighPrecision) {
1765 if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)
1766 && (fld.typ.id() == QMetaType::Double)) {
1767 v[index + i] = *reinterpret_cast<double *>(fld.data);
1768 break;
1769 } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
1770 && (fld.typ.id() == QMetaType::LongLong)) {
1771 qint64 qll = 0;
1772 int r = OCINumberToInt(d->err, reinterpret_cast<OCINumber *>(fld.data), sizeof(qint64),
1773 OCI_NUMBER_SIGNED, &qll);
1774 if (r == OCI_SUCCESS)
1775 v[index + i] = qll;
1776 else
1777 v[index + i] = QVariant();
1778 break;
1779 } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
1780 && (fld.typ.id() == QMetaType::Int)) {
1781 v[index + i] = *reinterpret_cast<int *>(fld.data);
1782 break;
1783 }
1784 }
1785 // else fall through
1786 case QMetaType::QString:
1787 v[index + i] = QString(reinterpret_cast<const QChar *>(fld.data));
1788 break;
1789 case QMetaType::QByteArray:
1790 if (fld.len > 0)
1791 v[index + i] = QByteArray(fld.data, fld.len);
1792 else
1793 v[index + i] = QVariant(QMetaType(QMetaType::QByteArray));
1794 break;
1795 default:
1796 qWarning("QOCICols::value: unknown data type");
1797 break;
1798 }
1799 }
1800}
1801
1804 env(drv_d_func()->env),
1805 svc(const_cast<OCISvcCtx*&>(drv_d_func()->svc)),
1806 transaction(drv_d_func()->transaction),
1807 serverVersion(drv_d_func()->serverVersion),
1808 prefetchRows(drv_d_func()->prefetchRows),
1809 prefetchMem(drv_d_func()->prefetchMem)
1810{
1811 Q_ASSERT(!err);
1812 int r = OCIHandleAlloc(env,
1813 reinterpret_cast<void **>(&err),
1814 OCI_HTYPE_ERROR,
1815 0, nullptr);
1816 if (r != OCI_SUCCESS)
1817 qWarning("QOCIResult: unable to alloc error handle");
1818}
1819
1821{
1822 delete cols;
1823
1824 if (sql && OCIHandleFree(sql, OCI_HTYPE_STMT) != OCI_SUCCESS)
1825 qWarning("~QOCIResult: unable to free statement handle");
1826
1827 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS)
1828 qWarning("~QOCIResult: unable to free error report handle");
1829}
1830
1831
1833
1836{
1837}
1838
1840{
1841}
1842
1844{
1845 Q_D(const QOCIResult);
1846 return QVariant::fromValue(d->sql);
1847}
1848
1850{
1851 if (!prepare(query))
1852 return false;
1853 return exec();
1854}
1855
1857{
1858 Q_D(QOCIResult);
1859 if (at() == QSql::AfterLastRow)
1860 return false;
1861
1862 bool piecewise = false;
1863 int r = OCI_SUCCESS;
1864 r = OCIStmtFetch(d->sql, d->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
1865
1866 if (index < 0) //not interested in values
1867 return r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO;
1868
1869 switch (r) {
1870 case OCI_SUCCESS:
1871 break;
1872 case OCI_SUCCESS_WITH_INFO:
1873 qOraWarning("QOCIResult::gotoNext: SuccessWithInfo: ", d->err);
1874 r = OCI_SUCCESS; //ignore it
1875 break;
1876 case OCI_NO_DATA:
1877 // end of rowset
1878 return false;
1879 case OCI_NEED_DATA:
1880 piecewise = true;
1881 r = OCI_SUCCESS;
1882 break;
1883 case OCI_ERROR:
1884 if (qOraErrorNumber(d->err) == 1406) {
1885 qWarning("QOCI Warning: data truncated for %s", lastQuery().toLocal8Bit().constData());
1886 r = OCI_SUCCESS; /* ignore it */
1887 break;
1888 }
1889 // fall through
1890 default:
1891 qOraWarning("QOCIResult::gotoNext: ", d->err);
1893 "Unable to goto next"),
1895 break;
1896 }
1897
1898 // need to read piecewise before assigning values
1899 if (r == OCI_SUCCESS && piecewise)
1900 r = d->cols->readPiecewise(values, index);
1901
1902 if (r == OCI_SUCCESS)
1903 d->cols->getValues(values, index);
1904 if (r == OCI_SUCCESS)
1905 r = d->cols->readLOBs(values, index);
1906 if (r != OCI_SUCCESS)
1908 return r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO;
1909}
1910
1912{
1913 return -1;
1914}
1915
1917{
1918 Q_D(QOCIResult);
1919 int rowCount;
1920 OCIAttrGet(d->sql,
1921 OCI_HTYPE_STMT,
1922 &rowCount,
1923 NULL,
1924 OCI_ATTR_ROW_COUNT,
1925 d->err);
1926 return rowCount;
1927}
1928
1930{
1931 Q_D(QOCIResult);
1932 int r = 0;
1934
1935 delete d->cols;
1936 d->cols = nullptr;
1938
1939 if (d->sql) {
1940 r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
1941 if (r == OCI_SUCCESS)
1942 d->sql = nullptr;
1943 else
1944 qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
1945 }
1946 if (query.isEmpty())
1947 return false;
1948 r = OCIHandleAlloc(d->env,
1949 reinterpret_cast<void **>(&d->sql),
1950 OCI_HTYPE_STMT,
1951 0, nullptr);
1952 if (r != OCI_SUCCESS) {
1953 qOraWarning("QOCIResult::prepare: unable to alloc statement:", d->err);
1955 "Unable to alloc statement"), QSqlError::StatementError, d->err));
1956 return false;
1957 }
1958 d->setStatementAttributes();
1959 const OraText *txt = reinterpret_cast<const OraText *>(query.utf16());
1960 const int len = query.length() * sizeof(QChar);
1961 r = OCIStmtPrepare(d->sql,
1962 d->err,
1963 txt,
1964 len,
1965 OCI_NTV_SYNTAX,
1966 OCI_DEFAULT);
1967 if (r != OCI_SUCCESS) {
1968 qOraWarning("QOCIResult::prepare: unable to prepare statement:", d->err);
1970 "Unable to prepare statement"), QSqlError::StatementError, d->err));
1971 return false;
1972 }
1973 return true;
1974}
1975
1977{
1978 Q_D(QOCIResult);
1979 int r = 0;
1980 ub2 stmtType=0;
1981 ub4 iters;
1982 ub4 mode;
1983 TempStorage tmpStorage;
1984 IndicatorArray indicators(boundValueCount());
1985 SizeArray tmpSizes(boundValueCount());
1986
1987 r = OCIAttrGet(d->sql,
1988 OCI_HTYPE_STMT,
1989 &stmtType,
1990 NULL,
1991 OCI_ATTR_STMT_TYPE,
1992 d->err);
1993
1994 if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
1995 qOraWarning("QOCIResult::exec: Unable to get statement type:", d->err);
1997 "Unable to get statement type"), QSqlError::StatementError, d->err));
1998#ifdef QOCI_DEBUG
1999 qDebug() << "lastQuery()" << lastQuery();
2000#endif
2001 return false;
2002 }
2003
2004 iters = stmtType == OCI_STMT_SELECT ? 0 : 1;
2005 mode = d->transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
2006
2007 // bind placeholders
2008 if (boundValueCount() > 0
2009 && d->bindValues(boundValues(), indicators, tmpSizes, tmpStorage) != OCI_SUCCESS) {
2010 qOraWarning("QOCIResult::exec: unable to bind value: ", d->err);
2011 setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind value"),
2013#ifdef QOCI_DEBUG
2014 qDebug() << "lastQuery()" << lastQuery();
2015#endif
2016 return false;
2017 }
2018
2019 // execute
2020 r = OCIStmtExecute(d->svc,
2021 d->sql,
2022 d->err,
2023 iters,
2024 0,
2025 0,
2026 0,
2027 mode);
2028 if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
2029 qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
2031 "Unable to execute statement"), QSqlError::StatementError, d->err));
2032#ifdef QOCI_DEBUG
2033 qDebug() << "lastQuery()" << lastQuery();
2034#endif
2035 return false;
2036 }
2037
2038 if (stmtType == OCI_STMT_SELECT) {
2039 ub4 parmCount = 0;
2040 int r = OCIAttrGet(d->sql, OCI_HTYPE_STMT, reinterpret_cast<void **>(&parmCount),
2041 0, OCI_ATTR_PARAM_COUNT, d->err);
2042 if (r == 0 && !d->cols)
2043 d->cols = new QOCICols(parmCount, d);
2044 setSelect(true);
2045 QSqlCachedResult::init(parmCount);
2046 } else { /* non-SELECT */
2047 setSelect(false);
2048 }
2050 setActive(true);
2051
2052 if (hasOutValues())
2053 d->outValues(boundValues(), indicators, tmpStorage);
2054 qDeleteAll(tmpStorage.dateTimes);
2055 return true;
2056}
2057
2059{
2060 Q_D(const QOCIResult);
2061 QSqlRecord inf;
2062 if (!isActive() || !isSelect() || !d->cols)
2063 return inf;
2064 return d->cols->rec;
2065}
2066
2068{
2069 Q_D(const QOCIResult);
2070 if (isActive()) {
2071 QOCIRowIdPointer ptr(new QOCIRowId(d->env));
2072
2073 int r = OCIAttrGet(d->sql, OCI_HTYPE_STMT, ptr.constData()->id,
2074 0, OCI_ATTR_ROWID, d->err);
2075 if (r == OCI_SUCCESS)
2076 return QVariant::fromValue(ptr);
2077 }
2078 return QVariant();
2079}
2080
2081bool QOCIResult::execBatch(bool arrayBind)
2082{
2083 Q_D(QOCIResult);
2084 QOCICols::execBatch(d, boundValues(), arrayBind);
2086 return lastError().type() == QSqlError::NoError;
2087}
2088
2090{
2091 Q_ASSERT(data);
2092
2094}
2095
2097{
2098 Q_D(QOCIResult);
2099 if (isForwardOnly())
2100 d->cache.clear();
2102}
2103
2105
2106
2109{
2110 Q_D(QOCIDriver);
2111#ifdef QOCI_THREADED
2112 const ub4 mode = OCI_UTF16 | OCI_OBJECT | OCI_THREADED;
2113#else
2114 const ub4 mode = OCI_UTF16 | OCI_OBJECT;
2115#endif
2116 int r = OCIEnvCreate(&d->env,
2117 mode,
2118 NULL,
2119 NULL,
2120 NULL,
2121 NULL,
2122 0,
2123 NULL);
2124 if (r != 0) {
2125 qWarning("QOCIDriver: unable to create environment");
2126 setLastError(qMakeError(tr("Unable to initialize", "QOCIDriver"),
2128 return;
2129 }
2130
2131 d->allocErrorHandle();
2132}
2133
2136{
2137 Q_D(QOCIDriver);
2138 d->env = env;
2139 d->svc = ctx;
2140
2141 d->allocErrorHandle();
2142
2143 if (env && ctx) {
2144 setOpen(true);
2145 setOpenError(false);
2146 }
2147}
2148
2150{
2151 Q_D(QOCIDriver);
2152 if (isOpen())
2153 close();
2154 int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR);
2155 if (r != OCI_SUCCESS)
2156 qWarning("Unable to free Error handle: %d", r);
2157 r = OCIHandleFree(d->env, OCI_HTYPE_ENV);
2158 if (r != OCI_SUCCESS)
2159 qWarning("Unable to free Environment handle: %d", r);
2160}
2161
2163{
2164 Q_D(const QOCIDriver);
2165 switch (f) {
2166 case Transactions:
2167 case LastInsertId:
2168 case BLOB:
2169 case PreparedQueries:
2170 case NamedPlaceholders:
2171 case BatchOperations:
2173 return true;
2174 case QuerySize:
2176 case SimpleLocking:
2177 case EventNotifications:
2178 case FinishQuery:
2179 case CancelQuery:
2180 case MultipleResultSets:
2181 return false;
2182 case Unicode:
2183 return d->serverVersion >= 9;
2184 }
2185 return false;
2186}
2187
2188static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
2189{
2190 const QVector<QStringView> opts(QStringView(options).split(u';', Qt::SkipEmptyParts));
2191 for (const auto tmp : opts) {
2192 qsizetype idx;
2193 if ((idx = tmp.indexOf(u'=')) == -1) {
2194 qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
2195 tmp.toLocal8Bit().constData());
2196 continue;
2197 }
2198 const QStringView opt = tmp.left(idx);
2199 const QStringView val = tmp.mid(idx + 1).trimmed();
2200 bool ok;
2201 if (opt == "OCI_ATTR_PREFETCH_ROWS"_L1) {
2202 d->prefetchRows = val.toInt(&ok);
2203 if (!ok)
2204 d->prefetchRows = -1;
2205 } else if (opt == "OCI_ATTR_PREFETCH_MEMORY"_L1) {
2206 d->prefetchMem = val.toInt(&ok);
2207 if (!ok)
2208 d->prefetchMem = -1;
2209 } else if (opt == "OCI_AUTH_MODE"_L1) {
2210 if (val == "OCI_SYSDBA"_L1) {
2211 d->authMode = OCI_SYSDBA;
2212 } else if (val == "OCI_SYSOPER"_L1) {
2213 d->authMode = OCI_SYSOPER;
2214 } else if (val != "OCI_DEFAULT"_L1) {
2215 qWarning("QOCIDriver::parseArgs: Unsupported value for OCI_AUTH_MODE: '%s'",
2216 val.toLocal8Bit().constData());
2217 }
2218 } else {
2219 qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
2220 opt.toLocal8Bit().constData());
2221 }
2222 }
2223}
2224
2226 const QString & user,
2227 const QString & password,
2228 const QString & hostname,
2229 int port,
2230 const QString &opts)
2231{
2232 Q_D(QOCIDriver);
2233 int r;
2234
2235 if (isOpen())
2236 close();
2237
2238 qParseOpts(opts, d);
2239
2240 // Connect without tnsnames.ora if a hostname is given
2241 QString connectionString = db;
2242 if (!hostname.isEmpty())
2243 connectionString =
2244 QString::fromLatin1("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))"
2245 "(CONNECT_DATA=(SID=%3)))").arg(hostname).arg((port > -1 ? port : 1521)).arg(db);
2246
2247 Q_ASSERT(!d->srvhp);
2248 r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->srvhp), OCI_HTYPE_SERVER, 0, nullptr);
2249 if (r == OCI_SUCCESS) {
2250 r = OCIServerAttach(d->srvhp, d->err,
2251 reinterpret_cast<const OraText *>(connectionString.utf16()),
2252 connectionString.length() * sizeof(QChar), OCI_DEFAULT);
2253 }
2254 Q_ASSERT(!d->svc);
2255 if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO) {
2256 r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->svc), OCI_HTYPE_SVCCTX,
2257 0, nullptr);
2258 }
2259 if (r == OCI_SUCCESS)
2260 r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->srvhp, 0, OCI_ATTR_SERVER, d->err);
2261 Q_ASSERT(!d->authp);
2262 if (r == OCI_SUCCESS) {
2263 r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->authp), OCI_HTYPE_SESSION,
2264 0, nullptr);
2265 }
2266 if (r == OCI_SUCCESS) {
2267 r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(user.utf16()),
2268 user.length() * sizeof(QChar), OCI_ATTR_USERNAME, d->err);
2269 }
2270 if (r == OCI_SUCCESS) {
2271 r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(password.utf16()),
2272 password.length() * sizeof(QChar), OCI_ATTR_PASSWORD, d->err);
2273 }
2274 Q_ASSERT(!d->trans);
2275 if (r == OCI_SUCCESS) {
2276 r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->trans), OCI_HTYPE_TRANS,
2277 0, nullptr);
2278 }
2279 if (r == OCI_SUCCESS)
2280 r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->trans, 0, OCI_ATTR_TRANS, d->err);
2281
2282 if (r == OCI_SUCCESS) {
2283 if (user.isEmpty() && password.isEmpty())
2284 r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_EXT, d->authMode);
2285 else
2286 r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_RDBMS, d->authMode);
2287 }
2288 if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
2289 r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->authp, 0, OCI_ATTR_SESSION, d->err);
2290
2291 if (r != OCI_SUCCESS) {
2292 setLastError(qMakeError(tr("Unable to logon"), QSqlError::ConnectionError, d->err));
2293 setOpenError(true);
2294 if (d->trans)
2295 OCIHandleFree(d->trans, OCI_HTYPE_TRANS);
2296 d->trans = nullptr;
2297 if (d->authp)
2298 OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
2299 d->authp = nullptr;
2300 if (d->svc)
2301 OCIHandleFree(d->svc, OCI_HTYPE_SVCCTX);
2302 d->svc = nullptr;
2303 if (d->srvhp)
2304 OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
2305 d->srvhp = nullptr;
2306 return false;
2307 }
2308
2309 // get server version
2310 char vertxt[512];
2311 r = OCIServerVersion(d->svc,
2312 d->err,
2313 reinterpret_cast<OraText *>(vertxt),
2314 sizeof(vertxt),
2315 OCI_HTYPE_SVCCTX);
2316 if (r != 0) {
2317 qWarning("QOCIDriver::open: could not get Oracle server version.");
2318 } else {
2319 QString versionStr;
2320 versionStr = QString(reinterpret_cast<const QChar *>(vertxt));
2321#if QT_CONFIG(regularexpression)
2322 auto match = QRegularExpression("([0-9]+)\\.[0-9\\.]+[0-9]"_L1).match(versionStr);
2323 if (match.hasMatch())
2324 d->serverVersion = match.captured(1).toInt();
2325#endif
2326 if (d->serverVersion == 0)
2327 d->serverVersion = -1;
2328 }
2329
2330 setOpen(true);
2331 setOpenError(false);
2332 d->user = user;
2333
2334 return true;
2335}
2336
2338{
2339 Q_D(QOCIDriver);
2340 if (!isOpen())
2341 return;
2342
2343 OCISessionEnd(d->svc, d->err, d->authp, OCI_DEFAULT);
2344 OCIServerDetach(d->srvhp, d->err, OCI_DEFAULT);
2345 OCIHandleFree(d->trans, OCI_HTYPE_TRANS);
2346 d->trans = nullptr;
2347 OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
2348 d->authp = nullptr;
2349 OCIHandleFree(d->svc, OCI_HTYPE_SVCCTX);
2350 d->svc = nullptr;
2351 OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
2352 d->srvhp = nullptr;
2353 setOpen(false);
2354 setOpenError(false);
2355}
2356
2358{
2359 return new QOCIResult(this);
2360}
2361
2363{
2364 Q_D(QOCIDriver);
2365 if (!isOpen()) {
2366 qWarning("QOCIDriver::beginTransaction: Database not open");
2367 return false;
2368 }
2369 int r = OCITransStart(d->svc,
2370 d->err,
2371 2,
2372 OCI_TRANS_READWRITE);
2373 if (r == OCI_ERROR) {
2374 qOraWarning("QOCIDriver::beginTransaction: ", d->err);
2376 "Unable to begin transaction"), QSqlError::TransactionError, d->err));
2377 return false;
2378 }
2379 d->transaction = true;
2380 return true;
2381}
2382
2384{
2385 Q_D(QOCIDriver);
2386 if (!isOpen()) {
2387 qWarning("QOCIDriver::commitTransaction: Database not open");
2388 return false;
2389 }
2390 int r = OCITransCommit(d->svc,
2391 d->err,
2392 0);
2393 if (r == OCI_ERROR) {
2394 qOraWarning("QOCIDriver::commitTransaction:", d->err);
2396 "Unable to commit transaction"), QSqlError::TransactionError, d->err));
2397 return false;
2398 }
2399 d->transaction = false;
2400 return true;
2401}
2402
2404{
2405 Q_D(QOCIDriver);
2406 if (!isOpen()) {
2407 qWarning("QOCIDriver::rollbackTransaction: Database not open");
2408 return false;
2409 }
2410 int r = OCITransRollback(d->svc,
2411 d->err,
2412 0);
2413 if (r == OCI_ERROR) {
2414 qOraWarning("QOCIDriver::rollbackTransaction:", d->err);
2416 "Unable to rollback transaction"), QSqlError::TransactionError, d->err));
2417 return false;
2418 }
2419 d->transaction = false;
2420 return true;
2421}
2422
2427
2429{
2430 static const char sysUsers[][8] = {
2431 "MDSYS",
2432 "LBACSYS",
2433 "SYS",
2434 "SYSTEM",
2435 "WKSYS",
2436 "CTXSYS",
2437 "WMSYS",
2438 };
2439 static const char joinC[][4] = { "or" , "and" };
2440 static constexpr char16_t bang[] = { u' ', u'!' };
2441
2442 const QLatin1StringView join(joinC[e]);
2443
2445 result.reserve(sizeof sysUsers / sizeof *sysUsers *
2446 // max-sizeof(owner != <sysuser> and )
2447 (9 + sizeof *sysUsers + 5));
2448 for (const auto &sysUser : sysUsers) {
2449 const QLatin1StringView l1(sysUser);
2450 if (l1 != user)
2451 result += "owner "_L1 + bang[e] + "= '"_L1 + l1 + "' "_L1 + join + u' ';
2452 }
2453
2454 result.chop(join.size() + 2); // remove final " <join> "
2455
2456 return result;
2457}
2458
2460{
2461 Q_D(const QOCIDriver);
2462 QStringList tl;
2463
2464 QString user = d->user;
2467 else
2468 user = user.toUpper();
2469
2470 if (!isOpen())
2471 return tl;
2472
2474 t.setForwardOnly(true);
2475 if (type & QSql::Tables) {
2476 const auto tableQuery = "select owner, table_name from all_tables where "_L1;
2477 const QString where = make_where_clause(user, AndExpression);
2478 t.exec(tableQuery + where);
2479 while (t.next()) {
2480 if (t.value(0).toString().toUpper() != user.toUpper())
2481 tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
2482 else
2483 tl.append(t.value(1).toString());
2484 }
2485
2486 // list all table synonyms as well
2487 const auto synonymQuery = "select owner, synonym_name from all_synonyms where "_L1;
2488 t.exec(synonymQuery + where);
2489 while (t.next()) {
2490 if (t.value(0).toString() != d->user)
2491 tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
2492 else
2493 tl.append(t.value(1).toString());
2494 }
2495 }
2496 if (type & QSql::Views) {
2497 const auto query = "select owner, view_name from all_views where "_L1;
2498 const QString where = make_where_clause(user, AndExpression);
2499 t.exec(query + where);
2500 while (t.next()) {
2501 if (t.value(0).toString().toUpper() != d->user.toUpper())
2502 tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
2503 else
2504 tl.append(t.value(1).toString());
2505 }
2506 }
2507 if (type & QSql::SystemTables) {
2508 t.exec("select table_name from dictionary"_L1);
2509 while (t.next()) {
2510 tl.append(t.value(0).toString());
2511 }
2512 const auto tableQuery = "select owner, table_name from all_tables where "_L1;
2513 const QString where = make_where_clause(user, OrExpression);
2514 t.exec(tableQuery + where);
2515 while (t.next()) {
2516 if (t.value(0).toString().toUpper() != user.toUpper())
2517 tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
2518 else
2519 tl.append(t.value(1).toString());
2520 }
2521
2522 // list all table synonyms as well
2523 const auto synonymQuery = "select owner, synonym_name from all_synonyms where "_L1;
2524 t.exec(synonymQuery + where);
2525 while (t.next()) {
2526 if (t.value(0).toString() != d->user)
2527 tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
2528 else
2529 tl.append(t.value(1).toString());
2530 }
2531 }
2532 return tl;
2533}
2534
2535void qSplitTableAndOwner(const QString & tname, QString * tbl,
2536 QString * owner)
2537{
2538 qsizetype i = tname.indexOf(u'.'); // prefixed with owner?
2539 if (i != -1) {
2540 *tbl = tname.right(tname.length() - i - 1);
2541 *owner = tname.left(i);
2542 } else {
2543 *tbl = tname;
2544 }
2545}
2546
2548{
2549 Q_D(const QOCIDriver);
2550 QSqlRecord fil;
2551 if (!isOpen())
2552 return fil;
2553
2555 // using two separate queries for this is A LOT faster than using
2556 // eg. a sub-query on the sys.synonyms table
2557 QString stmt("select column_name, data_type, data_length, "
2558 "data_precision, data_scale, nullable, data_default%1"
2559 "from all_tab_columns a "_L1);
2560 if (d->serverVersion >= 9)
2561 stmt = stmt.arg(", char_length "_L1);
2562 else
2563 stmt = stmt.arg(" "_L1);
2564 bool buildRecordInfo = false;
2565 QString table, owner, tmpStmt;
2566 qSplitTableAndOwner(tablename, &table, &owner);
2567
2570 else
2571 table = table.toUpper();
2572
2573 tmpStmt = stmt + "where a.table_name='"_L1 + table + u'\'';
2574 if (owner.isEmpty()) {
2575 owner = d->user;
2576 }
2577
2579 owner = stripDelimiters(owner, QSqlDriver::TableName);
2580 else
2581 owner = owner.toUpper();
2582
2583 tmpStmt += " and a.owner='"_L1 + owner + u'\'';
2584 t.setForwardOnly(true);
2585 t.exec(tmpStmt);
2586 if (!t.next()) { // try and see if the tablename is a synonym
2587 stmt = stmt + " join all_synonyms b on a.owner=b.table_owner and a.table_name=b.table_name "
2588 "where b.owner='"_L1 + owner + "' and b.synonym_name='"_L1 + table + u'\'';
2589 t.setForwardOnly(true);
2590 t.exec(stmt);
2591 if (t.next())
2592 buildRecordInfo = true;
2593 } else {
2594 buildRecordInfo = true;
2595 }
2596 QStringList keywords = QStringList() << "NUMBER"_L1 << "FLOAT"_L1 << "BINARY_FLOAT"_L1
2597 << "BINARY_DOUBLE"_L1;
2598 if (buildRecordInfo) {
2599 do {
2600 QMetaType ty = qDecodeOCIType(t.value(1).toString(), t.numericalPrecisionPolicy());
2601 QSqlField f(t.value(0).toString(), ty);
2602 f.setRequired(t.value(5).toString() == "N"_L1);
2603 f.setPrecision(t.value(4).toInt());
2604 if (d->serverVersion >= 9 && (ty.id() == QMetaType::QString) && !t.isNull(3) && !keywords.contains(t.value(1).toString())) {
2605 // Oracle9: data_length == size in bytes, char_length == amount of characters
2606 f.setLength(t.value(7).toInt());
2607 } else {
2608 f.setLength(t.value(t.isNull(3) ? 2 : 3).toInt());
2609 }
2610 f.setDefaultValue(t.value(6));
2611 fil.append(f);
2612 } while (t.next());
2613 }
2614 return fil;
2615}
2616
2618{
2619 Q_D(const QOCIDriver);
2620 QSqlIndex idx(tablename);
2621 if (!isOpen())
2622 return idx;
2624 QString stmt("select b.column_name, b.index_name, a.table_name, a.owner "
2625 "from all_constraints a, all_ind_columns b "
2626 "where a.constraint_type='P' "
2627 "and b.index_name = a.index_name "
2628 "and b.index_owner = a.owner"_L1);
2629
2630 bool buildIndex = false;
2631 QString table, owner, tmpStmt;
2632 qSplitTableAndOwner(tablename, &table, &owner);
2633
2636 else
2637 table = table.toUpper();
2638
2639 tmpStmt = stmt + " and a.table_name='"_L1 + table + u'\'';
2640 if (owner.isEmpty()) {
2641 owner = d->user;
2642 }
2643
2645 owner = stripDelimiters(owner, QSqlDriver::TableName);
2646 else
2647 owner = owner.toUpper();
2648
2649 tmpStmt += " and a.owner='"_L1 + owner + u'\'';
2650 t.setForwardOnly(true);
2651 t.exec(tmpStmt);
2652
2653 if (!t.next()) {
2654 stmt += " and a.table_name=(select tname from sys.synonyms where sname='"_L1
2655 + table + "' and creator=a.owner)"_L1;
2656 t.setForwardOnly(true);
2657 t.exec(stmt);
2658 if (t.next()) {
2659 owner = t.value(3).toString();
2660 buildIndex = true;
2661 }
2662 } else {
2663 buildIndex = true;
2664 }
2665 if (buildIndex) {
2666 QSqlQuery tt(createResult());
2667 tt.setForwardOnly(true);
2668 idx.setName(t.value(1).toString());
2669 do {
2670 tt.exec("select data_type from all_tab_columns where table_name='"_L1 +
2671 t.value(2).toString() + "' and column_name='"_L1 +
2672 t.value(0).toString() + "' and owner='"_L1 +
2673 owner + u'\'');
2674 if (!tt.next()) {
2675 return QSqlIndex();
2676 }
2677 QSqlField f(t.value(0).toString(), qDecodeOCIType(tt.value(0).toString(), t.numericalPrecisionPolicy()));
2678 idx.append(f);
2679 } while (t.next());
2680 return idx;
2681 }
2682 return QSqlIndex();
2683}
2684
2685QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const
2686{
2687 switch (field.typeID()) {
2688 case QMetaType::QDateTime: {
2689 QDateTime datetime = field.value().toDateTime();
2690 QString datestring;
2691 if (datetime.isValid()) {
2692 datestring = "TO_DATE('"_L1 + QString::number(datetime.date().year())
2693 + u'-'
2694 + QString::number(datetime.date().month()) + u'-'
2695 + QString::number(datetime.date().day()) + u' '
2696 + QString::number(datetime.time().hour()) + u':'
2697 + QString::number(datetime.time().minute()) + u':'
2698 + QString::number(datetime.time().second())
2699 + "','YYYY-MM-DD HH24:MI:SS')"_L1;
2700 } else {
2701 datestring = "NULL"_L1;
2702 }
2703 return datestring;
2704 }
2705 case QMetaType::QTime: {
2706 QDateTime datetime = field.value().toDateTime();
2707 QString datestring;
2708 if (datetime.isValid()) {
2709 datestring = "TO_DATE('"_L1
2710 + QString::number(datetime.time().hour()) + u':'
2711 + QString::number(datetime.time().minute()) + u':'
2712 + QString::number(datetime.time().second())
2713 + "','HH24:MI:SS')"_L1;
2714 } else {
2715 datestring = "NULL"_L1;
2716 }
2717 return datestring;
2718 }
2719 case QMetaType::QDate: {
2720 QDate date = field.value().toDate();
2721 QString datestring;
2722 if (date.isValid()) {
2723 datestring = "TO_DATE('"_L1 + QString::number(date.year()) +
2724 u'-' +
2725 QString::number(date.month()) + u'-' +
2726 QString::number(date.day()) + "','YYYY-MM-DD')"_L1;
2727 } else {
2728 datestring = "NULL"_L1;
2729 }
2730 return datestring;
2731 }
2732 default:
2733 break;
2734 }
2735 return QSqlDriver::formatValue(field, trimStrings);
2736}
2737
2739{
2740 Q_D(const QOCIDriver);
2741 return QVariant::fromValue(d->env);
2742}
2743
2745{
2746 QString res = identifier;
2747 if (!identifier.isEmpty() && !isIdentifierEscaped(identifier, type)) {
2748 res.replace(u'"', "\"\""_L1);
2749 res.replace(u'.', "\".\""_L1);
2750 res = u'"' + res + u'"';
2751 }
2752 return res;
2753}
2754
2756{
2757 Q_D(const QOCIDriver);
2758 Q_UNUSED(type);
2759 return d->serverVersion > 12 ? 128 : 30;
2760}
2761
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
Definition qbytearray.h:557
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
Definition qbytearray.h:523
qsizetype capacity() const
Returns the maximum number of bytes that can be stored in the byte array without forcing a reallocati...
Definition qbytearray.h:555
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
\inmodule QtCore
Definition qchar.h:48
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
Definition qdatetime.h:257
QTime time() const
Returns the time part of the datetime.
bool isValid() const
Returns true if this datetime represents a definite moment, otherwise false.
QDate date() const
Returns the date part of the datetime.
\inmodule QtCore \reentrant
Definition qdatetime.h:27
constexpr bool isValid() const
Returns true if this date is valid; otherwise returns false.
Definition qdatetime.h:86
int month() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int day() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
constexpr void chop(qsizetype n)
constexpr qsizetype size() const noexcept
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
value_type takeFirst()
Definition qlist.h:549
T value(qsizetype i) const
Definition qlist.h:661
qsizetype count() const noexcept
Definition qlist.h:387
pointer data()
Definition qlist.h:414
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmetatype.h:320
int id(int=0) const
Definition qmetatype.h:454
int readPiecewise(QVariantList &values, int index=0)
int fieldFromDefine(OCIDefine *d)
void getValues(QVariantList &v, int index)
int readLOBs(QVariantList &values, int index=0)
static bool execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool arrayBind)
QSqlRecord rec
Definition qsql_oci.cpp:807
int size()
Definition qsql_oci.cpp:804
QOCICols(int size, QOCIResultPrivate *dp)
Definition qsql_oci.cpp:858
OCIDateTime * dateTime
Definition qsql_oci.cpp:125
static QDateTime fromOCIDateTime(OCIEnv *env, OCIError *err, OCIDateTime *dt)
Definition qsql_oci.cpp:151
QOCIDateTime(OCIEnv *env, OCIError *err, const QDateTime &dt=QDateTime())
Definition qsql_oci.cpp:129
void allocErrorHandle()
Definition qsql_oci.cpp:544
OCITrans * trans
Definition qsql_oci.cpp:190
OCISession * authp
Definition qsql_oci.cpp:189
OCIServer * srvhp
Definition qsql_oci.cpp:188
OCISvcCtx * svc
Definition qsql_oci.cpp:187
QString formatValue(const QSqlField &field, bool trimStrings) const override
Returns a string representation of the field value for the database.
bool rollbackTransaction() override
This function is called to rollback a transaction.
int maximumIdentifierLength(IdentifierType type) const override
QStringList tables(QSql::TableType) const override
Returns a list of the names of the tables in the database.
QSqlIndex primaryIndex(const QString &tablename) const override
Returns the primary index for table tableName.
bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, const QString &connOpts) override
Derived classes must reimplement this pure virtual function to open a database connection on database...
bool hasFeature(DriverFeature f) const override
Returns true if the driver supports feature feature; otherwise returns false.
bool commitTransaction() override
This function is called to commit a transaction.
bool beginTransaction() override
This function is called to begin a transaction.
QSqlRecord record(const QString &tablename) const override
Returns a QSqlRecord populated with the names of the fields in table tableName.
QSqlResult * createResult() const override
Creates an empty SQL result on the database.
QVariant handle() const override
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
void close() override
Derived classes must reimplement this pure virtual function in order to close the database connection...
QOCIDriver(QObject *parent=nullptr)
QString escapeIdentifier(const QString &identifier, IdentifierType) const override
Returns the identifier escaped according to the database rules.
QOCICols * cols
Definition qsql_oci.cpp:237
void setCharset(dvoid *handle, ub4 type) const
Definition qsql_oci.cpp:258
void setStatementAttributes()
Definition qsql_oci.cpp:294
QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv)
bool isOutValue(int i) const
Definition qsql_oci.cpp:253
int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, const QVariant &val, dvoid *indPtr, ub2 *tmpSize, TempStorage &tmpStorage)
Definition qsql_oci.cpp:324
int bindValues(QVariantList &values, IndicatorArray &indicators, SizeArray &tmpSizes, TempStorage &tmpStorage)
Definition qsql_oci.cpp:470
OCISvcCtx *& svc
Definition qsql_oci.cpp:240
bool isBinaryValue(int i) const
Definition qsql_oci.cpp:255
void outValues(QVariantList &values, IndicatorArray &indicators, TempStorage &tmpStorage)
Definition qsql_oci.cpp:519
bool execBatch(bool arrayBind=false) override
QOCIResult(const QOCIDriver *db)
int numRowsAffected() override
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
friend class QOCICols
Definition qsql_oci.cpp:209
QSqlRecord record() const override
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
bool exec() override
Executes the query, returning true if successful; otherwise returns false.
bool reset(const QString &query) override
Sets the result to use the SQL statement query for subsequent data retrieval.
bool prepare(const QString &query) override
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
int size() override
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
QVariant handle() const override
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
bool gotoNext(ValueCache &values, int index) override
void virtual_hook(int id, void *data) override
bool fetchNext() override
Positions the result to the next available record (row) in the result.
QVariant lastInsertId() const override
Returns the object ID of the most recent inserted row if the database supports it.
QOCIRowId(OCIEnv *env)
Definition qsql_oci.cpp:107
OCIRowid * id
Definition qsql_oci.cpp:101
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore \reentrant
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
\inmodule QtCore
Definition qshareddata.h:35
\inmodule QtCore
Definition qshareddata.h:19
void virtual_hook(int id, void *data) override
void init(int colCount)
bool fetchNext() override
Positions the result to the next available record (row) in the result.
QSqlDriver::DbmsType dbmsType
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition qsqldriver.h:25
virtual QString formatValue(const QSqlField &field, bool trimStrings=false) const
Returns a string representation of the field value for the database.
IdentifierType
This enum contains a list of SQL identifier types.
Definition qsqldriver.h:40
virtual QString stripDelimiters(const QString &identifier, IdentifierType type) const
Returns the identifier with the leading and trailing delimiters removed, identifier can either be a t...
DriverFeature
This enum contains a list of features a driver might support.
Definition qsqldriver.h:32
@ PositionalPlaceholders
Definition qsqldriver.h:33
@ LowPrecisionNumbers
Definition qsqldriver.h:34
@ EventNotifications
Definition qsqldriver.h:35
@ PreparedQueries
Definition qsqldriver.h:32
@ NamedPlaceholders
Definition qsqldriver.h:33
@ BatchOperations
Definition qsqldriver.h:34
@ MultipleResultSets
Definition qsqldriver.h:35
virtual void setLastError(const QSqlError &e)
This function is used to set the value of the last error, error, that occurred on the database.
virtual bool isOpen() const
Returns true if the database connection is open; otherwise returns false.
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
virtual bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const
Returns whether identifier is escaped according to the database rules.
virtual void setOpen(bool o)
This function sets the open state of the database to open.
The QSqlError class provides SQL database error information.
Definition qsqlerror.h:17
ErrorType type() const
Returns the error type, or -1 if the type cannot be determined.
ErrorType
This enum type describes the context in which the error occurred, e.g., a connection error,...
Definition qsqlerror.h:19
@ StatementError
Definition qsqlerror.h:22
@ TransactionError
Definition qsqlerror.h:23
@ ConnectionError
Definition qsqlerror.h:21
The QSqlField class manipulates the fields in SQL database tables and views.
Definition qsqlfield.h:19
int typeID() const
QVariant value() const
Returns the value of the field as a QVariant.
Definition qsqlfield.h:37
The QSqlIndex class provides functions to manipulate and describe database indexes.
Definition qsqlindex.h:16
void setName(const QString &name)
Sets the name of the index to name.
Definition qsqlindex.cpp:90
void append(const QSqlField &field)
Appends the field field to the list of indexed fields.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition qsqlquery.h:23
bool next()
Retrieves the next record in the result, if available, and positions the query on the retrieved recor...
QVariant value(int i) const
Returns the value of field index in the current record.
void setForwardOnly(bool forward)
Sets forward only mode to forward.
bool exec(const QString &query)
Executes the SQL in query.
The QSqlRecord class encapsulates a database record.
Definition qsqlrecord.h:20
void append(const QSqlField &field)
Append a copy of field field to the end of the record.
static bool isVariantNull(const QVariant &variant)
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases.
Definition qsqlresult.h:25
bool isForwardOnly() const
Returns true if you can only scroll forward through the result set; otherwise returns false.
int at() const
Returns the current (zero-based) row position of the result.
virtual bool prepare(const QString &query)
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index.
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
QString lastQuery() const
Returns the current SQL query text, or an empty string if there isn't one.
bool hasOutValues() const
Returns true if at least one of the query's bound values is a QSql::Out or a QSql::InOut; otherwise r...
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active.
QVariantList & boundValues(QT6_DECL_NEW_OVERLOAD)
void resetBindCount()
Resets the number of bind parameters.
QSqlError lastError() const
Returns the last error associated with the result.
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
int boundValueCount() const
Returns the number of bound values in the result.
virtual void bindValue(int pos, const QVariant &val, QSql::ParamType type)
Binds the value val of parameter type paramType to position index in the current record (row).
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
QStringView trimmed() const noexcept
Strips leading and trailing whitespace and returns the result.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString right(qsizetype n) const
Returns a substring that contains the n rightmost characters of the string.
Definition qstring.cpp:5180
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
qsizetype capacity() const
Returns the maximum number of characters that can be stored in the string without forcing a reallocat...
Definition qstring.h:1111
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QByteArray toLocal8Bit() const &
Definition qstring.h:567
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString toUpper() const &
Definition qstring.h:372
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
static QTimeZone fromSecondsAheadOfUtc(int offset)
Definition qtimezone.h:129
\inmodule QtCore \reentrant
Definition qdatetime.h:189
int hour() const
Returns the hour part (0 to 23) of the time.
int minute() const
Returns the minute part (0 to 59) of the time.
int msec() const
Returns the millisecond part (0 to 999) of the time.
int second() const
Returns the second part (0 to 59) of the time.
void append(const T &t)
\inmodule QtCore
Definition qvariant.h:64
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has userType() \l QMetaType::QDateTime,...
QList< QVariant > toList() const
Returns the variant as a QVariantList if the variant has userType() \l QMetaType::QVariantList.
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
int typeId() const
Returns the storage type of the value stored in the variant.
Definition qvariant.h:337
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:531
QDate toDate() const
Returns the variant as a QDate if the variant has userType() \l QMetaType::QDate, \l QMetaType::QDate...
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has userType() \l QMetaType::QByteArray or \l QMet...
QMetaType metaType() const
EGLContext ctx
#define this
Definition dialogs.cpp:9
QString str
[2]
QString text
QDate date
[1]
qDeleteAll(list.begin(), list.end())
double e
QStyleOptionButton opt
static const struct @480 keywords[]
@ AfterLastRow
Definition qtsqlglobal.h:23
@ BeforeFirstRow
Definition qtsqlglobal.h:22
@ SystemTables
Definition qtsqlglobal.h:38
@ Views
Definition qtsqlglobal.h:39
@ Tables
Definition qtsqlglobal.h:37
@ Binary
Definition qtsqlglobal.h:31
NumericalPrecisionPolicy
Definition qtsqlglobal.h:44
@ LowPrecisionInt32
Definition qtsqlglobal.h:45
@ LowPrecisionDouble
Definition qtsqlglobal.h:47
@ LowPrecisionInt64
Definition qtsqlglobal.h:46
@ HighPrecision
Definition qtsqlglobal.h:49
Combined button and popup list for selecting options.
@ SkipEmptyParts
Definition qnamespace.h:127
#define Q_FALLTHROUGH()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputPortEXT port
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
static ControlElement< T > * ptr(QWidget *widget)
#define Q_DECLARE_OPAQUE_POINTER(POINTER)
Definition qmetatype.h:1496
#define Q_DECLARE_METATYPE(TYPE)
Definition qmetatype.h:1504
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLenum GLsizei dataSize
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLsizei GLenum GLenum GLuint GLenum GLsizei * lengths
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum const GLint * param
GLbyte GLbyte tz
GLboolean reset
GLenum query
GLuint res
const GLubyte * c
GLuint GLfloat * val
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLbyte ty
GLenum GLenum GLsizei void * table
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void split(QT_FT_Vector *b)
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QDB2DriverPrivate *p)
Definition qsql_db2.cpp:203
static QString make_where_clause(const QString &user, Expression e)
int qReadLob(T &buf, const QOCIResultPrivate *d, OCILobLocator *lob)
QSharedDataPointer< QOCIRowId > QOCIRowIdPointer
Definition qsql_oci.cpp:174
#define QOCI_PREFETCH_MEM
Definition qsql_oci.cpp:38
static void qOraOutValue(QVariant &value, TempStorage &tmpStorage, OCIEnv *env, OCIError *err)
Definition qsql_oci.cpp:489
static qlonglong qMakeLongLong(const char *ociNumber, OCIError *err)
Definition qsql_oci.cpp:779
static QString qOraWarn(OCIError *err, int *errorCode=0)
Definition qsql_oci.cpp:567
static qulonglong qMakeULongLong(const char *ociNumber, OCIError *err)
Definition qsql_oci.cpp:787
static void qOraWarning(const char *msg, OCIError *err)
Definition qsql_oci.cpp:586
#define QOCI_DYNAMIC_CHUNK_SIZE
Definition qsql_oci.cpp:37
static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
@ QOCIEncoding
Definition qsql_oci.cpp:57
static QSqlField qFromOraInf(const OraFieldInfo &ofi)
Definition qsql_oci.cpp:730
static QSqlError qMakeError(const QString &errString, QSqlError::ErrorType type, OCIError *err)
Definition qsql_oci.cpp:609
static int qOraErrorNumber(OCIError *err)
Definition qsql_oci.cpp:596
static const ub2 qOraCharset
Definition qsql_oci.cpp:73
Expression
@ AndExpression
@ OrExpression
QVarLengthArray< ub2, 32 > SizeArray
Definition qsql_oci.cpp:77
QMetaType qDecodeOCIType(const QString &ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
Definition qsql_oci.cpp:617
static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err)
Definition qsql_oci.cpp:750
void qSplitTableAndOwner(const QString &tname, QString *tbl, QString *owner)
QVarLengthArray< sb2, 32 > IndicatorArray
Definition qsql_oci.cpp:76
struct OCIEnv OCIEnv
Definition qsql_oci_p.h:26
struct OCISvcCtx OCISvcCtx
Definition qsql_oci_p.h:27
#define Q_DECLARE_SQLDRIVER_PRIVATE(Class)
#define qPrintable(string)
Definition qstring.h:1391
static char * toLocal8Bit(char *out, QStringView in, QStringConverter::State *state)
#define QT_BEGIN_INCLUDE_NAMESPACE
#define QT_END_INCLUDE_NAMESPACE
#define tr(X)
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
int qint32
Definition qtypes.h:44
quint64 qulonglong
Definition qtypes.h:59
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned short ushort
Definition qtypes.h:28
qint64 qlonglong
Definition qtypes.h:58
static int toInt(const QChar &qc, int R)
QList< int > list
[14]
QByteArray ba
[0]
QFileInfo fi("c:/temp/foo")
[newstuff]
QObject::connect nullptr
QMimeDatabase db
[0]
QDateTime dateTime
[12]
QSharedPointer< T > other(t)
[5]
Text files * txt
view create()
QMetaType type
Definition qsql_oci.cpp:558
QString name
Definition qsql_oci.cpp:557
QOCIBatchCleanupHandler(QList< QOCIBatchColumn > &columns)
QList< QOCIBatchColumn > & col
OCIBind * bindh
QList< QOCIDateTime * > dateTimes
Definition qsql_oci.cpp:171
QList< QByteArray > rawData
Definition qsql_oci.cpp:170
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent