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