Qt 4.8
qsql_odbc.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_odbc.h"
43 #include <qsqlrecord.h>
44 
45 #if defined (Q_OS_WIN32)
46 #include <qt_windows.h>
47 #endif
48 #include <qcoreapplication.h>
49 #include <qvariant.h>
50 #include <qdatetime.h>
51 #include <qsqlerror.h>
52 #include <qsqlfield.h>
53 #include <qsqlindex.h>
54 #include <qstringlist.h>
55 #include <qvarlengtharray.h>
56 #include <qvector.h>
57 #include <qmath.h>
58 #include <QDebug>
59 #include <QSqlQuery>
60 
62 
63 // undefine this to prevent initial check of the ODBC driver
64 #define ODBC_CHECK_DRIVER
65 
66 static const int COLNAMESIZE = 256;
67 //Map Qt parameter types to ODBC types
68 static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
69 
70 inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int size=-1)
71 {
72  QString result;
73 
74  int realsize = qMin(size, input.size());
75  if(realsize > 0 && input[realsize-1] == 0)
76  realsize--;
77  switch(sizeof(SQLTCHAR)) {
78  case 1:
79  result=QString::fromUtf8((const char *)input.constData(), realsize);
80  break;
81  case 2:
82  result=QString::fromUtf16((const ushort *)input.constData(), realsize);
83  break;
84  case 4:
85  result=QString::fromUcs4((const uint *)input.constData(), realsize);
86  break;
87  default:
88  qCritical() << "sizeof(SQLTCHAR) is " << sizeof(SQLTCHAR) << "Don't know how to handle this";
89  }
90  return result;
91 }
92 
93 inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
94 {
96  result.resize(input.size());
97  switch(sizeof(SQLTCHAR)) {
98  case 1:
99  memcpy(result.data(), input.toUtf8().data(), input.size());
100  break;
101  case 2:
102  memcpy(result.data(), input.unicode(), input.size() * 2);
103  break;
104  case 4:
105  memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
106  break;
107  default:
108  qCritical() << "sizeof(SQLTCHAR) is " << sizeof(SQLTCHAR) << "Don't know how to handle this";
109  }
110  result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
111  return result;
112 }
113 
115 {
116 public:
119  : hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19), isMySqlServer(false),
120  isMSSqlServer(false), isFreeTDSDriver(false), hasSQLFetchScroll(true),
121  hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"'))
122  {
123  }
124 
125  SQLHANDLE hEnv;
126  SQLHANDLE hDbc;
127 
128  bool unicode;
129  bool useSchema;
130  int disconnectCount;
131  int datetime_precision;
132  bool isMySqlServer;
133  bool isMSSqlServer;
134  bool isFreeTDSDriver;
135  bool hasSQLFetchScroll;
136  bool hasMultiResultSets;
137 
138  bool checkDriver() const;
139  void checkUnicode();
140  void checkSqlServer();
141  void checkHasSQLFetchScroll();
142  void checkHasMultiResults();
143  void checkSchemaUsage();
144  void checkDateTimePrecision();
145  bool setConnectionOptions(const QString& connOpts);
146  void splitTableQualifier(const QString &qualifier, QString &catalog,
147  QString &schema, QString &table);
148  DefaultCase defaultCase() const;
149  QString adjustCase(const QString&) const;
150  QChar quoteChar();
151 private:
152  bool isQuoteInitialized;
153  QChar quote;
154 };
155 
157 {
158 public:
160  : hStmt(0), useSchema(false), hasSQLFetchScroll(true), driverPrivate(dpp), userForwardOnly(false)
161  {
162  unicode = dpp->unicode;
163  useSchema = dpp->useSchema;
164  disconnectCount = dpp->disconnectCount;
165  hasSQLFetchScroll = dpp->hasSQLFetchScroll;
166  }
167 
168  inline void clearValues()
169  { fieldCache.fill(QVariant()); fieldCacheIdx = 0; }
170 
171  SQLHANDLE dpEnv() const { return driverPrivate ? driverPrivate->hEnv : 0;}
172  SQLHANDLE dpDbc() const { return driverPrivate ? driverPrivate->hDbc : 0;}
173  SQLHANDLE hStmt;
174 
175  bool unicode;
176  bool useSchema;
177 
185 
186  bool isStmtHandleValid(const QSqlDriver *driver);
187  void updateStmtHandleState(const QSqlDriver *driver);
188 };
189 
191 {
192  const QODBCDriver *odbcdriver = static_cast<const QODBCDriver*> (driver);
193  return disconnectCount == odbcdriver->d->disconnectCount;
194 }
195 
197 {
198  const QODBCDriver *odbcdriver = static_cast<const QODBCDriver*> (driver);
199  disconnectCount = odbcdriver->d->disconnectCount;
200 }
201 
202 static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
203 {
204  SQLINTEGER nativeCode_ = 0;
205  SQLSMALLINT msgLen = 0;
206  SQLRETURN r = SQL_NO_DATA;
207  SQLTCHAR state_[SQL_SQLSTATE_SIZE+1];
208  QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH);
209  QString result;
210  int i = 1;
211 
212  description_[0] = 0;
213  do {
214  r = SQLGetDiagRec(handleType,
215  handle,
216  i,
217  state_,
218  &nativeCode_,
219  0,
220  0,
221  &msgLen);
222  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && msgLen > 0)
223  description_.resize(msgLen+1);
224  r = SQLGetDiagRec(handleType,
225  handle,
226  i,
227  state_,
228  &nativeCode_,
229  description_.data(),
230  description_.size(),
231  &msgLen);
232  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
233  if (nativeCode)
234  *nativeCode = nativeCode_;
235  QString tmpstore;
236 #ifdef UNICODE
237  tmpstore = fromSQLTCHAR(description_, msgLen);
238 #else
239  tmpstore = QString::fromUtf8((const char*)description_.constData(), msgLen);
240 #endif
241  if(result != tmpstore) {
242  if(!result.isEmpty())
243  result += QLatin1Char(' ');
244  result += tmpstore;
245  }
246  } else if (r == SQL_ERROR || r == SQL_INVALID_HANDLE) {
247  return result;
248  }
249  ++i;
250  } while (r != SQL_NO_DATA);
251  return result;
252 }
253 
254 static QString qODBCWarn(const QODBCPrivate* odbc, int *nativeCode = 0)
255 {
256  return QString(qWarnODBCHandle(SQL_HANDLE_ENV, odbc->dpEnv()) + QLatin1Char(' ')
257  + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->dpDbc()) + QLatin1Char(' ')
258  + qWarnODBCHandle(SQL_HANDLE_STMT, odbc->hStmt, nativeCode)).simplified();
259 }
260 
261 static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0)
262 {
263  return QString(qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1Char(' ')
264  + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc, nativeCode)).simplified();
265 }
266 
267 static void qSqlWarning(const QString& message, const QODBCPrivate* odbc)
268 {
269  qWarning() << message << "\tError:" << qODBCWarn(odbc);
270 }
271 
272 static void qSqlWarning(const QString &message, const QODBCDriverPrivate *odbc)
273 {
274  qWarning() << message << "\tError:" << qODBCWarn(odbc);
275 }
276 
278 {
279  int nativeCode = -1;
280  QString message = qODBCWarn(p, &nativeCode);
281  return QSqlError(QLatin1String("QODBC3: ") + err, message, type, nativeCode);
282 }
283 
285  const QODBCDriverPrivate* p)
286 {
287  int nativeCode = -1;
288  QString message = qODBCWarn(p, &nativeCode);
289  return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, nativeCode);
290 }
291 
292 template<class T>
293 static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, const T* p, bool isSigned = true)
294 {
295  Q_UNUSED(p);
297  switch (sqltype) {
298  case SQL_DECIMAL:
299  case SQL_NUMERIC:
300  case SQL_REAL:
301  case SQL_FLOAT:
302  case SQL_DOUBLE:
303  type = QVariant::Double;
304  break;
305  case SQL_SMALLINT:
306  case SQL_INTEGER:
307  case SQL_BIT:
308  type = isSigned ? QVariant::Int : QVariant::UInt;
309  break;
310  case SQL_TINYINT:
311  type = QVariant::UInt;
312  break;
313  case SQL_BIGINT:
314  type = isSigned ? QVariant::LongLong : QVariant::ULongLong;
315  break;
316  case SQL_BINARY:
317  case SQL_VARBINARY:
318  case SQL_LONGVARBINARY:
319  type = QVariant::ByteArray;
320  break;
321  case SQL_DATE:
322  case SQL_TYPE_DATE:
323  type = QVariant::Date;
324  break;
325  case SQL_TIME:
326  case SQL_TYPE_TIME:
327  type = QVariant::Time;
328  break;
329  case SQL_TIMESTAMP:
330  case SQL_TYPE_TIMESTAMP:
331  type = QVariant::DateTime;
332  break;
333  case SQL_WCHAR:
334  case SQL_WVARCHAR:
335  case SQL_WLONGVARCHAR:
336  type = QVariant::String;
337  break;
338  case SQL_CHAR:
339  case SQL_VARCHAR:
340 #if (ODBCVER >= 0x0350)
341  case SQL_GUID:
342 #endif
343  case SQL_LONGVARCHAR:
344  type = QVariant::String;
345  break;
346  default:
347  type = QVariant::ByteArray;
348  break;
349  }
350  return type;
351 }
352 
353 static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool unicode = false)
354 {
355  QString fieldVal;
356  SQLRETURN r = SQL_ERROR;
357  SQLLEN lengthIndicator = 0;
358 
359  // NB! colSize must be a multiple of 2 for unicode enabled DBs
360  if (colSize <= 0) {
361  colSize = 256;
362  } else if (colSize > 65536) { // limit buffer size to 64 KB
363  colSize = 65536;
364  } else {
365  colSize++; // make sure there is room for more than the 0 termination
366  }
367  if(unicode) {
368  r = SQLGetData(hStmt,
369  column+1,
370  SQL_C_TCHAR,
371  NULL,
372  0,
373  &lengthIndicator);
374  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
375  colSize = lengthIndicator/sizeof(SQLTCHAR) + 1;
376  QVarLengthArray<SQLTCHAR> buf(colSize);
377  memset(buf.data(), 0, colSize*sizeof(SQLTCHAR));
378  while (true) {
379  r = SQLGetData(hStmt,
380  column+1,
381  SQL_C_TCHAR,
382  (SQLPOINTER)buf.data(),
383  colSize*sizeof(SQLTCHAR),
384  &lengthIndicator);
385  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
386  if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
387  fieldVal.clear();
388  break;
389  }
390  // if SQL_SUCCESS_WITH_INFO is returned, indicating that
391  // more data can be fetched, the length indicator does NOT
392  // contain the number of bytes returned - it contains the
393  // total number of bytes that CAN be fetched
394  // colSize-1: remove 0 termination when there is more data to fetch
395  int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator/sizeof(SQLTCHAR);
396  fieldVal += fromSQLTCHAR(buf, rSize);
397  if (lengthIndicator < SQLLEN(colSize*sizeof(SQLTCHAR))) {
398  // workaround for Drivermanagers that don't return SQL_NO_DATA
399  break;
400  }
401  } else if (r == SQL_NO_DATA) {
402  break;
403  } else {
404  qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
405  fieldVal.clear();
406  break;
407  }
408  }
409  } else {
410  r = SQLGetData(hStmt,
411  column+1,
412  SQL_C_CHAR,
413  NULL,
414  0,
415  &lengthIndicator);
416  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
417  colSize = lengthIndicator + 1;
418  QVarLengthArray<SQLCHAR> buf(colSize);
419  while (true) {
420  r = SQLGetData(hStmt,
421  column+1,
422  SQL_C_CHAR,
423  (SQLPOINTER)buf.data(),
424  colSize,
425  &lengthIndicator);
426  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
427  if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
428  fieldVal.clear();
429  break;
430  }
431  // if SQL_SUCCESS_WITH_INFO is returned, indicating that
432  // more data can be fetched, the length indicator does NOT
433  // contain the number of bytes returned - it contains the
434  // total number of bytes that CAN be fetched
435  // colSize-1: remove 0 termination when there is more data to fetch
436  int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator;
437  fieldVal += QString::fromUtf8((const char *)buf.constData(), rSize);
438  if (lengthIndicator < SQLLEN(colSize)) {
439  // workaround for Drivermanagers that don't return SQL_NO_DATA
440  break;
441  }
442  } else if (r == SQL_NO_DATA) {
443  break;
444  } else {
445  qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
446  fieldVal.clear();
447  break;
448  }
449  }
450  }
451  return fieldVal;
452 }
453 
454 static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
455 {
456  QByteArray fieldVal;
457  SQLSMALLINT colNameLen;
458  SQLSMALLINT colType;
459  SQLULEN colSize;
460  SQLSMALLINT colScale;
461  SQLSMALLINT nullable;
462  SQLLEN lengthIndicator = 0;
463  SQLRETURN r = SQL_ERROR;
464 
466 
467  r = SQLDescribeCol(hStmt,
468  column + 1,
469  colName.data(),
470  COLNAMESIZE,
471  &colNameLen,
472  &colType,
473  &colSize,
474  &colScale,
475  &nullable);
476  if (r != SQL_SUCCESS)
477  qWarning() << "qGetBinaryData: Unable to describe column" << column;
478  // SQLDescribeCol may return 0 if size cannot be determined
479  if (!colSize)
480  colSize = 255;
481  else if (colSize > 65536) // read the field in 64 KB chunks
482  colSize = 65536;
483  fieldVal.resize(colSize);
484  ulong read = 0;
485  while (true) {
486  r = SQLGetData(hStmt,
487  column+1,
488  SQL_C_BINARY,
489  (SQLPOINTER)(fieldVal.constData() + read),
490  colSize,
491  &lengthIndicator);
492  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
493  break;
494  if (lengthIndicator == SQL_NULL_DATA)
496  if (lengthIndicator > SQLLEN(colSize) || lengthIndicator == SQL_NO_TOTAL) {
497  read += colSize;
498  colSize = 65536;
499  } else {
500  read += lengthIndicator;
501  }
502  if (r == SQL_SUCCESS) { // the whole field was read in one chunk
503  fieldVal.resize(read);
504  break;
505  }
506  fieldVal.resize(fieldVal.size() + colSize);
507  }
508  return fieldVal;
509 }
510 
511 static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
512 {
513  SQLINTEGER intbuf = 0;
514  SQLLEN lengthIndicator = 0;
515  SQLRETURN r = SQLGetData(hStmt,
516  column+1,
517  isSigned ? SQL_C_SLONG : SQL_C_ULONG,
518  (SQLPOINTER)&intbuf,
519  sizeof(intbuf),
520  &lengthIndicator);
521  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
522  return QVariant(QVariant::Invalid);
523  if (lengthIndicator == SQL_NULL_DATA)
524  return QVariant(QVariant::Int);
525  if (isSigned)
526  return int(intbuf);
527  else
528  return uint(intbuf);
529 }
530 
531 static QVariant qGetDoubleData(SQLHANDLE hStmt, int column)
532 {
533  SQLDOUBLE dblbuf;
534  SQLLEN lengthIndicator = 0;
535  SQLRETURN r = SQLGetData(hStmt,
536  column+1,
537  SQL_C_DOUBLE,
538  (SQLPOINTER) &dblbuf,
539  0,
540  &lengthIndicator);
541  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
542  return QVariant(QVariant::Invalid);
543  }
544  if(lengthIndicator == SQL_NULL_DATA)
545  return QVariant(QVariant::Double);
546 
547  return (double) dblbuf;
548 }
549 
550 
551 static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
552 {
553  SQLBIGINT lngbuf = 0;
554  SQLLEN lengthIndicator = 0;
555  SQLRETURN r = SQLGetData(hStmt,
556  column+1,
557  isSigned ? SQL_C_SBIGINT : SQL_C_UBIGINT,
558  (SQLPOINTER) &lngbuf,
559  sizeof(lngbuf),
560  &lengthIndicator);
561  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
562  return QVariant(QVariant::Invalid);
563  if (lengthIndicator == SQL_NULL_DATA)
565 
566  if (isSigned)
567  return qint64(lngbuf);
568  else
569  return quint64(lngbuf);
570 }
571 
572 // creates a QSqlField from a valid hStmt generated
573 // by SQLColumns. The hStmt has to point to a valid position.
574 static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate* p)
575 {
576  QString fname = qGetStringData(hStmt, 3, -1, p->unicode);
577  int type = qGetIntData(hStmt, 4).toInt(); // column type
578  QSqlField f(fname, qDecodeODBCType(type, p));
579  int required = qGetIntData(hStmt, 10).toInt(); // nullable-flag
580  // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
581  if (required == SQL_NO_NULLS)
582  f.setRequired(true);
583  else if (required == SQL_NULLABLE)
584  f.setRequired(false);
585  // else we don't know
586  QVariant var = qGetIntData(hStmt, 6);
587  f.setLength(var.isNull() ? -1 : var.toInt()); // column size
588  var = qGetIntData(hStmt, 8).toInt();
589  f.setPrecision(var.isNull() ? -1 : var.toInt()); // precision
590  f.setSqlType(type);
591  return f;
592 }
593 
594 static QSqlField qMakeFieldInfo(const QODBCPrivate* p, int i )
595 {
596  SQLSMALLINT colNameLen;
597  SQLSMALLINT colType;
598  SQLULEN colSize;
599  SQLSMALLINT colScale;
600  SQLSMALLINT nullable;
601  SQLRETURN r = SQL_ERROR;
603  r = SQLDescribeCol(p->hStmt,
604  i+1,
605  colName.data(),
606  (SQLSMALLINT)COLNAMESIZE,
607  &colNameLen,
608  &colType,
609  &colSize,
610  &colScale,
611  &nullable);
612 
613  if (r != SQL_SUCCESS) {
614  qSqlWarning(QString::fromLatin1("qMakeField: Unable to describe column %1").arg(i), p);
615  return QSqlField();
616  }
617 
618  SQLLEN unsignedFlag = SQL_FALSE;
619  r = SQLColAttribute (p->hStmt,
620  i + 1,
621  SQL_DESC_UNSIGNED,
622  0,
623  0,
624  0,
625  &unsignedFlag);
626  if (r != SQL_SUCCESS) {
627  qSqlWarning(QString::fromLatin1("qMakeField: Unable to get column attributes for column %1").arg(i), p);
628  }
629 
630 #ifdef UNICODE
631  QString qColName(fromSQLTCHAR(colName, colNameLen));
632 #else
633  QString qColName = QString::fromUtf8((const char *)colName.constData());
634 #endif
635  // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
636  int required = -1;
637  if (nullable == SQL_NO_NULLS) {
638  required = 1;
639  } else if (nullable == SQL_NULLABLE) {
640  required = 0;
641  }
642  QVariant::Type type = qDecodeODBCType(colType, p, unsignedFlag == SQL_FALSE);
643  QSqlField f(qColName, type);
644  f.setSqlType(colType);
645  f.setLength(colSize == 0 ? -1 : int(colSize));
646  f.setPrecision(colScale == 0 ? -1 : int(colScale));
647  if (nullable == SQL_NO_NULLS)
648  f.setRequired(true);
649  else if (nullable == SQL_NULLABLE)
650  f.setRequired(false);
651  // else we don't know
652  return f;
653 }
654 
655 static int qGetODBCVersion(const QString &connOpts)
656 {
657  if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"), Qt::CaseInsensitive))
658  return SQL_OV_ODBC3;
659  return SQL_OV_ODBC2;
660 }
661 
662 QChar QODBCDriverPrivate::quoteChar()
663 {
664  if (!isQuoteInitialized) {
665  SQLTCHAR driverResponse[4];
666  SQLSMALLINT length;
667  int r = SQLGetInfo(hDbc,
668  SQL_IDENTIFIER_QUOTE_CHAR,
669  &driverResponse,
670  sizeof(driverResponse),
671  &length);
672  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
673 #ifdef UNICODE
674  quote = QChar(driverResponse[0]);
675 #else
676  quote = QLatin1Char(driverResponse[0]);
677 #endif
678  else
679  quote = QLatin1Char('"');
680  isQuoteInitialized = true;
681  }
682  return quote;
683 }
684 
685 
686 bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
687 {
688  // Set any connection attributes
689  const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
690  SQLRETURN r = SQL_SUCCESS;
691  for (int i = 0; i < opts.count(); ++i) {
692  const QString tmp(opts.at(i));
693  int idx;
694  if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
695  qWarning() << "QODBCDriver::open: Illegal connect option value '" << tmp << '\'';
696  continue;
697  }
698  const QString opt(tmp.left(idx));
699  const QString val(tmp.mid(idx + 1).simplified());
700  SQLUINTEGER v = 0;
701 
702  r = SQL_SUCCESS;
703  if (opt.toUpper() == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
704  if (val.toUpper() == QLatin1String("SQL_MODE_READ_ONLY")) {
705  v = SQL_MODE_READ_ONLY;
706  } else if (val.toUpper() == QLatin1String("SQL_MODE_READ_WRITE")) {
707  v = SQL_MODE_READ_WRITE;
708  } else {
709  qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
710  continue;
711  }
712  r = SQLSetConnectAttr(hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) v, 0);
713  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_TIMEOUT")) {
714  v = val.toUInt();
715  r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) v, 0);
716  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
717  v = val.toUInt();
718  r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) v, 0);
719  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
720  val.utf16(); // 0 terminate
721  r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
722 #ifdef UNICODE
723  toSQLTCHAR(val).data(),
724 #else
725  (SQLCHAR*) val.toUtf8().data(),
726 #endif
727  val.length()*sizeof(SQLTCHAR));
728  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
729  if (val.toUpper() == QLatin1String("SQL_TRUE")) {
730  v = SQL_TRUE;
731  } else if (val.toUpper() == QLatin1String("SQL_FALSE")) {
732  v = SQL_FALSE;
733  } else {
734  qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
735  continue;
736  }
737  r = SQLSetConnectAttr(hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) v, 0);
738  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_PACKET_SIZE")) {
739  v = val.toUInt();
740  r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) v, 0);
741  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
742  val.utf16(); // 0 terminate
743  r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
744 #ifdef UNICODE
745  toSQLTCHAR(val).data(),
746 #else
747  (SQLCHAR*) val.toUtf8().data(),
748 #endif
749  val.length()*sizeof(SQLTCHAR));
750  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
751  if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
752  v = SQL_OPT_TRACE_OFF;
753  } else if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_ON")) {
754  v = SQL_OPT_TRACE_ON;
755  } else {
756  qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
757  continue;
758  }
759  r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACE, (SQLPOINTER) v, 0);
760  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_POOLING")) {
761  if (val == QLatin1String("SQL_CP_OFF"))
762  v = SQL_CP_OFF;
763  else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_DRIVER"))
764  v = SQL_CP_ONE_PER_DRIVER;
765  else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_HENV"))
766  v = SQL_CP_ONE_PER_HENV;
767  else if (val.toUpper() == QLatin1String("SQL_CP_DEFAULT"))
768  v = SQL_CP_DEFAULT;
769  else {
770  qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
771  continue;
772  }
773  r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)v, 0);
774  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CP_MATCH")) {
775  if (val.toUpper() == QLatin1String("SQL_CP_STRICT_MATCH"))
776  v = SQL_CP_STRICT_MATCH;
777  else if (val.toUpper() == QLatin1String("SQL_CP_RELAXED_MATCH"))
778  v = SQL_CP_RELAXED_MATCH;
779  else if (val.toUpper() == QLatin1String("SQL_CP_MATCH_DEFAULT"))
780  v = SQL_CP_MATCH_DEFAULT;
781  else {
782  qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
783  continue;
784  }
785  r = SQLSetConnectAttr(hDbc, SQL_ATTR_CP_MATCH, (SQLPOINTER)v, 0);
786  } else if (opt.toUpper() == QLatin1String("SQL_ATTR_ODBC_VERSION")) {
787  // Already handled in QODBCDriver::open()
788  continue;
789  } else {
790  qWarning() << "QODBCDriver::open: Unknown connection attribute '" << opt << '\'';
791  }
792  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
793  qSqlWarning(QString::fromLatin1("QODBCDriver::open: Unable to set connection attribute'%1'").arg(
794  opt), this);
795  }
796  return true;
797 }
798 
799 void QODBCDriverPrivate::splitTableQualifier(const QString & qualifier, QString &catalog,
800  QString &schema, QString &table)
801 {
802  if (!useSchema) {
803  table = qualifier;
804  return;
805  }
806  QStringList l = qualifier.split(QLatin1Char('.'));
807  if (l.count() > 3)
808  return; // can't possibly be a valid table qualifier
809  int i = 0, n = l.count();
810  if (n == 1) {
811  table = qualifier;
812  } else {
813  for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
814  if (n == 3) {
815  if (i == 0) {
816  catalog = *it;
817  } else if (i == 1) {
818  schema = *it;
819  } else if (i == 2) {
820  table = *it;
821  }
822  } else if (n == 2) {
823  if (i == 0) {
824  schema = *it;
825  } else if (i == 1) {
826  table = *it;
827  }
828  }
829  i++;
830  }
831  }
832 }
833 
834 QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
835 {
836  DefaultCase ret;
837  SQLUSMALLINT casing;
838  int r = SQLGetInfo(hDbc,
839  SQL_IDENTIFIER_CASE,
840  &casing,
841  sizeof(casing),
842  NULL);
843  if ( r != SQL_SUCCESS)
844  ret = Mixed;//arbitrary case if driver cannot be queried
845  else {
846  switch (casing) {
847  case (SQL_IC_UPPER):
848  ret = Upper;
849  break;
850  case (SQL_IC_LOWER):
851  ret = Lower;
852  break;
853  case (SQL_IC_SENSITIVE):
854  ret = Sensitive;
855  break;
856  case (SQL_IC_MIXED):
857  default:
858  ret = Mixed;
859  break;
860  }
861  }
862  return ret;
863 }
864 
865 /*
866  Adjust the casing of an identifier to match what the
867  database engine would have done to it.
868 */
869 QString QODBCDriverPrivate::adjustCase(const QString &identifier) const
870 {
871  QString ret = identifier;
872  switch(defaultCase()) {
873  case (Lower):
874  ret = identifier.toLower();
875  break;
876  case (Upper):
877  ret = identifier.toUpper();
878  break;
879  case(Mixed):
880  case(Sensitive):
881  default:
882  ret = identifier;
883  }
884  return ret;
885 }
886 
888 
890 : QSqlResult(db)
891 {
892  d = new QODBCPrivate(p);
893 }
894 
896 {
897  if (d->hStmt && d->isStmtHandleValid(driver()) && driver()->isOpen()) {
898  SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
899  if (r != SQL_SUCCESS)
900  qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
901  + QString::number(r), d);
902  }
903 
904  delete d;
905 }
906 
907 bool QODBCResult::reset (const QString& query)
908 {
909  setActive(false);
911  d->rInf.clear();
912  d->fieldCache.clear();
913  d->fieldCacheIdx = 0;
914 
915  // Always reallocate the statement handle - the statement attributes
916  // are not reset if SQLFreeStmt() is called which causes some problems.
917  SQLRETURN r;
918  if (d->hStmt && d->isStmtHandleValid(driver())) {
919  r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
920  if (r != SQL_SUCCESS) {
921  qSqlWarning(QLatin1String("QODBCResult::reset: Unable to free statement handle"), d);
922  return false;
923  }
924  }
925  r = SQLAllocHandle(SQL_HANDLE_STMT,
926  d->dpDbc(),
927  &d->hStmt);
928  if (r != SQL_SUCCESS) {
929  qSqlWarning(QLatin1String("QODBCResult::reset: Unable to allocate statement handle"), d);
930  return false;
931  }
932 
934 
935  if (d->userForwardOnly) {
936  r = SQLSetStmtAttr(d->hStmt,
937  SQL_ATTR_CURSOR_TYPE,
938  (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
939  SQL_IS_UINTEGER);
940  } else {
941  r = SQLSetStmtAttr(d->hStmt,
942  SQL_ATTR_CURSOR_TYPE,
943  (SQLPOINTER)SQL_CURSOR_STATIC,
944  SQL_IS_UINTEGER);
945  }
946  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
948  "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
949  "Please check your ODBC driver configuration"), QSqlError::StatementError, d));
950  return false;
951  }
952 
953 #ifdef UNICODE
954  r = SQLExecDirect(d->hStmt,
955  toSQLTCHAR(query).data(),
956  (SQLINTEGER) query.length());
957 #else
958  QByteArray query8 = query.toUtf8();
959  r = SQLExecDirect(d->hStmt,
960  (SQLCHAR*) query8.data(),
961  (SQLINTEGER) query8.length());
962 #endif
963  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
965  "Unable to execute statement"), QSqlError::StatementError, d));
966  return false;
967  }
968 
969  SQLULEN isScrollable = 0;
970  r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
971  if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
972  QSqlResult::setForwardOnly(isScrollable==SQL_NONSCROLLABLE);
973 
974  SQLSMALLINT count;
975  SQLNumResultCols(d->hStmt, &count);
976  if (count) {
977  setSelect(true);
978  for (int i = 0; i < count; ++i) {
979  d->rInf.append(qMakeFieldInfo(d, i));
980  }
981  d->fieldCache.resize(count);
982  } else {
983  setSelect(false);
984  }
985  setActive(true);
986 
987  return true;
988 }
989 
991 {
992  if (!driver()->isOpen())
993  return false;
994 
995  if (isForwardOnly() && i < at())
996  return false;
997  if (i == at())
998  return true;
999  d->clearValues();
1000  int actualIdx = i + 1;
1001  if (actualIdx <= 0) {
1003  return false;
1004  }
1005  SQLRETURN r;
1006  if (isForwardOnly()) {
1007  bool ok = true;
1008  while (ok && i > at())
1009  ok = fetchNext();
1010  return ok;
1011  } else {
1012  r = SQLFetchScroll(d->hStmt,
1013  SQL_FETCH_ABSOLUTE,
1014  actualIdx);
1015  }
1016  if (r != SQL_SUCCESS) {
1017  if (r != SQL_NO_DATA)
1019  "Unable to fetch"), QSqlError::ConnectionError, d));
1020  return false;
1021  }
1022  setAt(i);
1023  return true;
1024 }
1025 
1027 {
1028  SQLRETURN r;
1029  d->clearValues();
1030 
1031  if (d->hasSQLFetchScroll)
1032  r = SQLFetchScroll(d->hStmt,
1033  SQL_FETCH_NEXT,
1034  0);
1035  else
1036  r = SQLFetch(d->hStmt);
1037 
1038  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
1039  if (r != SQL_NO_DATA)
1041  "Unable to fetch next"), QSqlError::ConnectionError, d));
1042  return false;
1043  }
1044  setAt(at() + 1);
1045  return true;
1046 }
1047 
1049 {
1050  if (isForwardOnly() && at() != QSql::BeforeFirstRow)
1051  return false;
1052  SQLRETURN r;
1053  d->clearValues();
1054  if (isForwardOnly()) {
1055  return fetchNext();
1056  }
1057  r = SQLFetchScroll(d->hStmt,
1058  SQL_FETCH_FIRST,
1059  0);
1060  if (r != SQL_SUCCESS) {
1061  if (r != SQL_NO_DATA)
1063  "Unable to fetch first"), QSqlError::ConnectionError, d));
1064  return false;
1065  }
1066  setAt(0);
1067  return true;
1068 }
1069 
1071 {
1072  if (isForwardOnly())
1073  return false;
1074  SQLRETURN r;
1075  d->clearValues();
1076  r = SQLFetchScroll(d->hStmt,
1077  SQL_FETCH_PRIOR,
1078  0);
1079  if (r != SQL_SUCCESS) {
1080  if (r != SQL_NO_DATA)
1082  "Unable to fetch previous"), QSqlError::ConnectionError, d));
1083  return false;
1084  }
1085  setAt(at() - 1);
1086  return true;
1087 }
1088 
1090 {
1091  SQLRETURN r;
1092  d->clearValues();
1093 
1094  if (isForwardOnly()) {
1095  // cannot seek to last row in forwardOnly mode, so we have to use brute force
1096  int i = at();
1097  if (i == QSql::AfterLastRow)
1098  return false;
1099  if (i == QSql::BeforeFirstRow)
1100  i = 0;
1101  while (fetchNext())
1102  ++i;
1103  setAt(i);
1104  return true;
1105  }
1106 
1107  r = SQLFetchScroll(d->hStmt,
1108  SQL_FETCH_LAST,
1109  0);
1110  if (r != SQL_SUCCESS) {
1111  if (r != SQL_NO_DATA)
1113  "Unable to fetch last"), QSqlError::ConnectionError, d));
1114  return false;
1115  }
1116  SQLULEN currRow = 0;
1117  r = SQLGetStmtAttr(d->hStmt,
1118  SQL_ROW_NUMBER,
1119  &currRow,
1120  SQL_IS_INTEGER,
1121  0);
1122  if (r != SQL_SUCCESS)
1123  return false;
1124  setAt(currRow-1);
1125  return true;
1126 }
1127 
1129 {
1130  if (field >= d->rInf.count() || field < 0) {
1131  qWarning() << "QODBCResult::data: column" << field << "out of range";
1132  return QVariant();
1133  }
1134  if (field < d->fieldCacheIdx)
1135  return d->fieldCache.at(field);
1136 
1137  SQLRETURN r(0);
1138  SQLLEN lengthIndicator = 0;
1139 
1140  for (int i = d->fieldCacheIdx; i <= field; ++i) {
1141  // some servers do not support fetching column n after we already
1142  // fetched column n+1, so cache all previous columns here
1143  const QSqlField info = d->rInf.field(i);
1144  switch (info.type()) {
1145  case QVariant::LongLong:
1146  d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
1147  break;
1148  case QVariant::ULongLong:
1149  d->fieldCache[i] = qGetBigIntData(d->hStmt, i, false);
1150  break;
1151  case QVariant::Int:
1152  d->fieldCache[i] = qGetIntData(d->hStmt, i);
1153  break;
1154  case QVariant::UInt:
1155  d->fieldCache[i] = qGetIntData(d->hStmt, i, false);
1156  break;
1157  case QVariant::Date:
1158  DATE_STRUCT dbuf;
1159  r = SQLGetData(d->hStmt,
1160  i + 1,
1161  SQL_C_DATE,
1162  (SQLPOINTER)&dbuf,
1163  0,
1164  &lengthIndicator);
1165  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
1166  d->fieldCache[i] = QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
1167  else
1169  break;
1170  case QVariant::Time:
1171  TIME_STRUCT tbuf;
1172  r = SQLGetData(d->hStmt,
1173  i + 1,
1174  SQL_C_TIME,
1175  (SQLPOINTER)&tbuf,
1176  0,
1177  &lengthIndicator);
1178  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
1179  d->fieldCache[i] = QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
1180  else
1182  break;
1183  case QVariant::DateTime:
1184  TIMESTAMP_STRUCT dtbuf;
1185  r = SQLGetData(d->hStmt,
1186  i + 1,
1187  SQL_C_TIMESTAMP,
1188  (SQLPOINTER)&dtbuf,
1189  0,
1190  &lengthIndicator);
1191  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
1192  d->fieldCache[i] = QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
1193  QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
1194  else
1196  break;
1197  case QVariant::ByteArray:
1198  d->fieldCache[i] = qGetBinaryData(d->hStmt, i);
1199  break;
1200  case QVariant::String:
1201  d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), d->unicode);
1202  break;
1203  case QVariant::Double:
1204  switch(numericalPrecisionPolicy()) {
1206  d->fieldCache[i] = qGetIntData(d->hStmt, i);
1207  break;
1209  d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
1210  break;
1212  d->fieldCache[i] = qGetDoubleData(d->hStmt, i);
1213  break;
1214  case QSql::HighPrecision:
1215  d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), false);
1216  break;
1217  }
1218  break;
1219  default:
1220  d->fieldCache[i] = QVariant(qGetStringData(d->hStmt, i, info.length(), false));
1221  break;
1222  }
1223  d->fieldCacheIdx = field + 1;
1224  }
1225  return d->fieldCache[field];
1226 }
1227 
1228 bool QODBCResult::isNull(int field)
1229 {
1230  if (field < 0 || field > d->fieldCache.size())
1231  return true;
1232  if (field <= d->fieldCacheIdx) {
1233  // since there is no good way to find out whether the value is NULL
1234  // without fetching the field we'll fetch it here.
1235  // (data() also sets the NULL flag)
1236  data(field);
1237  }
1238  return d->fieldCache.at(field).isNull();
1239 }
1240 
1242 {
1243  return -1;
1244 }
1245 
1247 {
1248  SQLLEN affectedRowCount = 0;
1249  SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
1250  if (r == SQL_SUCCESS)
1251  return affectedRowCount;
1252  else
1253  qSqlWarning(QLatin1String("QODBCResult::numRowsAffected: Unable to count affected rows"), d);
1254  return -1;
1255 }
1256 
1257 bool QODBCResult::prepare(const QString& query)
1258 {
1259  setActive(false);
1261  SQLRETURN r;
1262 
1263  d->rInf.clear();
1264  if (d->hStmt && d->isStmtHandleValid(driver())) {
1265  r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
1266  if (r != SQL_SUCCESS) {
1267  qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to close statement"), d);
1268  return false;
1269  }
1270  }
1271  r = SQLAllocHandle(SQL_HANDLE_STMT,
1272  d->dpDbc(),
1273  &d->hStmt);
1274  if (r != SQL_SUCCESS) {
1275  qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to allocate statement handle"), d);
1276  return false;
1277  }
1278 
1280 
1281  if (d->userForwardOnly) {
1282  r = SQLSetStmtAttr(d->hStmt,
1283  SQL_ATTR_CURSOR_TYPE,
1284  (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
1285  SQL_IS_UINTEGER);
1286  } else {
1287  r = SQLSetStmtAttr(d->hStmt,
1288  SQL_ATTR_CURSOR_TYPE,
1289  (SQLPOINTER)SQL_CURSOR_STATIC,
1290  SQL_IS_UINTEGER);
1291  }
1292  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
1294  "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
1295  "Please check your ODBC driver configuration"), QSqlError::StatementError, d));
1296  return false;
1297  }
1298 
1299 #ifdef UNICODE
1300  r = SQLPrepare(d->hStmt,
1301  toSQLTCHAR(query).data(),
1302  (SQLINTEGER) query.length());
1303 #else
1304  QByteArray query8 = query.toUtf8();
1305  r = SQLPrepare(d->hStmt,
1306  (SQLCHAR*) query8.data(),
1307  (SQLINTEGER) query8.length());
1308 #endif
1309 
1310  if (r != SQL_SUCCESS) {
1312  "Unable to prepare statement"), QSqlError::StatementError, d));
1313  return false;
1314  }
1315  return true;
1316 }
1317 
1319 {
1320  setActive(false);
1322  d->rInf.clear();
1323  d->fieldCache.clear();
1324  d->fieldCacheIdx = 0;
1325 
1326  if (!d->hStmt) {
1327  qSqlWarning(QLatin1String("QODBCResult::exec: No statement handle available"), d);
1328  return false;
1329  }
1330 
1331  if (isSelect())
1332  SQLCloseCursor(d->hStmt);
1333 
1335  QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
1336  QVarLengthArray<SQLLEN, 32> indicators(values.count());
1337  memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
1338 
1339  // bind parameters - only positional binding allowed
1340  int i;
1341  SQLRETURN r;
1342  for (i = 0; i < values.count(); ++i) {
1343  if (bindValueType(i) & QSql::Out)
1344  values[i].detach();
1345  const QVariant &val = values.at(i);
1346  SQLLEN *ind = &indicators[i];
1347  if (val.isNull())
1348  *ind = SQL_NULL_DATA;
1349  switch (val.type()) {
1350  case QVariant::Date: {
1351  QByteArray &ba = tmpStorage[i];
1352  ba.resize(sizeof(DATE_STRUCT));
1353  DATE_STRUCT *dt = (DATE_STRUCT *)ba.constData();
1354  QDate qdt = val.toDate();
1355  dt->year = qdt.year();
1356  dt->month = qdt.month();
1357  dt->day = qdt.day();
1358  r = SQLBindParameter(d->hStmt,
1359  i + 1,
1361  SQL_C_DATE,
1362  SQL_DATE,
1363  0,
1364  0,
1365  (void *) dt,
1366  0,
1367  *ind == SQL_NULL_DATA ? ind : NULL);
1368  break; }
1369  case QVariant::Time: {
1370  QByteArray &ba = tmpStorage[i];
1371  ba.resize(sizeof(TIME_STRUCT));
1372  TIME_STRUCT *dt = (TIME_STRUCT *)ba.constData();
1373  QTime qdt = val.toTime();
1374  dt->hour = qdt.hour();
1375  dt->minute = qdt.minute();
1376  dt->second = qdt.second();
1377  r = SQLBindParameter(d->hStmt,
1378  i + 1,
1380  SQL_C_TIME,
1381  SQL_TIME,
1382  0,
1383  0,
1384  (void *) dt,
1385  0,
1386  *ind == SQL_NULL_DATA ? ind : NULL);
1387  break; }
1388  case QVariant::DateTime: {
1389  QByteArray &ba = tmpStorage[i];
1390  ba.resize(sizeof(TIMESTAMP_STRUCT));
1391  TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)ba.constData();
1392  QDateTime qdt = val.toDateTime();
1393  dt->year = qdt.date().year();
1394  dt->month = qdt.date().month();
1395  dt->day = qdt.date().day();
1396  dt->hour = qdt.time().hour();
1397  dt->minute = qdt.time().minute();
1398  dt->second = qdt.time().second();
1399 
1400  int precision = d->driverPrivate->datetime_precision - 20; // (20 includes a separating period)
1401  if (precision <= 0) {
1402  dt->fraction = 0;
1403  } else {
1404  dt->fraction = qdt.time().msec() * 1000000;
1405 
1406  // (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000)
1407  int keep = (int)qPow(10.0, 9 - qMin(9, precision));
1408  dt->fraction = (dt->fraction / keep) * keep;
1409  }
1410 
1411  r = SQLBindParameter(d->hStmt,
1412  i + 1,
1414  SQL_C_TIMESTAMP,
1415  SQL_TIMESTAMP,
1416  d->driverPrivate->datetime_precision,
1417  precision,
1418  (void *) dt,
1419  0,
1420  *ind == SQL_NULL_DATA ? ind : NULL);
1421  break; }
1422  case QVariant::Int:
1423  r = SQLBindParameter(d->hStmt,
1424  i + 1,
1426  SQL_C_SLONG,
1427  SQL_INTEGER,
1428  0,
1429  0,
1430  (void *) val.constData(),
1431  0,
1432  *ind == SQL_NULL_DATA ? ind : NULL);
1433  break;
1434  case QVariant::UInt:
1435  r = SQLBindParameter(d->hStmt,
1436  i + 1,
1437  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1438  SQL_C_ULONG,
1439  SQL_NUMERIC,
1440  15,
1441  0,
1442  (void *) val.constData(),
1443  0,
1444  *ind == SQL_NULL_DATA ? ind : NULL);
1445  break;
1446  case QVariant::Double:
1447  r = SQLBindParameter(d->hStmt,
1448  i + 1,
1449  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1450  SQL_C_DOUBLE,
1451  SQL_DOUBLE,
1452  0,
1453  0,
1454  (void *) val.constData(),
1455  0,
1456  *ind == SQL_NULL_DATA ? ind : NULL);
1457  break;
1458  case QVariant::LongLong:
1459  r = SQLBindParameter(d->hStmt,
1460  i + 1,
1461  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1462  SQL_C_SBIGINT,
1463  SQL_BIGINT,
1464  0,
1465  0,
1466  (void *) val.constData(),
1467  0,
1468  *ind == SQL_NULL_DATA ? ind : NULL);
1469  break;
1470  case QVariant::ULongLong:
1471  r = SQLBindParameter(d->hStmt,
1472  i + 1,
1473  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1474  SQL_C_UBIGINT,
1475  SQL_BIGINT,
1476  0,
1477  0,
1478  (void *) val.constData(),
1479  0,
1480  *ind == SQL_NULL_DATA ? ind : NULL);
1481  break;
1482  case QVariant::ByteArray:
1483  if (*ind != SQL_NULL_DATA) {
1484  *ind = val.toByteArray().size();
1485  }
1486  r = SQLBindParameter(d->hStmt,
1487  i + 1,
1488  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1489  SQL_C_BINARY,
1490  SQL_LONGVARBINARY,
1491  val.toByteArray().size(),
1492  0,
1493  (void *) val.toByteArray().constData(),
1494  val.toByteArray().size(),
1495  ind);
1496  break;
1497  case QVariant::Bool:
1498  r = SQLBindParameter(d->hStmt,
1499  i + 1,
1500  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1501  SQL_C_BIT,
1502  SQL_BIT,
1503  0,
1504  0,
1505  (void *) val.constData(),
1506  0,
1507  *ind == SQL_NULL_DATA ? ind : NULL);
1508  break;
1509  case QVariant::String:
1510  if (d->unicode) {
1511  QByteArray &ba = tmpStorage[i];
1512  QString str = val.toString();
1513  if (*ind != SQL_NULL_DATA)
1514  *ind = str.length() * sizeof(SQLTCHAR);
1515  int strSize = str.length() * sizeof(SQLTCHAR);
1516 
1517  if (bindValueType(i) & QSql::Out) {
1519  a.reserve(str.capacity());
1520  r = SQLBindParameter(d->hStmt,
1521  i + 1,
1522  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1523  SQL_C_TCHAR,
1524  strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
1525  0, // god knows... don't change this!
1526  0,
1527  (void *)a.constData(),
1528  a.size(),
1529  ind);
1530  break;
1531  }
1532  ba = QByteArray((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
1533  r = SQLBindParameter(d->hStmt,
1534  i + 1,
1535  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1536  SQL_C_TCHAR,
1537  strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
1538  strSize,
1539  0,
1540  (SQLPOINTER)ba.constData(),
1541  ba.size(),
1542  ind);
1543  break;
1544  }
1545  else
1546  {
1547  QByteArray &str = tmpStorage[i];
1548  str = val.toString().toUtf8();
1549  if (*ind != SQL_NULL_DATA)
1550  *ind = str.length();
1551  int strSize = str.length();
1552 
1553  r = SQLBindParameter(d->hStmt,
1554  i + 1,
1555  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1556  SQL_C_CHAR,
1557  strSize > 254 ? SQL_LONGVARCHAR : SQL_VARCHAR,
1558  strSize,
1559  0,
1560  (void *)str.constData(),
1561  strSize,
1562  ind);
1563  break;
1564  }
1565  // fall through
1566  default: {
1567  QByteArray &ba = tmpStorage[i];
1568  if (*ind != SQL_NULL_DATA)
1569  *ind = ba.size();
1570  r = SQLBindParameter(d->hStmt,
1571  i + 1,
1572  qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
1573  SQL_C_BINARY,
1574  SQL_VARBINARY,
1575  ba.length() + 1,
1576  0,
1577  (void *) ba.constData(),
1578  ba.length() + 1,
1579  ind);
1580  break; }
1581  }
1582  if (r != SQL_SUCCESS) {
1583  qWarning() << "QODBCResult::exec: unable to bind variable:" << qODBCWarn(d);
1585  "Unable to bind variable"), QSqlError::StatementError, d));
1586  return false;
1587  }
1588  }
1589  r = SQLExecute(d->hStmt);
1590  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
1591  qWarning() << "QODBCResult::exec: Unable to execute statement:" << qODBCWarn(d);
1593  "Unable to execute statement"), QSqlError::StatementError, d));
1594  return false;
1595  }
1596 
1597  SQLULEN isScrollable = 0;
1598  r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
1599  if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
1600  QSqlResult::setForwardOnly(isScrollable==SQL_NONSCROLLABLE);
1601 
1602  SQLSMALLINT count;
1603  SQLNumResultCols(d->hStmt, &count);
1604  if (count) {
1605  setSelect(true);
1606  for (int i = 0; i < count; ++i) {
1607  d->rInf.append(qMakeFieldInfo(d, i));
1608  }
1609  d->fieldCache.resize(count);
1610  } else {
1611  setSelect(false);
1612  }
1613  setActive(true);
1614 
1615 
1616  //get out parameters
1617  if (!hasOutValues())
1618  return true;
1619 
1620  for (i = 0; i < values.count(); ++i) {
1621  switch (values.at(i).type()) {
1622  case QVariant::Date: {
1623  DATE_STRUCT ds = *((DATE_STRUCT *)tmpStorage.at(i).constData());
1624  values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
1625  break; }
1626  case QVariant::Time: {
1627  TIME_STRUCT dt = *((TIME_STRUCT *)tmpStorage.at(i).constData());
1628  values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
1629  break; }
1630  case QVariant::DateTime: {
1631  TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT*)
1632  tmpStorage.at(i).constData());
1633  values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
1634  QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
1635  break; }
1636  case QVariant::Bool:
1637  case QVariant::Int:
1638  case QVariant::UInt:
1639  case QVariant::Double:
1640  case QVariant::ByteArray:
1641  case QVariant::LongLong:
1642  case QVariant::ULongLong:
1643  //nothing to do
1644  break;
1645  case QVariant::String:
1646  if (d->unicode) {
1647  if (bindValueType(i) & QSql::Out) {
1648  const QByteArray &first = tmpStorage.at(i);
1650  array.append((SQLTCHAR *)first.constData(), first.size());
1651  values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR*));
1652  }
1653  break;
1654  }
1655  // fall through
1656  default: {
1657  if (bindValueType(i) & QSql::Out)
1658  values[i] = tmpStorage.at(i);
1659  break; }
1660  }
1661  if (indicators[i] == SQL_NULL_DATA)
1662  values[i] = QVariant(values[i].type());
1663  }
1664  return true;
1665 }
1666 
1668 {
1669  if (!isActive() || !isSelect())
1670  return QSqlRecord();
1671  return d->rInf;
1672 }
1673 
1675 {
1676  return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
1677 }
1678 
1680 {
1681  setActive(false);
1683  d->rInf.clear();
1684  d->fieldCache.clear();
1685  d->fieldCacheIdx = 0;
1686  setSelect(false);
1687 
1688  SQLRETURN r = SQLMoreResults(d->hStmt);
1689  if (r != SQL_SUCCESS) {
1690  if (r == SQL_SUCCESS_WITH_INFO) {
1691  int nativeCode = -1;
1692  QString message = qODBCWarn(d, &nativeCode);
1693  qWarning() << "QODBCResult::nextResult():" << message;
1694  } else {
1695  if (r != SQL_NO_DATA)
1697  "Unable to fetch last"), QSqlError::ConnectionError, d));
1698  return false;
1699  }
1700  }
1701 
1702  SQLSMALLINT count;
1703  SQLNumResultCols(d->hStmt, &count);
1704  if (count) {
1705  setSelect(true);
1706  for (int i = 0; i < count; ++i) {
1707  d->rInf.append(qMakeFieldInfo(d, i));
1708  }
1709  d->fieldCache.resize(count);
1710  } else {
1711  setSelect(false);
1712  }
1713  setActive(true);
1714 
1715  return true;
1716 }
1717 
1718 void QODBCResult::virtual_hook(int id, void *data)
1719 {
1720  switch (id) {
1722  if (d->hStmt)
1723  SQLCloseCursor(d->hStmt);
1724  break;
1726  Q_ASSERT(data);
1727  *static_cast<bool*>(data) = nextResult();
1728  break;
1729  default:
1730  QSqlResult::virtual_hook(id, data);
1731  }
1732 }
1733 
1735 {
1736  d->userForwardOnly = forward;
1737  QSqlResult::setForwardOnly(forward);
1738 }
1739 
1741 
1742 
1744  : QSqlDriver(parent)
1745 {
1746  init();
1747 }
1748 
1749 QODBCDriver::QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent)
1750  : QSqlDriver(parent)
1751 {
1752  init();
1753  d->hEnv = env;
1754  d->hDbc = con;
1755  if (env && con) {
1756  setOpen(true);
1757  setOpenError(false);
1758  }
1759 }
1760 
1762 {
1763  d = new QODBCDriverPrivate();
1764 }
1765 
1767 {
1768  cleanup();
1769  delete d;
1770 }
1771 
1773 {
1774  switch (f) {
1775  case Transactions: {
1776  if (!d->hDbc)
1777  return false;
1778  SQLUSMALLINT txn;
1779  SQLSMALLINT t;
1780  int r = SQLGetInfo(d->hDbc,
1781  (SQLUSMALLINT)SQL_TXN_CAPABLE,
1782  &txn,
1783  sizeof(txn),
1784  &t);
1785  if (r != SQL_SUCCESS || txn == SQL_TC_NONE)
1786  return false;
1787  else
1788  return true;
1789  }
1790  case Unicode:
1791  return d->unicode;
1792  case PreparedQueries:
1794  case FinishQuery:
1795  case LowPrecisionNumbers:
1796  return true;
1797  case QuerySize:
1798  case NamedPlaceholders:
1799  case LastInsertId:
1800  case BatchOperations:
1801  case SimpleLocking:
1802  case EventNotifications:
1803  return false;
1804  case MultipleResultSets:
1805  return d->hasMultiResultSets;
1806  case BLOB: {
1807  if(d->isMySqlServer)
1808  return true;
1809  else
1810  return false;
1811  }
1812  }
1813  return false;
1814 }
1815 
1816 bool QODBCDriver::open(const QString & db,
1817  const QString & user,
1818  const QString & password,
1819  const QString &,
1820  int,
1821  const QString& connOpts)
1822 {
1823  if (isOpen())
1824  close();
1825  SQLRETURN r;
1826  r = SQLAllocHandle(SQL_HANDLE_ENV,
1827  SQL_NULL_HANDLE,
1828  &d->hEnv);
1829  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
1830  qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate environment"), d);
1831  setOpenError(true);
1832  return false;
1833  }
1834  r = SQLSetEnvAttr(d->hEnv,
1835  SQL_ATTR_ODBC_VERSION,
1836  (SQLPOINTER)qGetODBCVersion(connOpts),
1837  SQL_IS_UINTEGER);
1838  r = SQLAllocHandle(SQL_HANDLE_DBC,
1839  d->hEnv,
1840  &d->hDbc);
1841  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
1842  qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate connection"), d);
1843  setOpenError(true);
1844  return false;
1845  }
1846 
1847  if (!d->setConnectionOptions(connOpts))
1848  return false;
1849 
1850  // Create the connection string
1851  QString connQStr;
1852  // support the "DRIVER={SQL SERVER};SERVER=blah" syntax
1853  if (db.contains(QLatin1String(".dsn"), Qt::CaseInsensitive))
1854  connQStr = QLatin1String("FILEDSN=") + db;
1855  else if (db.contains(QLatin1String("DRIVER="), Qt::CaseInsensitive)
1856  || db.contains(QLatin1String("SERVER="), Qt::CaseInsensitive))
1857  connQStr = db;
1858  else
1859  connQStr = QLatin1String("DSN=") + db;
1860 
1861  if (!user.isEmpty())
1862  connQStr += QLatin1String(";UID=") + user;
1863  if (!password.isEmpty())
1864  connQStr += QLatin1String(";PWD=") + password;
1865 
1866  SQLSMALLINT cb;
1867  QVarLengthArray<SQLTCHAR> connOut(1024);
1868  memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
1869  r = SQLDriverConnect(d->hDbc,
1870  NULL,
1871 #ifdef UNICODE
1872  toSQLTCHAR(connQStr).data(),
1873 #else
1874  (SQLCHAR*)connQStr.toUtf8().data(),
1875 #endif
1876  (SQLSMALLINT)connQStr.length(),
1877  connOut.data(),
1878  1024,
1879  &cb,
1880  /*SQL_DRIVER_NOPROMPT*/0);
1881 
1882  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
1883  setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
1884  setOpenError(true);
1885  return false;
1886  }
1887 
1888  if (!d->checkDriver()) {
1889  setLastError(qMakeError(tr("Unable to connect - Driver doesn't support all "
1890  "functionality required"), QSqlError::ConnectionError, d));
1891  setOpenError(true);
1892  return false;
1893  }
1894 
1895  d->checkUnicode();
1896  d->checkSchemaUsage();
1897  d->checkSqlServer();
1898  d->checkHasSQLFetchScroll();
1899  d->checkHasMultiResults();
1900  d->checkDateTimePrecision();
1901  setOpen(true);
1902  setOpenError(false);
1903  if(d->isMSSqlServer) {
1904  QSqlQuery i(createResult());
1905  i.exec(QLatin1String("SET QUOTED_IDENTIFIER ON"));
1906  }
1907  return true;
1908 }
1909 
1911 {
1912  cleanup();
1913  setOpen(false);
1914  setOpenError(false);
1915 }
1916 
1918 {
1919  SQLRETURN r;
1920  if (!d)
1921  return;
1922 
1923  if(d->hDbc) {
1924  // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect
1925  if (isOpen()) {
1926  r = SQLDisconnect(d->hDbc);
1927  if (r != SQL_SUCCESS)
1928  qSqlWarning(QLatin1String("QODBCDriver::disconnect: Unable to disconnect datasource"), d);
1929  else
1930  d->disconnectCount++;
1931  }
1932 
1933  r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
1934  if (r != SQL_SUCCESS)
1935  qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free connection handle"), d);
1936  d->hDbc = 0;
1937  }
1938 
1939  if (d->hEnv) {
1940  r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
1941  if (r != SQL_SUCCESS)
1942  qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free environment handle"), d);
1943  d->hEnv = 0;
1944  }
1945 }
1946 
1947 // checks whether the server can return char, varchar and longvarchar
1948 // as two byte unicode characters
1949 void QODBCDriverPrivate::checkUnicode()
1950 {
1951  SQLRETURN r;
1952  SQLUINTEGER fFunc;
1953 
1954  unicode = false;
1955  r = SQLGetInfo(hDbc,
1956  SQL_CONVERT_CHAR,
1957  (SQLPOINTER)&fFunc,
1958  sizeof(fFunc),
1959  NULL);
1960  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
1961  unicode = true;
1962  return;
1963  }
1964 
1965  r = SQLGetInfo(hDbc,
1966  SQL_CONVERT_VARCHAR,
1967  (SQLPOINTER)&fFunc,
1968  sizeof(fFunc),
1969  NULL);
1970  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
1971  unicode = true;
1972  return;
1973  }
1974 
1975  r = SQLGetInfo(hDbc,
1976  SQL_CONVERT_LONGVARCHAR,
1977  (SQLPOINTER)&fFunc,
1978  sizeof(fFunc),
1979  NULL);
1980  if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
1981  unicode = true;
1982  return;
1983  }
1984  SQLHANDLE hStmt;
1985  r = SQLAllocHandle(SQL_HANDLE_STMT,
1986  hDbc,
1987  &hStmt);
1988 
1989  r = SQLExecDirect(hStmt, toSQLTCHAR(QLatin1String("select 'test'")).data(), SQL_NTS);
1990  if(r == SQL_SUCCESS) {
1991  r = SQLFetch(hStmt);
1992  if(r == SQL_SUCCESS) {
1993  QVarLengthArray<SQLWCHAR> buffer(10);
1994  r = SQLGetData(hStmt, 1, SQL_C_WCHAR, buffer.data(), buffer.size() * sizeof(SQLWCHAR), NULL);
1995  if(r == SQL_SUCCESS && fromSQLTCHAR(buffer) == QLatin1String("test")) {
1996  unicode = true;
1997  }
1998  }
1999  }
2000  r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
2001 }
2002 
2003 bool QODBCDriverPrivate::checkDriver() const
2004 {
2005 #ifdef ODBC_CHECK_DRIVER
2006  static const SQLUSMALLINT reqFunc[] = {
2007  SQL_API_SQLDESCRIBECOL, SQL_API_SQLGETDATA, SQL_API_SQLCOLUMNS,
2008  SQL_API_SQLGETSTMTATTR, SQL_API_SQLGETDIAGREC, SQL_API_SQLEXECDIRECT,
2009  SQL_API_SQLGETINFO, SQL_API_SQLTABLES, 0
2010  };
2011 
2012  // these functions are optional
2013  static const SQLUSMALLINT optFunc[] = {
2014  SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT, 0
2015  };
2016 
2017  SQLRETURN r;
2018  SQLUSMALLINT sup;
2019 
2020  int i;
2021  // check the required functions
2022  for (i = 0; reqFunc[i] != 0; ++i) {
2023 
2024  r = SQLGetFunctions(hDbc, reqFunc[i], &sup);
2025 
2026  if (r != SQL_SUCCESS) {
2027  qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
2028  return false;
2029  }
2030  if (sup == SQL_FALSE) {
2031  qWarning () << "QODBCDriver::open: Warning - Driver doesn't support all needed functionality (" << reqFunc[i] <<
2032  ").\nPlease look at the Qt SQL Module Driver documentation for more information.";
2033  return false;
2034  }
2035  }
2036 
2037  // these functions are optional and just generate a warning
2038  for (i = 0; optFunc[i] != 0; ++i) {
2039 
2040  r = SQLGetFunctions(hDbc, optFunc[i], &sup);
2041 
2042  if (r != SQL_SUCCESS) {
2043  qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
2044  return false;
2045  }
2046  if (sup == SQL_FALSE) {
2047  qWarning() << "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (" << optFunc[i] << ')';
2048  return true;
2049  }
2050  }
2051 #endif //ODBC_CHECK_DRIVER
2052 
2053  return true;
2054 }
2055 
2056 void QODBCDriverPrivate::checkSchemaUsage()
2057 {
2058  SQLRETURN r;
2059  SQLUINTEGER val;
2060 
2061  r = SQLGetInfo(hDbc,
2062  SQL_SCHEMA_USAGE,
2063  (SQLPOINTER) &val,
2064  sizeof(val),
2065  NULL);
2066  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
2067  useSchema = (val != 0);
2068 }
2069 
2070 void QODBCDriverPrivate::checkSqlServer()
2071 {
2072  SQLRETURN r;
2073  QVarLengthArray<SQLTCHAR> serverString(200);
2074  SQLSMALLINT t;
2075  memset(serverString.data(), 0, serverString.size() * sizeof(SQLTCHAR));
2076 
2077  r = SQLGetInfo(hDbc,
2078  SQL_DBMS_NAME,
2079  serverString.data(),
2080  serverString.size() * sizeof(SQLTCHAR),
2081  &t);
2082  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
2083  QString serverType;
2084 #ifdef UNICODE
2085  serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR));
2086 #else
2087  serverType = QString::fromUtf8((const char *)serverString.constData(), t);
2088 #endif
2089  isMySqlServer = serverType.contains(QLatin1String("mysql"), Qt::CaseInsensitive);
2090  isMSSqlServer = serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive);
2091  }
2092  r = SQLGetInfo(hDbc,
2093  SQL_DRIVER_NAME,
2094  serverString.data(),
2095  serverString.size() * sizeof(SQLTCHAR),
2096  &t);
2097  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
2098  QString serverType;
2099 #ifdef UNICODE
2100  serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR));
2101 #else
2102  serverType = QString::fromUtf8((const char *)serverString.constData(), t);
2103 #endif
2104  isFreeTDSDriver = serverType.contains(QLatin1String("tdsodbc"), Qt::CaseInsensitive);
2105  unicode = unicode && !isFreeTDSDriver;
2106  }
2107 }
2108 
2109 void QODBCDriverPrivate::checkHasSQLFetchScroll()
2110 {
2111  SQLUSMALLINT sup;
2112  SQLRETURN r = SQLGetFunctions(hDbc, SQL_API_SQLFETCHSCROLL, &sup);
2113  if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || sup != SQL_TRUE) {
2114  hasSQLFetchScroll = false;
2115  qWarning() << "QODBCDriver::checkHasSQLFetchScroll: Warning - Driver doesn't support scrollable result sets, use forward only mode for queries";
2116  }
2117 }
2118 
2119 void QODBCDriverPrivate::checkHasMultiResults()
2120 {
2121  QVarLengthArray<SQLTCHAR> driverResponse(2);
2122  SQLSMALLINT length;
2123  SQLRETURN r = SQLGetInfo(hDbc,
2124  SQL_MULT_RESULT_SETS,
2125  driverResponse.data(),
2126  driverResponse.size() * sizeof(SQLTCHAR),
2127  &length);
2128  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
2129 #ifdef UNICODE
2130  hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y'));
2131 #else
2132  hasMultiResultSets = QString::fromUtf8((const char *)driverResponse.constData(), length).startsWith(QLatin1Char('Y'));
2133 #endif
2134 }
2135 
2136 void QODBCDriverPrivate::checkDateTimePrecision()
2137 {
2138  SQLINTEGER columnSize;
2139  SQLHANDLE hStmt;
2140 
2141  SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);
2142  if (r != SQL_SUCCESS) {
2143  return;
2144  }
2145 
2146  r = SQLGetTypeInfo(hStmt, SQL_TIMESTAMP);
2147  if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
2148  r = SQLFetch(hStmt);
2149  if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO )
2150  {
2151  if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) {
2152  datetime_precision = (int)columnSize;
2153  }
2154  }
2155  }
2156  SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
2157 }
2158 
2160 {
2161  return new QODBCResult(this, d);
2162 }
2163 
2165 {
2166  if (!isOpen()) {
2167  qWarning() << "QODBCDriver::beginTransaction: Database not open";
2168  return false;
2169  }
2170  SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF);
2171  SQLRETURN r = SQLSetConnectAttr(d->hDbc,
2172  SQL_ATTR_AUTOCOMMIT,
2173  (SQLPOINTER)ac,
2174  sizeof(ac));
2175  if (r != SQL_SUCCESS) {
2176  setLastError(qMakeError(tr("Unable to disable autocommit"),
2178  return false;
2179  }
2180  return true;
2181 }
2182 
2184 {
2185  if (!isOpen()) {
2186  qWarning() << "QODBCDriver::commitTransaction: Database not open";
2187  return false;
2188  }
2189  SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
2190  d->hDbc,
2191  SQL_COMMIT);
2192  if (r != SQL_SUCCESS) {
2193  setLastError(qMakeError(tr("Unable to commit transaction"),
2195  return false;
2196  }
2197  return endTrans();
2198 }
2199 
2201 {
2202  if (!isOpen()) {
2203  qWarning() << "QODBCDriver::rollbackTransaction: Database not open";
2204  return false;
2205  }
2206  SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
2207  d->hDbc,
2208  SQL_ROLLBACK);
2209  if (r != SQL_SUCCESS) {
2210  setLastError(qMakeError(tr("Unable to rollback transaction"),
2212  return false;
2213  }
2214  return endTrans();
2215 }
2216 
2218 {
2219  SQLUINTEGER ac(SQL_AUTOCOMMIT_ON);
2220  SQLRETURN r = SQLSetConnectAttr(d->hDbc,
2221  SQL_ATTR_AUTOCOMMIT,
2222  (SQLPOINTER)ac,
2223  sizeof(ac));
2224  if (r != SQL_SUCCESS) {
2225  setLastError(qMakeError(tr("Unable to enable autocommit"), QSqlError::TransactionError, d));
2226  return false;
2227  }
2228  return true;
2229 }
2230 
2232 {
2233  QStringList tl;
2234  if (!isOpen())
2235  return tl;
2236  SQLHANDLE hStmt;
2237 
2238  SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
2239  d->hDbc,
2240  &hStmt);
2241  if (r != SQL_SUCCESS) {
2242  qSqlWarning(QLatin1String("QODBCDriver::tables: Unable to allocate handle"), d);
2243  return tl;
2244  }
2245  r = SQLSetStmtAttr(hStmt,
2246  SQL_ATTR_CURSOR_TYPE,
2247  (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
2248  SQL_IS_UINTEGER);
2249  QStringList tableType;
2250  if (type & QSql::Tables)
2251  tableType += QLatin1String("TABLE");
2252  if (type & QSql::Views)
2253  tableType += QLatin1String("VIEW");
2254  if (type & QSql::SystemTables)
2255  tableType += QLatin1String("SYSTEM TABLE");
2256  if (tableType.isEmpty())
2257  return tl;
2258 
2259  QString joinedTableTypeString = tableType.join(QLatin1String(","));
2260 
2261  r = SQLTables(hStmt,
2262  NULL,
2263  0,
2264  NULL,
2265  0,
2266  NULL,
2267  0,
2268 #ifdef UNICODE
2269  toSQLTCHAR(joinedTableTypeString).data(),
2270 #else
2271  (SQLCHAR*)joinedTableTypeString.toUtf8().data(),
2272 #endif
2273  joinedTableTypeString.length() /* characters, not bytes */);
2274 
2275  if (r != SQL_SUCCESS)
2276  qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
2277 
2278  if (d->hasSQLFetchScroll)
2279  r = SQLFetchScroll(hStmt,
2280  SQL_FETCH_NEXT,
2281  0);
2282  else
2283  r = SQLFetch(hStmt);
2284 
2285  if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
2286  qWarning() << "QODBCDriver::tables failed to retrieve table/view list: (" << r << "," << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ")";
2287  return QStringList();
2288  }
2289 
2290  while (r == SQL_SUCCESS) {
2291  QString fieldVal = qGetStringData(hStmt, 2, -1, false);
2292  tl.append(fieldVal);
2293 
2294  if (d->hasSQLFetchScroll)
2295  r = SQLFetchScroll(hStmt,
2296  SQL_FETCH_NEXT,
2297  0);
2298  else
2299  r = SQLFetch(hStmt);
2300  }
2301 
2302  r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
2303  if (r!= SQL_SUCCESS)
2304  qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
2305  return tl;
2306 }
2307 
2309 {
2310  QSqlIndex index(tablename);
2311  if (!isOpen())
2312  return index;
2313  bool usingSpecialColumns = false;
2314  QSqlRecord rec = record(tablename);
2315 
2316  SQLHANDLE hStmt;
2317  SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
2318  d->hDbc,
2319  &hStmt);
2320  if (r != SQL_SUCCESS) {
2321  qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to list primary key"), d);
2322  return index;
2323  }
2324  QString catalog, schema, table;
2325  d->splitTableQualifier(tablename, catalog, schema, table);
2326 
2328  catalog = stripDelimiters(catalog, QSqlDriver::TableName);
2329  else
2330  catalog = d->adjustCase(catalog);
2331 
2333  schema = stripDelimiters(schema, QSqlDriver::TableName);
2334  else
2335  schema = d->adjustCase(schema);
2336 
2338  table = stripDelimiters(table, QSqlDriver::TableName);
2339  else
2340  table = d->adjustCase(table);
2341 
2342  r = SQLSetStmtAttr(hStmt,
2343  SQL_ATTR_CURSOR_TYPE,
2344  (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
2345  SQL_IS_UINTEGER);
2346  r = SQLPrimaryKeys(hStmt,
2347 #ifdef UNICODE
2348  catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
2349 #else
2350  catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
2351 #endif
2352  catalog.length(),
2353 #ifdef UNICODE
2354  schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
2355 #else
2356  schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
2357 #endif
2358  schema.length(),
2359 #ifdef UNICODE
2360  toSQLTCHAR(table).data(),
2361 #else
2362  (SQLCHAR*)table.toUtf8().data(),
2363 #endif
2364  table.length() /* in characters, not in bytes */);
2365 
2366  // if the SQLPrimaryKeys() call does not succeed (e.g the driver
2367  // does not support it) - try an alternative method to get hold of
2368  // the primary index (e.g MS Access and FoxPro)
2369  if (r != SQL_SUCCESS) {
2370  r = SQLSpecialColumns(hStmt,
2371  SQL_BEST_ROWID,
2372 #ifdef UNICODE
2373  catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
2374 #else
2375  catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
2376 #endif
2377  catalog.length(),
2378 #ifdef UNICODE
2379  schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
2380 #else
2381  schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
2382 #endif
2383  schema.length(),
2384 #ifdef UNICODE
2385  toSQLTCHAR(table).data(),
2386 #else
2387  (SQLCHAR*)table.toUtf8().data(),
2388 #endif
2389  table.length(),
2390  SQL_SCOPE_CURROW,
2391  SQL_NULLABLE);
2392 
2393  if (r != SQL_SUCCESS) {
2394  qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
2395  } else {
2396  usingSpecialColumns = true;
2397  }
2398  }
2399 
2400  if (d->hasSQLFetchScroll)
2401  r = SQLFetchScroll(hStmt,
2402  SQL_FETCH_NEXT,
2403  0);
2404  else
2405  r = SQLFetch(hStmt);
2406 
2407  int fakeId = 0;
2408  QString cName, idxName;
2409  // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
2410  while (r == SQL_SUCCESS) {
2411  if (usingSpecialColumns) {
2412  cName = qGetStringData(hStmt, 1, -1, d->unicode); // column name
2413  idxName = QString::number(fakeId++); // invent a fake index name
2414  } else {
2415  cName = qGetStringData(hStmt, 3, -1, d->unicode); // column name
2416  idxName = qGetStringData(hStmt, 5, -1, d->unicode); // pk index name
2417  }
2418  index.append(rec.field(cName));
2419  index.setName(idxName);
2420 
2421  if (d->hasSQLFetchScroll)
2422  r = SQLFetchScroll(hStmt,
2423  SQL_FETCH_NEXT,
2424  0);
2425  else
2426  r = SQLFetch(hStmt);
2427 
2428  }
2429  r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
2430  if (r!= SQL_SUCCESS)
2431  qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
2432  return index;
2433 }
2434 
2435 QSqlRecord QODBCDriver::record(const QString& tablename) const
2436 {
2437  QSqlRecord fil;
2438  if (!isOpen())
2439  return fil;
2440 
2441  SQLHANDLE hStmt;
2442  QString catalog, schema, table;
2443  d->splitTableQualifier(tablename, catalog, schema, table);
2444 
2446  catalog = stripDelimiters(catalog, QSqlDriver::TableName);
2447  else
2448  catalog = d->adjustCase(catalog);
2449 
2451  schema = stripDelimiters(schema, QSqlDriver::TableName);
2452  else
2453  schema = d->adjustCase(schema);
2454 
2456  table = stripDelimiters(table, QSqlDriver::TableName);
2457  else
2458  table = d->adjustCase(table);
2459 
2460  SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
2461  d->hDbc,
2462  &hStmt);
2463  if (r != SQL_SUCCESS) {
2464  qSqlWarning(QLatin1String("QODBCDriver::record: Unable to allocate handle"), d);
2465  return fil;
2466  }
2467  r = SQLSetStmtAttr(hStmt,
2468  SQL_ATTR_CURSOR_TYPE,
2469  (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
2470  SQL_IS_UINTEGER);
2471  r = SQLColumns(hStmt,
2472 #ifdef UNICODE
2473  catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
2474 #else
2475  catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
2476 #endif
2477  catalog.length(),
2478 #ifdef UNICODE
2479  schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
2480 #else
2481  schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
2482 #endif
2483  schema.length(),
2484 #ifdef UNICODE
2485  toSQLTCHAR(table).data(),
2486 #else
2487  (SQLCHAR*)table.toUtf8().data(),
2488 #endif
2489  table.length(),
2490  NULL,
2491  0);
2492  if (r != SQL_SUCCESS)
2493  qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
2494 
2495  if (d->hasSQLFetchScroll)
2496  r = SQLFetchScroll(hStmt,
2497  SQL_FETCH_NEXT,
2498  0);
2499  else
2500  r = SQLFetch(hStmt);
2501 
2502  // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
2503  while (r == SQL_SUCCESS) {
2504 
2505  fil.append(qMakeFieldInfo(hStmt, d));
2506 
2507  if (d->hasSQLFetchScroll)
2508  r = SQLFetchScroll(hStmt,
2509  SQL_FETCH_NEXT,
2510  0);
2511  else
2512  r = SQLFetch(hStmt);
2513  }
2514 
2515  r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
2516  if (r!= SQL_SUCCESS)
2517  qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ") + QString::number(r), d);
2518 
2519  return fil;
2520 }
2521 
2523  bool trimStrings) const
2524 {
2525  QString r;
2526  if (field.isNull()) {
2527  r = QLatin1String("NULL");
2528  } else if (field.type() == QVariant::DateTime) {
2529  // Use an escape sequence for the datetime fields
2530  if (field.value().toDateTime().isValid()){
2531  QDate dt = field.value().toDateTime().date();
2532  QTime tm = field.value().toDateTime().time();
2533  // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
2534  r = QLatin1String("{ ts '") +
2535  QString::number(dt.year()) + QLatin1Char('-') +
2536  QString::number(dt.month()).rightJustified(2, QLatin1Char('0'), true) +
2537  QLatin1Char('-') +
2538  QString::number(dt.day()).rightJustified(2, QLatin1Char('0'), true) +
2539  QLatin1Char(' ') +
2540  tm.toString() +
2541  QLatin1String("' }");
2542  } else
2543  r = QLatin1String("NULL");
2544  } else if (field.type() == QVariant::ByteArray) {
2545  QByteArray ba = field.value().toByteArray();
2546  QString res;
2547  static const char hexchars[] = "0123456789abcdef";
2548  for (int i = 0; i < ba.size(); ++i) {
2549  uchar s = (uchar) ba[i];
2550  res += QLatin1Char(hexchars[s >> 4]);
2551  res += QLatin1Char(hexchars[s & 0x0f]);
2552  }
2553  r = QLatin1String("0x") + res;
2554  } else {
2555  r = QSqlDriver::formatValue(field, trimStrings);
2556  }
2557  return r;
2558 }
2559 
2561 {
2562  return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
2563 }
2564 
2566 {
2567  QChar quote = d->quoteChar();
2568  QString res = identifier;
2569  if(!identifier.isEmpty() && !identifier.startsWith(quote) && !identifier.endsWith(quote) ) {
2570  res.replace(quote, QString(quote)+QString(quote));
2571  res.prepend(quote).append(quote);
2572  res.replace(QLatin1Char('.'), QString(quote)+QLatin1Char('.')+QString(quote));
2573  }
2574  return res;
2575 }
2576 
2578 {
2579  QChar quote = d->quoteChar();
2580  return identifier.size() > 2
2581  && identifier.startsWith(quote) //left delimited
2582  && identifier.endsWith(quote); //right delimited
2583 }
2584 
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
static QString qODBCWarn(const QODBCPrivate *odbc, int *nativeCode=0)
Definition: qsql_odbc.cpp:254
The QSqlIndex class provides functions to manipulate and describe database indexes.
Definition: qsqlindex.h:55
QBool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:904
void resize(int size)
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_odbc.cpp:1241
void cleanup()
Definition: qsql_odbc.cpp:1917
bool nextResult()
Definition: qsql_odbc.cpp:1679
const T * constData() const
const QSqlDriver * driver() const
Returns the driver associated with the result.
Definition: qsqlresult.cpp:389
QVariant handle() const
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
Definition: qsql_odbc.cpp:2560
bool fetchPrevious()
Positions the result to the previous record (row) in the result.
Definition: qsql_odbc.cpp:1070
SQLHANDLE hStmt
Definition: qsql_odbc.cpp:173
int type
Definition: qmetatype.cpp:239
bool fetchNext()
Positions the result to the next available record (row) in the result.
Definition: qsql_odbc.cpp:1026
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
Definition: qsqlresult.cpp:340
static mach_timebase_info_data_t info
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const
Definition: qsql_odbc.cpp:2577
virtual void setOpen(bool o)
This function sets the open state of the database to open.
Definition: qsqldriver.cpp:283
QODBCPrivate * d
Definition: qsql_odbc.h:110
bool isForwardOnly() const
Returns true if you can only scroll forward through the result set; otherwise returns false...
Definition: qsqlresult.cpp:582
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
DriverFeature
This enum contains a list of features a driver might support.
Definition: qsqldriver.h:75
QString formatValue(const QSqlField &field, bool trimStrings) const
Returns a string representation of the field value for the database.
Definition: qsql_odbc.cpp:2522
bool isNull() const
Returns true if this is a NULL variant, false otherwise.
Definition: qvariant.cpp:3102
static int qGetODBCVersion(const QString &connOpts)
Definition: qsql_odbc.cpp:655
#define it(className, varName)
The QFlag class is a helper data type for QFlags.
Definition: qglobal.h:2289
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
int numRowsAffected()
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
Definition: qsql_odbc.cpp:1246
void append(const QSqlField &field)
Appends the field field to the list of indexed fields.
Definition: qsqlindex.cpp:129
QVariant value() const
Returns the value of the field as a QVariant.
Definition: qsqlfield.h:71
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
QString & replace(int i, int len, QChar after)
Definition: qstring.cpp:2005
static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, const T *p, bool isSigned=true)
Definition: qsql_odbc.cpp:293
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
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
static QVarLengthArray< SQLTCHAR > toSQLTCHAR(const QString &input)
Definition: qsql_odbc.cpp:93
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
QODBCDriverPrivate * driverPrivate
Definition: qsql_odbc.cpp:183
static QVariant qGetDoubleData(SQLHANDLE hStmt, int column)
Definition: qsql_odbc.cpp:531
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
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
bool fetchLast()
Positions the result to the last record (last row) in the result.
Definition: qsql_odbc.cpp:1089
bool endTrans()
Definition: qsql_odbc.cpp:2217
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
int day() const
Returns the day of the month (1 to 31) of this date.
Definition: qdatetime.cpp:395
bool isValid() const
Returns true if both the date and the time are valid; otherwise returns false.
Definition: qdatetime.cpp:2346
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
QString escapeIdentifier(const QString &identifier, IdentifierType type) const
Returns the identifier escaped according to the database rules.
Definition: qsql_odbc.cpp:2565
int msec() const
Returns the millisecond part (0 to 999) of the time.
Definition: qdatetime.cpp:1611
QVariant data(int field)
Returns the data for field index in the current row as a QVariant.
Definition: qsql_odbc.cpp:1128
long ASN1_INTEGER_get ASN1_INTEGER * a
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
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
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
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
bool rollbackTransaction()
This function is called to rollback a transaction.
Definition: qsql_odbc.cpp:2200
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
SQLHANDLE dpDbc() const
Definition: qsql_odbc.cpp:172
void close()
Derived classes must reimplement this pure virtual function in order to close the database connection...
Definition: qsql_odbc.cpp:1910
QODBCPrivate(QODBCDriverPrivate *dpp)
Definition: qsql_odbc.cpp:159
void append(const T &t)
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has type() ByteArray or String (converted using QS...
Definition: qvariant.cpp:2383
iterator Iterator
Qt-style synonym for QList::iterator.
Definition: qlist.h:278
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
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
static QString translate(const char *context, const char *key, const char *disambiguation=0, Encoding encoding=CodecForTr)
static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned=true)
Definition: qsql_odbc.cpp:511
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
Definition: qsqlresult.cpp:417
bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const
Returns whether identifier is escaped according to the database rules.
Definition: qsqldriver.cpp:429
SQLHANDLE dpEnv() const
Definition: qsql_odbc.cpp:171
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
virtual ~QODBCDriver()
Definition: qsql_odbc.cpp:1766
void clearValues()
Definition: qsql_odbc.cpp:168
ErrorType
This enum type describes the context in which the error occurred, e.
Definition: qsqlerror.h:56
bool fetchFirst()
Positions the result to the first record (row 0) in the result.
Definition: qsql_odbc.cpp:1048
virtual void setForwardOnly(bool forward)
Sets forward only mode to forward.
Definition: qsql_odbc.cpp:1734
unsigned char uchar
Definition: qglobal.h:994
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
The QTime class provides clock time functions.
Definition: qdatetime.h:148
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
bool commitTransaction()
This function is called to commit a transaction.
Definition: qsql_odbc.cpp:2183
bool hasSQLFetchScroll
Definition: qsql_odbc.cpp:182
bool fetch(int i)
Positions the result to an arbitrary (zero-based) row index.
Definition: qsql_odbc.cpp:990
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
unsigned __int64 quint64
Definition: qglobal.h:943
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
static const SQLSMALLINT qParamType[4]
Definition: qsql_odbc.cpp:68
int size() const
Returns the number of characters in this string.
Definition: qstring.h:102
const QChar * unicode() const
Returns a &#39;\0&#39;-terminated Unicode representation of the string.
Definition: qstring.h:706
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode=0)
Definition: qsql_odbc.cpp:202
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
void virtual_hook(int id, void *data)
Definition: qsql_odbc.cpp:1718
bool isNull(int field)
Returns true if the field at position index in the current row is null; otherwise returns false...
Definition: qsql_odbc.cpp:1228
static const int COLNAMESIZE
Definition: qsql_odbc.cpp:66
QODBCDriverPrivate * d
Definition: qsql_odbc.h:150
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 QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
Q_CORE_EXPORT void qWarning(const char *,...)
int second() const
Returns the second part (0 to 59) of the time.
Definition: qdatetime.cpp:1600
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
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
QSqlRecord record(const QString &tablename) const
Returns a QSqlRecord populated with the names of the fields in table tableName.
Definition: qsql_odbc.cpp:2435
bool hasFeature(DriverFeature f) const
Returns true if the driver supports feature feature; otherwise returns false.
Definition: qsql_odbc.cpp:1772
virtual ~QODBCResult()
Definition: qsql_odbc.cpp:895
bool beginTransaction()
This function is called to begin a transaction.
Definition: qsql_odbc.cpp:2164
#define UNICODE
Definition: qsql_db2.cpp:62
__int64 qint64
Definition: qglobal.h:942
static void qSqlWarning(const QString &message, const QODBCPrivate *odbc)
Definition: qsql_odbc.cpp:267
static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned=true)
Definition: qsql_odbc.cpp:551
int minute() const
Returns the minute part (0 to 59) of the time.
Definition: qdatetime.cpp:1589
unsigned long ulong
Definition: qglobal.h:997
quint16 values[128]
QVariant::Type type() const
Returns the field&#39;s type as stored in the database.
Definition: qsqlfield.cpp:394
virtual void setForwardOnly(bool forward)
Sets forward only mode to forward.
Definition: qsqlresult.cpp:603
qreal qPow(qreal x, qreal y)
Definition: qmath.h:244
QSqlField field(int i) const
Returns the field at position index.
Definition: qsqlrecord.cpp:289
virtual void virtual_hook(int id, void *data)
Definition: qsqlresult.cpp:962
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_odbc.cpp:1257
QStringList tables(QSql::TableType) const
Returns a list of the names of the tables in the database.
Definition: qsql_odbc.cpp:2231
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
Definition: qsql_odbc.cpp:454
int disconnectCount
Definition: qsql_odbc.cpp:181
int length() const
Same as size().
Definition: qbytearray.h:356
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
QString toString(Qt::DateFormat f=Qt::TextDate) const
Returns the time as a string.
Definition: qdatetime.cpp:1653
int length() const
Returns the field&#39;s length.
Definition: qsqlfield.cpp:457
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
QVector< QVariant > fieldCache
Definition: qsql_odbc.cpp:179
QDate toDate() const
Returns the variant as a QDate if the variant has type() Date , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2311
int count() const
Returns the number of fields in the record.
Definition: qsqlrecord.cpp:573
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 & append(QChar c)
Definition: qstring.cpp:1777
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
QSqlResult * createResult() const
Creates an empty SQL result on the database.
Definition: qsql_odbc.cpp:2159
int capacity() const
Returns the maximum number of characters that can be stored in the string without forcing a reallocat...
Definition: qstring.h:727
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
bool isStmtHandleValid(const QSqlDriver *driver)
Definition: qsql_odbc.cpp:190
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
unsigned short ushort
Definition: qglobal.h:995
QODBCDriver(QObject *parent=0)
Definition: qsql_odbc.cpp:1743
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 QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool unicode=false)
Definition: qsql_odbc.cpp:353
Type type() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1901
QSqlIndex primaryIndex(const QString &tablename) const
Returns the primary index for table tableName.
Definition: qsql_odbc.cpp:2308
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
bool isNull() const
Returns true if the field&#39;s value is NULL; otherwise returns false.
Definition: qsqlfield.cpp:428
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
QString toLower() const Q_REQUIRED_RESULT
Returns a lowercase copy of the string.
Definition: qstring.cpp:5389
void resize(int size)
Sets the size of the byte array to size bytes.
QODBCResult(const QODBCDriver *db, QODBCDriverPrivate *p)
Definition: qsql_odbc.cpp:889
void append(const QSqlField &field)
Append a copy of field field to the end of the record.
Definition: qsqlrecord.cpp:312
QFactoryLoader * l
static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate *p)
Definition: qsql_odbc.cpp:574
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_odbc.cpp:1816
bool exec()
Executes the query, returning true if successful; otherwise returns false.
Definition: qsql_odbc.cpp:1318
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
Definition: qsqlresult.cpp:379
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active...
Definition: qsqlresult.cpp:402
void clear()
Removes all the record&#39;s fields.
Definition: qsqlrecord.cpp:367
QSqlRecord rInf
Definition: qsql_odbc.cpp:178
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QODBCPrivate *p)
Definition: qsql_odbc.cpp:277
quint16 index
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
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
QTime time() const
Returns the time part of the datetime.
Definition: qdatetime.cpp:2368
Definition: qsql.h:68
QTime toTime() const
Returns the variant as a QTime if the variant has type() Time , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2330
The QSqlField class manipulates the fields in SQL database tables and views.
Definition: qsqlfield.h:56
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
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
char at(int i) const
Returns the character at index position i in the byte array.
Definition: qbytearray.h:413
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
QSqlRecord record() const
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
Definition: qsql_odbc.cpp:1667
static QString fromSQLTCHAR(const QVarLengthArray< SQLTCHAR > &input, int size=-1)
Definition: qsql_odbc.cpp:70
QVector< uint > toUcs4() const Q_REQUIRED_RESULT
Returns a UCS-4/UTF-32 representation of the string as a QVector<uint>.
Definition: qstring.cpp:4095
#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
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases...
Definition: qsqlresult.h:63
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
QVariant handle() const
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
Definition: qsql_odbc.cpp:1674
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
IdentifierType
This enum contains a list of SQL identifier types.
Definition: qsqldriver.h:83
bool reset(const QString &query)
Sets the result to use the SQL statement query for subsequent data retrieval.
Definition: qsql_odbc.cpp:907
Q_CORE_EXPORT void qCritical(const char *,...)
int size() const
static QString fromUtf16(const ushort *, int size=-1)
Returns a QString initialized with the first size characters of the Unicode string unicode (ISO-10646...
Definition: qstring.cpp:4329
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
bool userForwardOnly
Definition: qsql_odbc.cpp:184
void updateStmtHandleState(const QSqlDriver *driver)
Definition: qsql_odbc.cpp:196
void reserve(int size)
static QString fromUcs4(const uint *, int size=-1)
Returns a QString initialized with the first size characters of the Unicode string unicode (ISO-10646...
Definition: qstring.cpp:4356