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