src/sql/drivers/odbc/qsql_odbc.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtSql module of the Qt Toolkit.
     7 ** This file is part of the QtSql module of the Qt Toolkit.
     8 **
     8 **
    64 
    64 
    65 #if defined(Q_ODBC_VERSION_2)
    65 #if defined(Q_ODBC_VERSION_2)
    66 //crude hack to get non-unicode capable driver managers to work
    66 //crude hack to get non-unicode capable driver managers to work
    67 # undef UNICODE
    67 # undef UNICODE
    68 # define SQLTCHAR SQLCHAR
    68 # define SQLTCHAR SQLCHAR
    69 # define SQL_C_WCHAR SQL_C_CHAR
    69 # define SQL_C_TCHAR SQL_C_CHAR
    70 #endif
    70 #endif
    71 
    71 
    72 // newer platform SDKs use SQLLEN instead of SQLINTEGER
    72 // newer platform SDKs use SQLLEN instead of SQLINTEGER
    73 #if defined(WIN32) && (_MSC_VER < 1300)
    73 #if defined(WIN32) && (_MSC_VER < 1300)
    74 # define QSQLLEN SQLINTEGER
    74 # define QSQLLEN SQLINTEGER
    76 #else
    76 #else
    77 # define QSQLLEN SQLLEN
    77 # define QSQLLEN SQLLEN
    78 # define QSQLULEN SQLULEN
    78 # define QSQLULEN SQLULEN
    79 #endif
    79 #endif
    80 
    80 
    81 
       
    82 static const int COLNAMESIZE = 256;
    81 static const int COLNAMESIZE = 256;
    83 //Map Qt parameter types to ODBC types
    82 //Map Qt parameter types to ODBC types
    84 static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
    83 static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
    85 
    84 
       
    85 inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int size=-1)
       
    86 {
       
    87     QString result;
       
    88 
       
    89     int realsize = qMin(size, input.size());
       
    90     if(realsize > 0 && input[realsize-1] == 0)
       
    91         realsize--;
       
    92     switch(sizeof(SQLTCHAR)) {
       
    93         case 1:
       
    94             result=QString::fromUtf8((const char *)input.constData(), realsize);
       
    95             break;
       
    96         case 2:
       
    97             result=QString::fromUtf16((const ushort *)input.constData(), realsize);
       
    98             break;
       
    99         case 4:
       
   100             result=QString::fromUcs4((const uint *)input.constData(), realsize);
       
   101             break;
       
   102         default:
       
   103             qCritical() << "sizeof(SQLTCHAR) is " << sizeof(SQLTCHAR) << "Don't know how to handle this";
       
   104     }
       
   105     return result;
       
   106 }
       
   107 
       
   108 inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
       
   109 {
       
   110     QVarLengthArray<SQLTCHAR> result;
       
   111     result.resize(input.size());
       
   112     switch(sizeof(SQLTCHAR)) {
       
   113         case 1:
       
   114             memcpy(result.data(), input.toUtf8().data(), input.size());
       
   115             break;
       
   116         case 2:
       
   117             memcpy(result.data(), input.unicode(), input.size() * 2);
       
   118             break;
       
   119         case 4:
       
   120             memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
       
   121             break;
       
   122         default:
       
   123             qCritical() << "sizeof(SQLTCHAR) is " << sizeof(SQLTCHAR) << "Don't know how to handle this";
       
   124     }
       
   125     result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
       
   126     return result;
       
   127 }
       
   128 
    86 class QODBCDriverPrivate
   129 class QODBCDriverPrivate
    87 {
   130 {
    88 public:
   131 public:
    89     enum DefaultCase{Lower, Mixed, Upper, Sensitive};
   132     enum DefaultCase{Lower, Mixed, Upper, Sensitive};
    90     QODBCDriverPrivate()
   133     QODBCDriverPrivate()
    91     : hEnv(0), hDbc(0), useSchema(false), disconnectCount(0), isMySqlServer(false),
   134     : hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), isMySqlServer(false),
    92            isMSSqlServer(false), hasSQLFetchScroll(true), hasMultiResultSets(false),
   135            isMSSqlServer(false), isFreeTDSDriver(false), hasSQLFetchScroll(true),
    93            isQuoteInitialized(false), quote(QLatin1Char('"'))
   136            hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"'))
    94     {
   137     {
    95         unicode = false;
       
    96     }
   138     }
    97 
   139 
    98     SQLHANDLE hEnv;
   140     SQLHANDLE hEnv;
    99     SQLHANDLE hDbc;
   141     SQLHANDLE hDbc;
   100 
   142 
   101     uint unicode :1;
   143     bool unicode;
   102     uint useSchema :1;
   144     bool useSchema;
   103     int disconnectCount;
   145     int disconnectCount;
   104     bool isMySqlServer;
   146     bool isMySqlServer;
   105     bool isMSSqlServer;
   147     bool isMSSqlServer;
       
   148     bool isFreeTDSDriver;
   106     bool hasSQLFetchScroll;
   149     bool hasSQLFetchScroll;
   107     bool hasMultiResultSets;
   150     bool hasMultiResultSets;
   108 
   151 
   109     bool checkDriver() const;
   152     bool checkDriver() const;
   110     void checkUnicode();
   153     void checkUnicode();
   127 {
   170 {
   128 public:
   171 public:
   129     QODBCPrivate(QODBCDriverPrivate *dpp)
   172     QODBCPrivate(QODBCDriverPrivate *dpp)
   130     : hStmt(0), useSchema(false), hasSQLFetchScroll(true), driverPrivate(dpp), userForwardOnly(false)
   173     : hStmt(0), useSchema(false), hasSQLFetchScroll(true), driverPrivate(dpp), userForwardOnly(false)
   131     {
   174     {
   132         unicode = false;
   175         unicode = dpp->unicode;
       
   176         useSchema = dpp->useSchema;
       
   177         disconnectCount = dpp->disconnectCount;
       
   178         hasSQLFetchScroll = dpp->hasSQLFetchScroll;
   133     }
   179     }
   134 
   180 
   135     inline void clearValues()
   181     inline void clearValues()
   136     { fieldCache.fill(QVariant()); fieldCacheIdx = 0; }
   182     { fieldCache.fill(QVariant()); fieldCacheIdx = 0; }
   137 
   183 
   138     SQLHANDLE dpEnv() const { return driverPrivate ? driverPrivate->hEnv : 0;}
   184     SQLHANDLE dpEnv() const { return driverPrivate ? driverPrivate->hEnv : 0;}
   139     SQLHANDLE dpDbc() const { return driverPrivate ? driverPrivate->hDbc : 0;}
   185     SQLHANDLE dpDbc() const { return driverPrivate ? driverPrivate->hDbc : 0;}
   140     SQLHANDLE hStmt;
   186     SQLHANDLE hStmt;
   141 
   187 
   142     uint unicode :1;
   188     bool unicode;
   143     uint useSchema :1;
   189     bool useSchema;
   144 
   190 
   145     QSqlRecord rInf;
   191     QSqlRecord rInf;
   146     QVector<QVariant> fieldCache;
   192     QVector<QVariant> fieldCache;
   147     int fieldCacheIdx;
   193     int fieldCacheIdx;
   148     int disconnectCount;
   194     int disconnectCount;
   175     QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH);
   221     QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH);
   176     QString result;
   222     QString result;
   177     int i = 1;
   223     int i = 1;
   178 
   224 
   179     description_[0] = 0;
   225     description_[0] = 0;
   180     r = SQLGetDiagRec(handleType,
       
   181                       handle,
       
   182                       i,
       
   183                       state_,
       
   184                       &nativeCode_,
       
   185                       0,
       
   186                       NULL,
       
   187                       &msgLen);
       
   188     if(r == SQL_NO_DATA)
       
   189         return QString();
       
   190     description_.resize(msgLen+1);
       
   191     do {
   226     do {
       
   227         r = SQLGetDiagRec(handleType,
       
   228                           handle,
       
   229                           i,
       
   230                           state_,
       
   231                           &nativeCode_,
       
   232                           0,
       
   233                           NULL,
       
   234                           &msgLen);
       
   235         if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && msgLen > 0)
       
   236             description_.resize(msgLen+1);
   192         r = SQLGetDiagRec(handleType,
   237         r = SQLGetDiagRec(handleType,
   193                             handle,
   238                             handle,
   194                             i,
   239                             i,
   195                             state_,
   240                             state_,
   196                             &nativeCode_,
   241                             &nativeCode_,
   200         if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
   245         if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
   201             if (nativeCode)
   246             if (nativeCode)
   202                 *nativeCode = nativeCode_;
   247                 *nativeCode = nativeCode_;
   203             QString tmpstore;
   248             QString tmpstore;
   204 #ifdef UNICODE
   249 #ifdef UNICODE
   205             tmpstore = QString((const QChar*)description_.data(), msgLen);
   250             tmpstore = fromSQLTCHAR(description_, msgLen);
   206 #else
   251 #else
   207             tmpstore = QString::fromLocal8Bit((const char*)description_.data(), msgLen);
   252             tmpstore = QString::fromUtf8((const char*)description_.constData(), msgLen);
   208 #endif
   253 #endif
   209             if(result != tmpstore) {
   254             if(result != tmpstore) {
   210                 if(!result.isEmpty())
   255                 if(!result.isEmpty())
   211                     result += QLatin1Char(' ');
   256                     result += QLatin1Char(' ');
   212                 result += tmpstore;
   257                 result += tmpstore;
   221 
   266 
   222 static QString qODBCWarn(const QODBCPrivate* odbc, int *nativeCode = 0)
   267 static QString qODBCWarn(const QODBCPrivate* odbc, int *nativeCode = 0)
   223 {
   268 {
   224     return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->dpEnv()) + QLatin1Char(' ')
   269     return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->dpEnv()) + QLatin1Char(' ')
   225              + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->dpDbc()) + QLatin1Char(' ')
   270              + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->dpDbc()) + QLatin1Char(' ')
   226              + qWarnODBCHandle(SQL_HANDLE_STMT, odbc->hStmt, nativeCode));
   271              + qWarnODBCHandle(SQL_HANDLE_STMT, odbc->hStmt, nativeCode)).simplified();
   227 }
   272 }
   228 
   273 
   229 static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0)
   274 static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0)
   230 {
   275 {
   231     return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1Char(' ')
   276     return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1Char(' ')
   232              + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc, nativeCode));
   277              + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc, nativeCode)).simplified();
   233 }
   278 }
   234 
   279 
   235 static void qSqlWarning(const QString& message, const QODBCPrivate* odbc)
   280 static void qSqlWarning(const QString& message, const QODBCPrivate* odbc)
   236 {
   281 {
   237     qWarning() << message << "\tError:" << qODBCWarn(odbc);
   282     qWarning() << message << "\tError:" << qODBCWarn(odbc);
   305         type = QVariant::String;
   350         type = QVariant::String;
   306         break;
   351         break;
   307 #endif
   352 #endif
   308     case SQL_CHAR:
   353     case SQL_CHAR:
   309     case SQL_VARCHAR:
   354     case SQL_VARCHAR:
       
   355 #if (ODBCVER >= 0x0350)
   310     case SQL_GUID:
   356     case SQL_GUID:
       
   357 #endif
   311     case SQL_LONGVARCHAR:
   358     case SQL_LONGVARCHAR:
   312         type = QVariant::String;
   359         type = QVariant::String;
   313         break;
   360         break;
   314     default:
   361     default:
   315         type = QVariant::ByteArray;
   362         type = QVariant::ByteArray;
   329         colSize = 256;
   376         colSize = 256;
   330     } else if (colSize > 65536) { // limit buffer size to 64 KB
   377     } else if (colSize > 65536) { // limit buffer size to 64 KB
   331         colSize = 65536;
   378         colSize = 65536;
   332     } else {
   379     } else {
   333         colSize++; // make sure there is room for more than the 0 termination
   380         colSize++; // make sure there is room for more than the 0 termination
   334         if (unicode) {
   381     }
   335             colSize *= 2; // a tiny bit faster, since it saves a SQLGetData() call
   382     if(unicode) {
   336         }
       
   337     }
       
   338     QVarLengthArray<char> buf(colSize);
       
   339     while (true) {
       
   340         r = SQLGetData(hStmt,
   383         r = SQLGetData(hStmt,
   341                         column+1,
   384                         column+1,
   342                         unicode ? SQL_C_WCHAR : SQL_C_CHAR,
   385                         SQL_C_TCHAR,
   343                         (SQLPOINTER)buf.data(),
   386                         NULL,
   344                         colSize,
   387                         0,
   345                         &lengthIndicator);
   388                         &lengthIndicator);
   346         if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
   389         if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
   347             if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
   390             colSize = lengthIndicator/sizeof(SQLTCHAR) + 1;
       
   391         QVarLengthArray<SQLTCHAR> buf(colSize);
       
   392         memset(buf.data(), 0, colSize*sizeof(SQLTCHAR));
       
   393         while (true) {
       
   394             r = SQLGetData(hStmt,
       
   395                             column+1,
       
   396                             SQL_C_TCHAR,
       
   397                             (SQLPOINTER)buf.data(),
       
   398                             colSize*sizeof(SQLTCHAR),
       
   399                             &lengthIndicator);
       
   400             if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
       
   401                 if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
       
   402                     fieldVal.clear();
       
   403                     break;
       
   404                 }
       
   405                 // if SQL_SUCCESS_WITH_INFO is returned, indicating that
       
   406                 // more data can be fetched, the length indicator does NOT
       
   407                 // contain the number of bytes returned - it contains the
       
   408                 // total number of bytes that CAN be fetched
       
   409                 // colSize-1: remove 0 termination when there is more data to fetch
       
   410                 int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator/sizeof(SQLTCHAR);
       
   411                     fieldVal += fromSQLTCHAR(buf, rSize);
       
   412                 if (lengthIndicator < (unsigned int)colSize*sizeof(SQLTCHAR)) {
       
   413                     // workaround for Drivermanagers that don't return SQL_NO_DATA
       
   414                     break;
       
   415                 }
       
   416             } else if (r == SQL_NO_DATA) {
       
   417                 break;
       
   418             } else {
       
   419                 qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
   348                 fieldVal.clear();
   420                 fieldVal.clear();
   349                 break;
   421                 break;
   350             }
   422             }
   351             // if SQL_SUCCESS_WITH_INFO is returned, indicating that
   423         }
   352             // more data can be fetched, the length indicator does NOT
   424     } else {
   353             // contain the number of bytes returned - it contains the
   425         r = SQLGetData(hStmt,
   354             // total number of bytes that CAN be fetched
   426                         column+1,
   355             // colSize-1: remove 0 termination when there is more data to fetch
   427                         SQL_C_CHAR,
   356             int rSize = (r == SQL_SUCCESS_WITH_INFO) ? (unicode ? colSize-2 : colSize-1) : lengthIndicator;
   428                         NULL,
   357             if (unicode) {
   429                         0,
   358                 fieldVal += QString((const QChar*) buf.constData(), rSize / 2);
   430                         &lengthIndicator);
       
   431         if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
       
   432             colSize = lengthIndicator + 1;
       
   433         QVarLengthArray<SQLCHAR> buf(colSize);
       
   434         while (true) {
       
   435             r = SQLGetData(hStmt,
       
   436                             column+1,
       
   437                             SQL_C_CHAR,
       
   438                             (SQLPOINTER)buf.data(),
       
   439                             colSize,
       
   440                             &lengthIndicator);
       
   441             if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
       
   442                 if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
       
   443                     fieldVal.clear();
       
   444                     break;
       
   445                 }
       
   446                 // if SQL_SUCCESS_WITH_INFO is returned, indicating that
       
   447                 // more data can be fetched, the length indicator does NOT
       
   448                 // contain the number of bytes returned - it contains the
       
   449                 // total number of bytes that CAN be fetched
       
   450                 // colSize-1: remove 0 termination when there is more data to fetch
       
   451                 int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator;
       
   452                     fieldVal += QString::fromUtf8((const char *)buf.constData(), rSize);
       
   453                 if (lengthIndicator < (unsigned int)colSize) {
       
   454                     // workaround for Drivermanagers that don't return SQL_NO_DATA
       
   455                     break;
       
   456                 }
       
   457             } else if (r == SQL_NO_DATA) {
       
   458                 break;
   359             } else {
   459             } else {
   360                 fieldVal += QString::fromAscii(buf.constData(), rSize);
   460                 qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
   361             }
   461                 fieldVal.clear();
   362             memset(buf.data(), 0, colSize);
       
   363             if (lengthIndicator < colSize) {
       
   364                 // workaround for Drivermanagers that don't return SQL_NO_DATA
       
   365                 break;
   462                 break;
   366             }
   463             }
   367         } else if (r == SQL_NO_DATA) {
       
   368             break;
       
   369         } else {
       
   370             qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
       
   371             fieldVal.clear();
       
   372             break;
       
   373         }
   464         }
   374     }
   465     }
   375     return fieldVal;
   466     return fieldVal;
   376 }
   467 }
   377 
   468 
   384     SQLSMALLINT colScale;
   475     SQLSMALLINT colScale;
   385     SQLSMALLINT nullable;
   476     SQLSMALLINT nullable;
   386     QSQLLEN lengthIndicator = 0;
   477     QSQLLEN lengthIndicator = 0;
   387     SQLRETURN r = SQL_ERROR;
   478     SQLRETURN r = SQL_ERROR;
   388 
   479 
   389     SQLTCHAR colName[COLNAMESIZE];
   480     QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
       
   481 
   390     r = SQLDescribeCol(hStmt,
   482     r = SQLDescribeCol(hStmt,
   391                        column + 1,
   483                        column + 1,
   392                        colName,
   484                        colName.data(),
   393                        COLNAMESIZE,
   485                        COLNAMESIZE,
   394                        &colNameLen,
   486                        &colNameLen,
   395                        &colType,
   487                        &colType,
   396                        &colSize,
   488                        &colSize,
   397                        &colScale,
   489                        &colScale,
   520     SQLSMALLINT colType;
   612     SQLSMALLINT colType;
   521     QSQLULEN colSize;
   613     QSQLULEN colSize;
   522     SQLSMALLINT colScale;
   614     SQLSMALLINT colScale;
   523     SQLSMALLINT nullable;
   615     SQLSMALLINT nullable;
   524     SQLRETURN r = SQL_ERROR;
   616     SQLRETURN r = SQL_ERROR;
   525     SQLTCHAR colName[COLNAMESIZE];
   617     QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
   526     r = SQLDescribeCol(p->hStmt,
   618     r = SQLDescribeCol(p->hStmt,
   527                         i+1,
   619                         i+1,
   528                         colName,
   620                         colName.data(),
   529                         (SQLSMALLINT)COLNAMESIZE,
   621                         (SQLSMALLINT)COLNAMESIZE,
   530                         &colNameLen,
   622                         &colNameLen,
   531                         &colType,
   623                         &colType,
   532                         &colSize,
   624                         &colSize,
   533                         &colScale,
   625                         &colScale,
   549     if (r != SQL_SUCCESS) {
   641     if (r != SQL_SUCCESS) {
   550         qSqlWarning(QString::fromLatin1("qMakeField: Unable to get column attributes for column %1").arg(i), p);
   642         qSqlWarning(QString::fromLatin1("qMakeField: Unable to get column attributes for column %1").arg(i), p);
   551     }
   643     }
   552 
   644 
   553 #ifdef UNICODE
   645 #ifdef UNICODE
   554     QString qColName((const QChar*)colName, colNameLen);
   646     QString qColName(fromSQLTCHAR(colName, colNameLen));
   555 #else
   647 #else
   556     QString qColName = QString::fromLocal8Bit((const char*)colName);
   648     QString qColName = QString::fromUtf8((const char *)colName.constData());
   557 #endif
   649 #endif
   558     // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
   650     // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
   559     int required = -1;
   651     int required = -1;
   560     if (nullable == SQL_NO_NULLS) {
   652     if (nullable == SQL_NO_NULLS) {
   561         required = 1;
   653         required = 1;
   579 {
   671 {
   580 #ifndef Q_ODBC_VERSION_2
   672 #ifndef Q_ODBC_VERSION_2
   581     if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"), Qt::CaseInsensitive))
   673     if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"), Qt::CaseInsensitive))
   582         return SQL_OV_ODBC3;
   674         return SQL_OV_ODBC3;
   583 #endif
   675 #endif
       
   676     if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC2"), Qt::CaseInsensitive))
       
   677         return SQL_OV_ODBC2;
       
   678 #ifdef _IODBCUNIX_H
       
   679     return SQL_OV_ODBC3;
       
   680 #else
   584     return SQL_OV_ODBC2;
   681     return SQL_OV_ODBC2;
       
   682 #endif
   585 }
   683 }
   586 
   684 
   587 QChar QODBCDriverPrivate::quoteChar()
   685 QChar QODBCDriverPrivate::quoteChar()
   588 {
   686 {
   589     if (!isQuoteInitialized) {
   687     if (!isQuoteInitialized) {
   590         char driverResponse[4];
   688         SQLTCHAR driverResponse[4];
   591         SQLSMALLINT length;
   689         SQLSMALLINT length;
   592         int r = SQLGetInfo(hDbc,
   690         int r = SQLGetInfo(hDbc,
   593                 SQL_IDENTIFIER_QUOTE_CHAR,
   691                 SQL_IDENTIFIER_QUOTE_CHAR,
   594                 &driverResponse,
   692                 &driverResponse,
   595                 sizeof(driverResponse),
   693                 sizeof(driverResponse),
   596                 &length);
   694                 &length);
   597         if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
   695         if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
       
   696 #ifdef UNICODE
       
   697             quote = QChar(driverResponse[0]);
       
   698 #else
   598             quote = QLatin1Char(driverResponse[0]);
   699             quote = QLatin1Char(driverResponse[0]);
   599         } else {
   700 #endif
       
   701         else
   600             quote = QLatin1Char('"');
   702             quote = QLatin1Char('"');
   601         }
       
   602         isQuoteInitialized = true;
   703         isQuoteInitialized = true;
   603     }
   704     }
   604     return quote;
   705     return quote;
   605 }
   706 }
   606 
   707 
   640             r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) v, 0);
   741             r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) v, 0);
   641         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
   742         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
   642             val.utf16(); // 0 terminate
   743             val.utf16(); // 0 terminate
   643             r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
   744             r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
   644 #ifdef UNICODE
   745 #ifdef UNICODE
   645                                     (SQLWCHAR*) val.unicode(),
   746                                     toSQLTCHAR(val).data(),
   646 #else
   747 #else
   647                                     (SQLCHAR*) val.toLatin1().constData(),
   748                                     (SQLCHAR*) val.toUtf8().data(),
   648 #endif
   749 #endif
   649                                     SQL_NTS);
   750                                     val.length()*sizeof(SQLTCHAR));
   650         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
   751         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
   651             if (val.toUpper() == QLatin1String("SQL_TRUE")) {
   752             if (val.toUpper() == QLatin1String("SQL_TRUE")) {
   652                 v = SQL_TRUE;
   753                 v = SQL_TRUE;
   653             } else if (val.toUpper() == QLatin1String("SQL_FALSE")) {
   754             } else if (val.toUpper() == QLatin1String("SQL_FALSE")) {
   654                 v = SQL_FALSE;
   755                 v = SQL_FALSE;
   662             r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) v, 0);
   763             r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) v, 0);
   663         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
   764         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
   664             val.utf16(); // 0 terminate
   765             val.utf16(); // 0 terminate
   665             r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
   766             r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
   666 #ifdef UNICODE
   767 #ifdef UNICODE
   667                                     (SQLWCHAR*) val.unicode(),
   768                                     toSQLTCHAR(val).data(),
   668 #else
   769 #else
   669                                     (SQLCHAR*) val.toLatin1().constData(),
   770                                     (SQLCHAR*) val.toUtf8().data(),
   670 #endif
   771 #endif
   671                                     SQL_NTS);
   772                                     val.length()*sizeof(SQLTCHAR));
   672         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
   773         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
   673             if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
   774             if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
   674                 v = SQL_OPT_TRACE_OFF;
   775                 v = SQL_OPT_TRACE_OFF;
   675             } else if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_ON")) {
   776             } else if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_ON")) {
   676                 v = SQL_OPT_TRACE_ON;
   777                 v = SQL_OPT_TRACE_ON;
   812 
   913 
   813 QODBCResult::QODBCResult(const QODBCDriver * db, QODBCDriverPrivate* p)
   914 QODBCResult::QODBCResult(const QODBCDriver * db, QODBCDriverPrivate* p)
   814 : QSqlResult(db)
   915 : QSqlResult(db)
   815 {
   916 {
   816     d = new QODBCPrivate(p);
   917     d = new QODBCPrivate(p);
   817     d->unicode = p->unicode;
       
   818     d->useSchema = p->useSchema;
       
   819     d->disconnectCount = p->disconnectCount;
       
   820     d->hasSQLFetchScroll = p->hasSQLFetchScroll;
       
   821 }
   918 }
   822 
   919 
   823 QODBCResult::~QODBCResult()
   920 QODBCResult::~QODBCResult()
   824 {
   921 {
   825     if (d->hStmt && d->isStmtHandleValid(driver()) && driver()->isOpen()) {
   922     if (d->hStmt && d->isStmtHandleValid(driver()) && driver()->isOpen()) {
   878         return false;
   975         return false;
   879     }
   976     }
   880 
   977 
   881 #ifdef UNICODE
   978 #ifdef UNICODE
   882     r = SQLExecDirect(d->hStmt,
   979     r = SQLExecDirect(d->hStmt,
   883                        (SQLWCHAR*) query.unicode(),
   980                        toSQLTCHAR(query).data(),
   884                        (SQLINTEGER) query.length());
   981                        (SQLINTEGER) query.length());
   885 #else
   982 #else
   886     QByteArray query8 = query.toLocal8Bit();
   983     QByteArray query8 = query.toUtf8();
   887     r = SQLExecDirect(d->hStmt,
   984     r = SQLExecDirect(d->hStmt,
   888                        (SQLCHAR*) query8.constData(),
   985                        (SQLCHAR*) query8.data(),
   889                        (SQLINTEGER) query8.length());
   986                        (SQLINTEGER) query8.length());
   890 #endif
   987 #endif
   891     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
   988     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
   892         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
   989         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
   893                      "Unable to execute statement"), QSqlError::StatementError, d));
   990                      "Unable to execute statement"), QSqlError::StatementError, d));
   894         return false;
   991         return false;
       
   992     }
       
   993 
       
   994     if(r == SQL_NO_DATA) {
       
   995         setSelect(false);
       
   996         return true;
   895     }
   997     }
   896 
   998 
   897     SQLINTEGER isScrollable, bufferLength;
   999     SQLINTEGER isScrollable, bufferLength;
   898     r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, &bufferLength);
  1000     r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, &bufferLength);
   899     if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
  1001     if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
  1224         return false;
  1326         return false;
  1225     }
  1327     }
  1226 
  1328 
  1227 #ifdef UNICODE
  1329 #ifdef UNICODE
  1228     r = SQLPrepare(d->hStmt,
  1330     r = SQLPrepare(d->hStmt,
  1229                     (SQLWCHAR*) query.unicode(),
  1331                     toSQLTCHAR(query).data(),
  1230                     (SQLINTEGER) query.length());
  1332                     (SQLINTEGER) query.length());
  1231 #else
  1333 #else
  1232     QByteArray query8 = query.toLocal8Bit();
  1334     QByteArray query8 = query.toUtf8();
  1233     r = SQLPrepare(d->hStmt,
  1335     r = SQLPrepare(d->hStmt,
  1234                     (SQLCHAR*) query8.constData(),
  1336                     (SQLCHAR*) query8.data(),
  1235                     (SQLINTEGER) query8.length());
  1337                     (SQLINTEGER) query8.length());
  1236 #endif
  1338 #endif
  1237 
  1339 
  1238     if (r != SQL_SUCCESS) {
  1340     if (r != SQL_SUCCESS) {
  1239         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
  1341         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
  1428                 break;
  1530                 break;
  1429             case QVariant::String:
  1531             case QVariant::String:
  1430 #ifndef Q_ODBC_VERSION_2
  1532 #ifndef Q_ODBC_VERSION_2
  1431                 if (d->unicode) {
  1533                 if (d->unicode) {
  1432                     QString str = val.toString();
  1534                     QString str = val.toString();
  1433                     str.utf16();
       
  1434                     if (*ind != SQL_NULL_DATA)
  1535                     if (*ind != SQL_NULL_DATA)
  1435                         *ind = str.length() * sizeof(QChar);
  1536                         *ind = str.length() * sizeof(SQLTCHAR);
  1436                     int strSize = str.length() * sizeof(QChar);
  1537                     int strSize = str.length() * sizeof(SQLTCHAR);
  1437 
  1538 
  1438                     if (bindValueType(i) & QSql::Out) {
  1539                     if (bindValueType(i) & QSql::Out) {
  1439                         QByteArray ba((char*)str.constData(), str.capacity() * sizeof(QChar));
  1540                         QVarLengthArray<SQLTCHAR> ba(toSQLTCHAR(str));
       
  1541                         ba.reserve(str.capacity());
  1440                         r = SQLBindParameter(d->hStmt,
  1542                         r = SQLBindParameter(d->hStmt,
  1441                                             i + 1,
  1543                                             i + 1,
  1442                                             qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1544                                             qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1443                                             SQL_C_WCHAR,
  1545                                             SQL_C_TCHAR,
  1444                                             strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1546                                             strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1445                                             0, // god knows... don't change this!
  1547                                             0, // god knows... don't change this!
  1446                                             0,
  1548                                             0,
  1447                                             (void *)ba.constData(),
  1549                                             (void *)ba.constData(),
  1448                                             ba.size(),
  1550                                             ba.size(),
  1449                                             ind);
  1551                                             ind);
  1450                         tmpStorage.append(ba);
  1552                         tmpStorage.append(QByteArray((const char *)ba.constData(), ba.size()*sizeof(SQLTCHAR)));
  1451                         break;
  1553                         break;
  1452                     }
  1554                     }
  1453 
  1555                     QByteArray strba((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
  1454                     r = SQLBindParameter(d->hStmt,
  1556                     r = SQLBindParameter(d->hStmt,
  1455                                           i + 1,
  1557                                           i + 1,
  1456                                           qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1558                                           qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1457                                           SQL_C_WCHAR,
  1559                                           SQL_C_TCHAR,
  1458                                           strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1560                                           strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1459                                           strSize,
  1561                                           strSize,
  1460                                           0,
  1562                                           0,
  1461                                           (void *)str.constData(),
  1563                                           (SQLPOINTER)strba.constData(),
  1462                                           strSize,
  1564                                           strba.size(),
  1463                                           ind);
  1565                                           ind);
       
  1566                     tmpStorage.append(strba);
  1464                     break;
  1567                     break;
  1465                 }
  1568                 }
  1466                 else
  1569                 else
  1467 #endif
  1570 #endif
  1468                 {
  1571                 {
  1469                     QByteArray str = val.toString().toAscii();
  1572                     QByteArray str = val.toString().toUtf8();
  1470                     if (*ind != SQL_NULL_DATA)
  1573                     if (*ind != SQL_NULL_DATA)
  1471                         *ind = str.length();
  1574                         *ind = str.length();
  1472                     int strSize = str.length();
  1575                     int strSize = str.length();
  1473 
  1576 
  1474                     r = SQLBindParameter(d->hStmt,
  1577                     r = SQLBindParameter(d->hStmt,
  1565             case QVariant::ULongLong:
  1668             case QVariant::ULongLong:
  1566                 //nothing to do
  1669                 //nothing to do
  1567                 break;
  1670                 break;
  1568             case QVariant::String:
  1671             case QVariant::String:
  1569                 if (d->unicode) {
  1672                 if (d->unicode) {
  1570                     if (bindValueType(i) & QSql::Out)
  1673                     if (bindValueType(i) & QSql::Out) {
  1571                         values[i] = QString::fromUtf16((ushort*)tmpStorage.takeFirst().constData());
  1674                         QByteArray first = tmpStorage.takeFirst();
       
  1675                         QVarLengthArray<SQLTCHAR> array;
       
  1676                         array.append((SQLTCHAR *)first.constData(), first.size());
       
  1677                         values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR*));
       
  1678                     }
  1572                     break;
  1679                     break;
  1573                 }
  1680                 }
  1574                 // fall through
  1681                 // fall through
  1575             default: {
  1682             default: {
  1576                 QByteArray ba = tmpStorage.takeFirst();
       
  1577                 if (bindValueType(i) & QSql::Out)
  1683                 if (bindValueType(i) & QSql::Out)
  1578                     values[i] = QString::fromAscii(ba.constData());
  1684                     values[i] = tmpStorage.takeFirst();
  1579                 break; }
  1685                 break; }
  1580         }
  1686         }
  1581         if (indicators[i] == SQL_NULL_DATA)
  1687         if (indicators[i] == SQL_NULL_DATA)
  1582             values[i] = QVariant(values[i].type());
  1688             values[i] = QVariant(values[i].type());
  1583     }
  1689     }
  1782         connQStr += QLatin1String(";UID=") + user;
  1888         connQStr += QLatin1String(";UID=") + user;
  1783     if (!password.isEmpty())
  1889     if (!password.isEmpty())
  1784         connQStr += QLatin1String(";PWD=") + password;
  1890         connQStr += QLatin1String(";PWD=") + password;
  1785 
  1891 
  1786     SQLSMALLINT cb;
  1892     SQLSMALLINT cb;
  1787     SQLTCHAR connOut[1024];
  1893     QVarLengthArray<SQLTCHAR> connOut(1024);
       
  1894     memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
  1788     r = SQLDriverConnect(d->hDbc,
  1895     r = SQLDriverConnect(d->hDbc,
  1789                           NULL,
  1896                           NULL,
  1790 #ifdef UNICODE
  1897 #ifdef UNICODE
  1791                           (SQLWCHAR*)connQStr.unicode(),
  1898                           toSQLTCHAR(connQStr).data(),
  1792 #else
  1899 #else
  1793                           (SQLCHAR*)connQStr.toLatin1().constData(),
  1900                           (SQLCHAR*)connQStr.toUtf8().data(),
  1794 #endif
  1901 #endif
  1795                           (SQLSMALLINT)connQStr.length(),
  1902                           (SQLSMALLINT)connQStr.length(),
  1796                           connOut,
  1903                           connOut.data(),
  1797                           1024,
  1904                           1024,
  1798                           &cb,
  1905                           &cb,
  1799                           SQL_DRIVER_NOPROMPT);
  1906                           /*SQL_DRIVER_NOPROMPT*/0);
       
  1907 
  1800     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
  1908     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
  1801         setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
  1909         setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
  1802         setOpenError(true);
  1910         setOpenError(true);
  1803         return false;
  1911         return false;
  1804     }
  1912     }
  1879                     (SQLPOINTER)&fFunc,
  1987                     (SQLPOINTER)&fFunc,
  1880                     sizeof(fFunc),
  1988                     sizeof(fFunc),
  1881                     NULL);
  1989                     NULL);
  1882     if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
  1990     if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
  1883         unicode = true;
  1991         unicode = true;
       
  1992         return;
  1884     }
  1993     }
  1885 
  1994 
  1886     r = SQLGetInfo(hDbc,
  1995     r = SQLGetInfo(hDbc,
  1887                     SQL_CONVERT_VARCHAR,
  1996                     SQL_CONVERT_VARCHAR,
  1888                     (SQLPOINTER)&fFunc,
  1997                     (SQLPOINTER)&fFunc,
  1889                     sizeof(fFunc),
  1998                     sizeof(fFunc),
  1890                     NULL);
  1999                     NULL);
  1891     if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
  2000     if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
  1892         unicode = true;
  2001         unicode = true;
       
  2002         return;
  1893     }
  2003     }
  1894 
  2004 
  1895     r = SQLGetInfo(hDbc,
  2005     r = SQLGetInfo(hDbc,
  1896                     SQL_CONVERT_LONGVARCHAR,
  2006                     SQL_CONVERT_LONGVARCHAR,
  1897                     (SQLPOINTER)&fFunc,
  2007                     (SQLPOINTER)&fFunc,
  1898                     sizeof(fFunc),
  2008                     sizeof(fFunc),
  1899                     NULL);
  2009                     NULL);
  1900     if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
  2010     if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
  1901         unicode = true;
  2011         unicode = true;
  1902     }
  2012         return;
       
  2013     }
       
  2014     SQLHANDLE hStmt;
       
  2015     r = SQLAllocHandle(SQL_HANDLE_STMT,
       
  2016                                   hDbc,
       
  2017                                   &hStmt);
       
  2018 
       
  2019     r = SQLExecDirect(hStmt, toSQLTCHAR(QLatin1String("select 'test'")).data(), SQL_NTS);
       
  2020     if(r == SQL_SUCCESS) {
       
  2021         r = SQLFetch(hStmt);
       
  2022         if(r == SQL_SUCCESS) {
       
  2023             QVarLengthArray<SQLWCHAR> buffer(10);
       
  2024             r = SQLGetData(hStmt, 1, SQL_C_WCHAR, buffer.data(), buffer.size() * sizeof(SQLWCHAR), NULL);
       
  2025             if(r == SQL_SUCCESS && fromSQLTCHAR(buffer) == QLatin1String("test")) {
       
  2026                 unicode = true;
       
  2027             }
       
  2028         }
       
  2029     }
       
  2030     r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
  1903 }
  2031 }
  1904 
  2032 
  1905 bool QODBCDriverPrivate::checkDriver() const
  2033 bool QODBCDriverPrivate::checkDriver() const
  1906 {
  2034 {
  1907 #ifdef ODBC_CHECK_DRIVER
  2035 #ifdef ODBC_CHECK_DRIVER
  1970 }
  2098 }
  1971 
  2099 
  1972 void QODBCDriverPrivate::checkSqlServer()
  2100 void QODBCDriverPrivate::checkSqlServer()
  1973 {
  2101 {
  1974     SQLRETURN   r;
  2102     SQLRETURN   r;
  1975     char serverString[200];
  2103     QVarLengthArray<SQLTCHAR> serverString(200);
  1976     SQLSMALLINT t;
  2104     SQLSMALLINT t;
       
  2105     memset(serverString.data(), 0, serverString.size() * sizeof(SQLTCHAR));
  1977 
  2106 
  1978     r = SQLGetInfo(hDbc,
  2107     r = SQLGetInfo(hDbc,
  1979                    SQL_DBMS_NAME,
  2108                    SQL_DBMS_NAME,
  1980                    serverString,
  2109                    serverString.data(),
  1981                    sizeof(serverString),
  2110                    serverString.size() * sizeof(SQLTCHAR),
  1982                    &t);
  2111                    &t);
  1983     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
  2112     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
  1984         QString serverType;
  2113         QString serverType;
  1985 #ifdef UNICODE
  2114 #ifdef UNICODE
  1986         serverType = QString(reinterpret_cast<const QChar*>(serverString), t/sizeof(QChar));
  2115         serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR));
  1987 #else
  2116 #else
  1988         serverType = QString::fromLocal8Bit(serverString, t);
  2117         serverType = QString::fromUtf8((const char *)serverString.constData(), t);
  1989 #endif
  2118 #endif
  1990         isMySqlServer = serverType.contains(QLatin1String("mysql"), Qt::CaseInsensitive);
  2119         isMySqlServer = serverType.contains(QLatin1String("mysql"), Qt::CaseInsensitive);
  1991         isMSSqlServer = serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive);
  2120         isMSSqlServer = serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive);
       
  2121     }
       
  2122     r = SQLGetInfo(hDbc,
       
  2123                    SQL_DRIVER_NAME,
       
  2124                    serverString.data(),
       
  2125                    serverString.size() * sizeof(SQLTCHAR),
       
  2126                    &t);
       
  2127     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
       
  2128         QString serverType;
       
  2129 #ifdef UNICODE
       
  2130         serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR));
       
  2131 #else
       
  2132         serverType = QString::fromUtf8((const char *)serverString.constData(), t);
       
  2133 #endif
       
  2134         isFreeTDSDriver = serverType.contains(QLatin1String("tdsodbc"), Qt::CaseInsensitive);
       
  2135         unicode = isFreeTDSDriver == false;
  1992     }
  2136     }
  1993 }
  2137 }
  1994 
  2138 
  1995 void QODBCDriverPrivate::checkHasSQLFetchScroll()
  2139 void QODBCDriverPrivate::checkHasSQLFetchScroll()
  1996 {
  2140 {
  2002     }
  2146     }
  2003 }
  2147 }
  2004 
  2148 
  2005 void QODBCDriverPrivate::checkHasMultiResults()
  2149 void QODBCDriverPrivate::checkHasMultiResults()
  2006 {
  2150 {
  2007     char driverResponse[4];
  2151     QVarLengthArray<SQLTCHAR> driverResponse(2);
  2008     SQLSMALLINT length;
  2152     SQLSMALLINT length;
  2009     SQLRETURN r = SQLGetInfo(hDbc,
  2153     SQLRETURN r = SQLGetInfo(hDbc,
  2010                              SQL_MULT_RESULT_SETS,
  2154                              SQL_MULT_RESULT_SETS,
  2011                              driverResponse,
  2155                              driverResponse.data(),
  2012                              sizeof(driverResponse),
  2156                              driverResponse.size() * sizeof(SQLTCHAR),
  2013                              &length);
  2157                              &length);
  2014     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
  2158     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
  2015 #ifdef UNICODE
  2159 #ifdef UNICODE
  2016         hasMultiResultSets = QString(reinterpret_cast<const QChar*>(driverResponse), length/sizeof(QChar)).startsWith(QLatin1Char('Y'));
  2160         hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y'));
  2017 #else
  2161 #else
  2018         hasMultiResultSets = QString::fromLocal8Bit(driverResponse, length).startsWith(QLatin1Char('Y'));
  2162         hasMultiResultSets = QString::fromUtf8((const char *)driverResponse.constData(), length).startsWith(QLatin1Char('Y'));
  2019 #endif
  2163 #endif
  2020 }
  2164 }
  2021 
  2165 
  2022 QSqlResult *QODBCDriver::createResult() const
  2166 QSqlResult *QODBCDriver::createResult() const
  2023 {
  2167 {
  2127                    NULL,
  2271                    NULL,
  2128                    0,
  2272                    0,
  2129                    NULL,
  2273                    NULL,
  2130                    0,
  2274                    0,
  2131 #ifdef UNICODE
  2275 #ifdef UNICODE
  2132                    (SQLWCHAR*)joinedTableTypeString.unicode(),
  2276                    toSQLTCHAR(joinedTableTypeString).data(),
  2133 #else
  2277 #else
  2134                    (SQLCHAR*)joinedTableTypeString.toLatin1().constData(),
  2278                    (SQLCHAR*)joinedTableTypeString.toUtf8().data(),
  2135 #endif
  2279 #endif
  2136                    joinedTableTypeString.length() /* characters, not bytes */);
  2280                    joinedTableTypeString.length() /* characters, not bytes */);
  2137 
  2281 
  2138     if (r != SQL_SUCCESS)
  2282     if (r != SQL_SUCCESS)
  2139         qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
  2283         qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
  2142         r = SQLFetchScroll(hStmt,
  2286         r = SQLFetchScroll(hStmt,
  2143                            SQL_FETCH_NEXT,
  2287                            SQL_FETCH_NEXT,
  2144                            0);
  2288                            0);
  2145     else
  2289     else
  2146         r = SQLFetch(hStmt);
  2290         r = SQLFetch(hStmt);
       
  2291 
       
  2292     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
       
  2293         qWarning() << "QODBCDriver::tables failed to retrieve table/view list: (" << r << "," << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ")";
       
  2294         return QStringList();
       
  2295     }
  2147 
  2296 
  2148     while (r == SQL_SUCCESS) {
  2297     while (r == SQL_SUCCESS) {
  2149         QString fieldVal = qGetStringData(hStmt, 2, -1, false);
  2298         QString fieldVal = qGetStringData(hStmt, 2, -1, false);
  2150         tl.append(fieldVal);
  2299         tl.append(fieldVal);
  2151 
  2300 
  2201                         SQL_ATTR_CURSOR_TYPE,
  2350                         SQL_ATTR_CURSOR_TYPE,
  2202                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2351                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2203                         SQL_IS_UINTEGER);
  2352                         SQL_IS_UINTEGER);
  2204     r = SQLPrimaryKeys(hStmt,
  2353     r = SQLPrimaryKeys(hStmt,
  2205 #ifdef UNICODE
  2354 #ifdef UNICODE
  2206                         catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),
  2355                         catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
  2207 #else
  2356 #else
  2208                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toLatin1().constData(),
  2357                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
  2209 #endif
  2358 #endif
  2210                         catalog.length(),
  2359                         catalog.length(),
  2211 #ifdef UNICODE
  2360 #ifdef UNICODE
  2212                         schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),
  2361                         schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
  2213 #else
  2362 #else
  2214                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toLatin1().constData(),
  2363                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
  2215 #endif
  2364 #endif
  2216                         schema.length(),
  2365                         schema.length(),
  2217 #ifdef UNICODE
  2366 #ifdef UNICODE
  2218                         (SQLWCHAR*)table.unicode(),
  2367                         toSQLTCHAR(table).data(),
  2219 #else
  2368 #else
  2220                         (SQLCHAR*)table.toLatin1().constData(),
  2369                         (SQLCHAR*)table.toUtf8().data(),
  2221 #endif
  2370 #endif
  2222                         table.length() /* in characters, not in bytes */);
  2371                         table.length() /* in characters, not in bytes */);
  2223 
  2372 
  2224     // if the SQLPrimaryKeys() call does not succeed (e.g the driver
  2373     // if the SQLPrimaryKeys() call does not succeed (e.g the driver
  2225     // does not support it) - try an alternative method to get hold of
  2374     // does not support it) - try an alternative method to get hold of
  2226     // the primary index (e.g MS Access and FoxPro)
  2375     // the primary index (e.g MS Access and FoxPro)
  2227     if (r != SQL_SUCCESS) {
  2376     if (r != SQL_SUCCESS) {
  2228             r = SQLSpecialColumns(hStmt,
  2377             r = SQLSpecialColumns(hStmt,
  2229                         SQL_BEST_ROWID,
  2378                         SQL_BEST_ROWID,
  2230 #ifdef UNICODE
  2379 #ifdef UNICODE
  2231                         catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),
  2380                         catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
  2232 #else
  2381 #else
  2233                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toLatin1().constData(),
  2382                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
  2234 #endif
  2383 #endif
  2235                         catalog.length(),
  2384                         catalog.length(),
  2236 #ifdef UNICODE
  2385 #ifdef UNICODE
  2237                         schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),
  2386                         schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
  2238 #else
  2387 #else
  2239                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toLatin1().constData(),
  2388                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
  2240 #endif
  2389 #endif
  2241                         schema.length(),
  2390                         schema.length(),
  2242 #ifdef UNICODE
  2391 #ifdef UNICODE
  2243                         (SQLWCHAR*)table.unicode(),
  2392                         toSQLTCHAR(table).data(),
  2244 #else
  2393 #else
  2245                         (SQLCHAR*)table.toLatin1().constData(),
  2394                         (SQLCHAR*)table.toUtf8().data(),
  2246 #endif
  2395 #endif
  2247                         table.length(),
  2396                         table.length(),
  2248                         SQL_SCOPE_CURROW,
  2397                         SQL_SCOPE_CURROW,
  2249                         SQL_NULLABLE);
  2398                         SQL_NULLABLE);
  2250 
  2399 
  2326                         SQL_ATTR_CURSOR_TYPE,
  2475                         SQL_ATTR_CURSOR_TYPE,
  2327                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2476                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2328                         SQL_IS_UINTEGER);
  2477                         SQL_IS_UINTEGER);
  2329     r =  SQLColumns(hStmt,
  2478     r =  SQLColumns(hStmt,
  2330 #ifdef UNICODE
  2479 #ifdef UNICODE
  2331                      catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),
  2480                      catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
  2332 #else
  2481 #else
  2333                      catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toLatin1().constData(),
  2482                      catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
  2334 #endif
  2483 #endif
  2335                      catalog.length(),
  2484                      catalog.length(),
  2336 #ifdef UNICODE
  2485 #ifdef UNICODE
  2337                      schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),
  2486                      schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
  2338 #else
  2487 #else
  2339                      schema.length() == 0 ? NULL : (SQLCHAR*)schema.toLatin1().constData(),
  2488                      schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
  2340 #endif
  2489 #endif
  2341                      schema.length(),
  2490                      schema.length(),
  2342 #ifdef UNICODE
  2491 #ifdef UNICODE
  2343                      (SQLWCHAR*)table.unicode(),
  2492                      toSQLTCHAR(table).data(),
  2344 #else
  2493 #else
  2345                      (SQLCHAR*)table.toLatin1().constData(),
  2494                      (SQLCHAR*)table.toUtf8().data(),
  2346 #endif
  2495 #endif
  2347                      table.length(),
  2496                      table.length(),
  2348                      NULL,
  2497                      NULL,
  2349                      0);
  2498                      0);
  2350     if (r != SQL_SUCCESS)
  2499     if (r != SQL_SUCCESS)