src/sql/drivers/odbc/qsql_odbc.cpp
changeset 19 fcece45ef507
parent 18 2f34d5167611
child 30 5dc02b23752f
equal deleted inserted replaced
18:2f34d5167611 19:fcece45ef507
    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 && r!= SQL_NO_DATA) {
   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));
  1229         return false;
  1326         return false;
  1230     }
  1327     }
  1231 
  1328 
  1232 #ifdef UNICODE
  1329 #ifdef UNICODE
  1233     r = SQLPrepare(d->hStmt,
  1330     r = SQLPrepare(d->hStmt,
  1234                     (SQLWCHAR*) query.unicode(),
  1331                     toSQLTCHAR(query).data(),
  1235                     (SQLINTEGER) query.length());
  1332                     (SQLINTEGER) query.length());
  1236 #else
  1333 #else
  1237     QByteArray query8 = query.toLocal8Bit();
  1334     QByteArray query8 = query.toUtf8();
  1238     r = SQLPrepare(d->hStmt,
  1335     r = SQLPrepare(d->hStmt,
  1239                     (SQLCHAR*) query8.constData(),
  1336                     (SQLCHAR*) query8.data(),
  1240                     (SQLINTEGER) query8.length());
  1337                     (SQLINTEGER) query8.length());
  1241 #endif
  1338 #endif
  1242 
  1339 
  1243     if (r != SQL_SUCCESS) {
  1340     if (r != SQL_SUCCESS) {
  1244         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
  1341         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
  1433                 break;
  1530                 break;
  1434             case QVariant::String:
  1531             case QVariant::String:
  1435 #ifndef Q_ODBC_VERSION_2
  1532 #ifndef Q_ODBC_VERSION_2
  1436                 if (d->unicode) {
  1533                 if (d->unicode) {
  1437                     QString str = val.toString();
  1534                     QString str = val.toString();
  1438                     str.utf16();
       
  1439                     if (*ind != SQL_NULL_DATA)
  1535                     if (*ind != SQL_NULL_DATA)
  1440                         *ind = str.length() * sizeof(QChar);
  1536                         *ind = str.length() * sizeof(SQLTCHAR);
  1441                     int strSize = str.length() * sizeof(QChar);
  1537                     int strSize = str.length() * sizeof(SQLTCHAR);
  1442 
  1538 
  1443                     if (bindValueType(i) & QSql::Out) {
  1539                     if (bindValueType(i) & QSql::Out) {
  1444                         QByteArray ba((char*)str.constData(), str.capacity() * sizeof(QChar));
  1540                         QVarLengthArray<SQLTCHAR> ba(toSQLTCHAR(str));
       
  1541                         ba.reserve(str.capacity());
  1445                         r = SQLBindParameter(d->hStmt,
  1542                         r = SQLBindParameter(d->hStmt,
  1446                                             i + 1,
  1543                                             i + 1,
  1447                                             qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1544                                             qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1448                                             SQL_C_WCHAR,
  1545                                             SQL_C_TCHAR,
  1449                                             strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1546                                             strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1450                                             0, // god knows... don't change this!
  1547                                             0, // god knows... don't change this!
  1451                                             0,
  1548                                             0,
  1452                                             (void *)ba.constData(),
  1549                                             (void *)ba.constData(),
  1453                                             ba.size(),
  1550                                             ba.size(),
  1454                                             ind);
  1551                                             ind);
  1455                         tmpStorage.append(ba);
  1552                         tmpStorage.append(QByteArray((const char *)ba.constData(), ba.size()*sizeof(SQLTCHAR)));
  1456                         break;
  1553                         break;
  1457                     }
  1554                     }
  1458 
  1555                     QByteArray strba((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
  1459                     r = SQLBindParameter(d->hStmt,
  1556                     r = SQLBindParameter(d->hStmt,
  1460                                           i + 1,
  1557                                           i + 1,
  1461                                           qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1558                                           qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
  1462                                           SQL_C_WCHAR,
  1559                                           SQL_C_TCHAR,
  1463                                           strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1560                                           strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
  1464                                           strSize,
  1561                                           strSize,
  1465                                           0,
  1562                                           0,
  1466                                           (void *)str.constData(),
  1563                                           (SQLPOINTER)strba.constData(),
  1467                                           strSize,
  1564                                           strba.size(),
  1468                                           ind);
  1565                                           ind);
       
  1566                     tmpStorage.append(strba);
  1469                     break;
  1567                     break;
  1470                 }
  1568                 }
  1471                 else
  1569                 else
  1472 #endif
  1570 #endif
  1473                 {
  1571                 {
  1474                     QByteArray str = val.toString().toAscii();
  1572                     QByteArray str = val.toString().toUtf8();
  1475                     if (*ind != SQL_NULL_DATA)
  1573                     if (*ind != SQL_NULL_DATA)
  1476                         *ind = str.length();
  1574                         *ind = str.length();
  1477                     int strSize = str.length();
  1575                     int strSize = str.length();
  1478 
  1576 
  1479                     r = SQLBindParameter(d->hStmt,
  1577                     r = SQLBindParameter(d->hStmt,
  1570             case QVariant::ULongLong:
  1668             case QVariant::ULongLong:
  1571                 //nothing to do
  1669                 //nothing to do
  1572                 break;
  1670                 break;
  1573             case QVariant::String:
  1671             case QVariant::String:
  1574                 if (d->unicode) {
  1672                 if (d->unicode) {
  1575                     if (bindValueType(i) & QSql::Out)
  1673                     if (bindValueType(i) & QSql::Out) {
  1576                         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                     }
  1577                     break;
  1679                     break;
  1578                 }
  1680                 }
  1579                 // fall through
  1681                 // fall through
  1580             default: {
  1682             default: {
  1581                 QByteArray ba = tmpStorage.takeFirst();
       
  1582                 if (bindValueType(i) & QSql::Out)
  1683                 if (bindValueType(i) & QSql::Out)
  1583                     values[i] = QString::fromAscii(ba.constData());
  1684                     values[i] = tmpStorage.takeFirst();
  1584                 break; }
  1685                 break; }
  1585         }
  1686         }
  1586         if (indicators[i] == SQL_NULL_DATA)
  1687         if (indicators[i] == SQL_NULL_DATA)
  1587             values[i] = QVariant(values[i].type());
  1688             values[i] = QVariant(values[i].type());
  1588     }
  1689     }
  1787         connQStr += QLatin1String(";UID=") + user;
  1888         connQStr += QLatin1String(";UID=") + user;
  1788     if (!password.isEmpty())
  1889     if (!password.isEmpty())
  1789         connQStr += QLatin1String(";PWD=") + password;
  1890         connQStr += QLatin1String(";PWD=") + password;
  1790 
  1891 
  1791     SQLSMALLINT cb;
  1892     SQLSMALLINT cb;
  1792     SQLTCHAR connOut[1024];
  1893     QVarLengthArray<SQLTCHAR> connOut(1024);
       
  1894     memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
  1793     r = SQLDriverConnect(d->hDbc,
  1895     r = SQLDriverConnect(d->hDbc,
  1794                           NULL,
  1896                           NULL,
  1795 #ifdef UNICODE
  1897 #ifdef UNICODE
  1796                           (SQLWCHAR*)connQStr.unicode(),
  1898                           toSQLTCHAR(connQStr).data(),
  1797 #else
  1899 #else
  1798                           (SQLCHAR*)connQStr.toLatin1().constData(),
  1900                           (SQLCHAR*)connQStr.toUtf8().data(),
  1799 #endif
  1901 #endif
  1800                           (SQLSMALLINT)connQStr.length(),
  1902                           (SQLSMALLINT)connQStr.length(),
  1801                           connOut,
  1903                           connOut.data(),
  1802                           1024,
  1904                           1024,
  1803                           &cb,
  1905                           &cb,
  1804                           SQL_DRIVER_NOPROMPT);
  1906                           /*SQL_DRIVER_NOPROMPT*/0);
       
  1907 
  1805     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
  1908     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
  1806         setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
  1909         setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
  1807         setOpenError(true);
  1910         setOpenError(true);
  1808         return false;
  1911         return false;
  1809     }
  1912     }
  1884                     (SQLPOINTER)&fFunc,
  1987                     (SQLPOINTER)&fFunc,
  1885                     sizeof(fFunc),
  1988                     sizeof(fFunc),
  1886                     NULL);
  1989                     NULL);
  1887     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)) {
  1888         unicode = true;
  1991         unicode = true;
       
  1992         return;
  1889     }
  1993     }
  1890 
  1994 
  1891     r = SQLGetInfo(hDbc,
  1995     r = SQLGetInfo(hDbc,
  1892                     SQL_CONVERT_VARCHAR,
  1996                     SQL_CONVERT_VARCHAR,
  1893                     (SQLPOINTER)&fFunc,
  1997                     (SQLPOINTER)&fFunc,
  1894                     sizeof(fFunc),
  1998                     sizeof(fFunc),
  1895                     NULL);
  1999                     NULL);
  1896     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)) {
  1897         unicode = true;
  2001         unicode = true;
       
  2002         return;
  1898     }
  2003     }
  1899 
  2004 
  1900     r = SQLGetInfo(hDbc,
  2005     r = SQLGetInfo(hDbc,
  1901                     SQL_CONVERT_LONGVARCHAR,
  2006                     SQL_CONVERT_LONGVARCHAR,
  1902                     (SQLPOINTER)&fFunc,
  2007                     (SQLPOINTER)&fFunc,
  1903                     sizeof(fFunc),
  2008                     sizeof(fFunc),
  1904                     NULL);
  2009                     NULL);
  1905     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)) {
  1906         unicode = true;
  2011         unicode = true;
  1907     }
  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);
  1908 }
  2031 }
  1909 
  2032 
  1910 bool QODBCDriverPrivate::checkDriver() const
  2033 bool QODBCDriverPrivate::checkDriver() const
  1911 {
  2034 {
  1912 #ifdef ODBC_CHECK_DRIVER
  2035 #ifdef ODBC_CHECK_DRIVER
  1975 }
  2098 }
  1976 
  2099 
  1977 void QODBCDriverPrivate::checkSqlServer()
  2100 void QODBCDriverPrivate::checkSqlServer()
  1978 {
  2101 {
  1979     SQLRETURN   r;
  2102     SQLRETURN   r;
  1980     char serverString[200];
  2103     QVarLengthArray<SQLTCHAR> serverString(200);
  1981     SQLSMALLINT t;
  2104     SQLSMALLINT t;
       
  2105     memset(serverString.data(), 0, serverString.size() * sizeof(SQLTCHAR));
  1982 
  2106 
  1983     r = SQLGetInfo(hDbc,
  2107     r = SQLGetInfo(hDbc,
  1984                    SQL_DBMS_NAME,
  2108                    SQL_DBMS_NAME,
  1985                    serverString,
  2109                    serverString.data(),
  1986                    sizeof(serverString),
  2110                    serverString.size() * sizeof(SQLTCHAR),
  1987                    &t);
  2111                    &t);
  1988     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
  2112     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
  1989         QString serverType;
  2113         QString serverType;
  1990 #ifdef UNICODE
  2114 #ifdef UNICODE
  1991         serverType = QString(reinterpret_cast<const QChar*>(serverString), t/sizeof(QChar));
  2115         serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR));
  1992 #else
  2116 #else
  1993         serverType = QString::fromLocal8Bit(serverString, t);
  2117         serverType = QString::fromUtf8((const char *)serverString.constData(), t);
  1994 #endif
  2118 #endif
  1995         isMySqlServer = serverType.contains(QLatin1String("mysql"), Qt::CaseInsensitive);
  2119         isMySqlServer = serverType.contains(QLatin1String("mysql"), Qt::CaseInsensitive);
  1996         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;
  1997     }
  2136     }
  1998 }
  2137 }
  1999 
  2138 
  2000 void QODBCDriverPrivate::checkHasSQLFetchScroll()
  2139 void QODBCDriverPrivate::checkHasSQLFetchScroll()
  2001 {
  2140 {
  2007     }
  2146     }
  2008 }
  2147 }
  2009 
  2148 
  2010 void QODBCDriverPrivate::checkHasMultiResults()
  2149 void QODBCDriverPrivate::checkHasMultiResults()
  2011 {
  2150 {
  2012     char driverResponse[4];
  2151     QVarLengthArray<SQLTCHAR> driverResponse(2);
  2013     SQLSMALLINT length;
  2152     SQLSMALLINT length;
  2014     SQLRETURN r = SQLGetInfo(hDbc,
  2153     SQLRETURN r = SQLGetInfo(hDbc,
  2015                              SQL_MULT_RESULT_SETS,
  2154                              SQL_MULT_RESULT_SETS,
  2016                              driverResponse,
  2155                              driverResponse.data(),
  2017                              sizeof(driverResponse),
  2156                              driverResponse.size() * sizeof(SQLTCHAR),
  2018                              &length);
  2157                              &length);
  2019     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
  2158     if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
  2020 #ifdef UNICODE
  2159 #ifdef UNICODE
  2021         hasMultiResultSets = QString(reinterpret_cast<const QChar*>(driverResponse), length/sizeof(QChar)).startsWith(QLatin1Char('Y'));
  2160         hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y'));
  2022 #else
  2161 #else
  2023         hasMultiResultSets = QString::fromLocal8Bit(driverResponse, length).startsWith(QLatin1Char('Y'));
  2162         hasMultiResultSets = QString::fromUtf8((const char *)driverResponse.constData(), length).startsWith(QLatin1Char('Y'));
  2024 #endif
  2163 #endif
  2025 }
  2164 }
  2026 
  2165 
  2027 QSqlResult *QODBCDriver::createResult() const
  2166 QSqlResult *QODBCDriver::createResult() const
  2028 {
  2167 {
  2132                    NULL,
  2271                    NULL,
  2133                    0,
  2272                    0,
  2134                    NULL,
  2273                    NULL,
  2135                    0,
  2274                    0,
  2136 #ifdef UNICODE
  2275 #ifdef UNICODE
  2137                    (SQLWCHAR*)joinedTableTypeString.unicode(),
  2276                    toSQLTCHAR(joinedTableTypeString).data(),
  2138 #else
  2277 #else
  2139                    (SQLCHAR*)joinedTableTypeString.toLatin1().constData(),
  2278                    (SQLCHAR*)joinedTableTypeString.toUtf8().data(),
  2140 #endif
  2279 #endif
  2141                    joinedTableTypeString.length() /* characters, not bytes */);
  2280                    joinedTableTypeString.length() /* characters, not bytes */);
  2142 
  2281 
  2143     if (r != SQL_SUCCESS)
  2282     if (r != SQL_SUCCESS)
  2144         qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
  2283         qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
  2147         r = SQLFetchScroll(hStmt,
  2286         r = SQLFetchScroll(hStmt,
  2148                            SQL_FETCH_NEXT,
  2287                            SQL_FETCH_NEXT,
  2149                            0);
  2288                            0);
  2150     else
  2289     else
  2151         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     }
  2152 
  2296 
  2153     while (r == SQL_SUCCESS) {
  2297     while (r == SQL_SUCCESS) {
  2154         QString fieldVal = qGetStringData(hStmt, 2, -1, false);
  2298         QString fieldVal = qGetStringData(hStmt, 2, -1, false);
  2155         tl.append(fieldVal);
  2299         tl.append(fieldVal);
  2156 
  2300 
  2206                         SQL_ATTR_CURSOR_TYPE,
  2350                         SQL_ATTR_CURSOR_TYPE,
  2207                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2351                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2208                         SQL_IS_UINTEGER);
  2352                         SQL_IS_UINTEGER);
  2209     r = SQLPrimaryKeys(hStmt,
  2353     r = SQLPrimaryKeys(hStmt,
  2210 #ifdef UNICODE
  2354 #ifdef UNICODE
  2211                         catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),
  2355                         catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
  2212 #else
  2356 #else
  2213                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toLatin1().constData(),
  2357                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
  2214 #endif
  2358 #endif
  2215                         catalog.length(),
  2359                         catalog.length(),
  2216 #ifdef UNICODE
  2360 #ifdef UNICODE
  2217                         schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),
  2361                         schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
  2218 #else
  2362 #else
  2219                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toLatin1().constData(),
  2363                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
  2220 #endif
  2364 #endif
  2221                         schema.length(),
  2365                         schema.length(),
  2222 #ifdef UNICODE
  2366 #ifdef UNICODE
  2223                         (SQLWCHAR*)table.unicode(),
  2367                         toSQLTCHAR(table).data(),
  2224 #else
  2368 #else
  2225                         (SQLCHAR*)table.toLatin1().constData(),
  2369                         (SQLCHAR*)table.toUtf8().data(),
  2226 #endif
  2370 #endif
  2227                         table.length() /* in characters, not in bytes */);
  2371                         table.length() /* in characters, not in bytes */);
  2228 
  2372 
  2229     // if the SQLPrimaryKeys() call does not succeed (e.g the driver
  2373     // if the SQLPrimaryKeys() call does not succeed (e.g the driver
  2230     // 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
  2231     // the primary index (e.g MS Access and FoxPro)
  2375     // the primary index (e.g MS Access and FoxPro)
  2232     if (r != SQL_SUCCESS) {
  2376     if (r != SQL_SUCCESS) {
  2233             r = SQLSpecialColumns(hStmt,
  2377             r = SQLSpecialColumns(hStmt,
  2234                         SQL_BEST_ROWID,
  2378                         SQL_BEST_ROWID,
  2235 #ifdef UNICODE
  2379 #ifdef UNICODE
  2236                         catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),
  2380                         catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
  2237 #else
  2381 #else
  2238                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toLatin1().constData(),
  2382                         catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
  2239 #endif
  2383 #endif
  2240                         catalog.length(),
  2384                         catalog.length(),
  2241 #ifdef UNICODE
  2385 #ifdef UNICODE
  2242                         schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),
  2386                         schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
  2243 #else
  2387 #else
  2244                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toLatin1().constData(),
  2388                         schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
  2245 #endif
  2389 #endif
  2246                         schema.length(),
  2390                         schema.length(),
  2247 #ifdef UNICODE
  2391 #ifdef UNICODE
  2248                         (SQLWCHAR*)table.unicode(),
  2392                         toSQLTCHAR(table).data(),
  2249 #else
  2393 #else
  2250                         (SQLCHAR*)table.toLatin1().constData(),
  2394                         (SQLCHAR*)table.toUtf8().data(),
  2251 #endif
  2395 #endif
  2252                         table.length(),
  2396                         table.length(),
  2253                         SQL_SCOPE_CURROW,
  2397                         SQL_SCOPE_CURROW,
  2254                         SQL_NULLABLE);
  2398                         SQL_NULLABLE);
  2255 
  2399 
  2331                         SQL_ATTR_CURSOR_TYPE,
  2475                         SQL_ATTR_CURSOR_TYPE,
  2332                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2476                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
  2333                         SQL_IS_UINTEGER);
  2477                         SQL_IS_UINTEGER);
  2334     r =  SQLColumns(hStmt,
  2478     r =  SQLColumns(hStmt,
  2335 #ifdef UNICODE
  2479 #ifdef UNICODE
  2336                      catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),
  2480                      catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
  2337 #else
  2481 #else
  2338                      catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toLatin1().constData(),
  2482                      catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(),
  2339 #endif
  2483 #endif
  2340                      catalog.length(),
  2484                      catalog.length(),
  2341 #ifdef UNICODE
  2485 #ifdef UNICODE
  2342                      schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),
  2486                      schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
  2343 #else
  2487 #else
  2344                      schema.length() == 0 ? NULL : (SQLCHAR*)schema.toLatin1().constData(),
  2488                      schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(),
  2345 #endif
  2489 #endif
  2346                      schema.length(),
  2490                      schema.length(),
  2347 #ifdef UNICODE
  2491 #ifdef UNICODE
  2348                      (SQLWCHAR*)table.unicode(),
  2492                      toSQLTCHAR(table).data(),
  2349 #else
  2493 #else
  2350                      (SQLCHAR*)table.toLatin1().constData(),
  2494                      (SQLCHAR*)table.toUtf8().data(),
  2351 #endif
  2495 #endif
  2352                      table.length(),
  2496                      table.length(),
  2353                      NULL,
  2497                      NULL,
  2354                      0);
  2498                      0);
  2355     if (r != SQL_SUCCESS)
  2499     if (r != SQL_SUCCESS)