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