QTBUG-18435 fix stored procedure output parameters on ODBC
authorMark Brand <mabrand@mabrand.nl>
Thu, 12 Apr 2012 20:26:08 +0000 (22:26 +0200)
committerQt by Nokia <qt-info@nokia.com>
Tue, 17 Apr 2012 21:16:51 +0000 (23:16 +0200)
Follow-up to c55a99965d8c08d5f924d49db4fe4aa49df8096.

3 problems prevented stored procedure output parameters from working.
- SQLBindParameter needs access to buffer provided by QByteArray.
- The length of the buffer is measured in bytes.
- A typo corrupted conversion back to QString.

Also, data() makes more sense than constData() to expose the buffer.

Task-Id: QTBUG-18435
Change-Id: I66444b13c0f584ed79bcf026e5a23caff83c22cb
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
Reviewed-by: Mark Brand <mabrand@mabrand.nl>
src/sql/drivers/odbc/qsql_odbc.cpp
tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp

index 70471d0..9b1b7fa 100644 (file)
@@ -1502,8 +1502,9 @@ bool QODBCResult::exec()
                     int strSize = str.length() * sizeof(SQLTCHAR);
 
                     if (bindValueType(i) & QSql::Out) {
-                        QVarLengthArray<SQLTCHAR> ba(toSQLTCHAR(str));
-                        ba.reserve(str.capacity());
+                        QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
+                        a.reserve(str.capacity());
+                        QByteArray ba((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
                         r = SQLBindParameter(d->hStmt,
                                             i + 1,
                                             qParamType[(QFlag)(bindValueType(i)) & QSql::InOut],
@@ -1511,10 +1512,10 @@ bool QODBCResult::exec()
                                             strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
                                             0, // god knows... don't change this!
                                             0,
-                                            (void *)ba.constData(),
+                                            (void *)ba.data(),
                                             ba.size(),
                                             ind);
-                        tmpStorage.append(QByteArray((const char *)ba.constData(), ba.size()*sizeof(SQLTCHAR)));
+                        tmpStorage.append(ba);
                         break;
                     }
                     QByteArray strba((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
@@ -1638,7 +1639,7 @@ bool QODBCResult::exec()
                         QByteArray first = tmpStorage.takeFirst();
                         QVarLengthArray<SQLTCHAR> array;
                         array.append((SQLTCHAR *)first.constData(), first.size());
-                        values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR*));
+                        values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
                     }
                     break;
                 }
index e73ce79..36ac9de 100644 (file)
@@ -211,6 +211,8 @@ private slots:
     void QTBUG_5765();
     void QTBUG_14132_data() { generic_data("QOCI"); }
     void QTBUG_14132();
+    void QTBUG_18435_data() { generic_data("QODBC"); }
+    void QTBUG_18435();
     void QTBUG_21884_data() { generic_data("QSQLITE"); }
     void QTBUG_21884();
     void QTBUG_16967_data() { generic_data("QSQLITE"); }
@@ -3024,6 +3026,36 @@ void tst_QSqlQuery::QTBUG_14132()
     QCOMPARE(q.boundValue(0).toString(), QLatin1String("OUTSTRING"));
 }
 
+void tst_QSqlQuery::QTBUG_18435()
+{
+    QFETCH(QString, dbName);
+    QSqlDatabase db = QSqlDatabase::database(dbName);
+    CHECK_DATABASE(db);
+
+    if (!db.driverName().startsWith("QODBC") || !tst_Databases::isSqlServer(db))
+        return;
+
+    QSqlQuery q(db);
+    QString procName(qTableName("qtbug_18435_proc", __FILE__));
+
+    q.exec("DROP PROCEDURE " + procName);
+    const QString stmt =
+    "CREATE PROCEDURE " + procName + " @key nvarchar(50) OUTPUT AS\n"
+    "BEGIN\n"
+    "  SET NOCOUNT ON\n"
+    "  SET @key = 'TEST'\n"
+    "END\n";
+
+    QVERIFY_SQL(q, exec(stmt));
+    QVERIFY_SQL(q, prepare("{CALL "+ procName +"(?)}"));
+    const QString testStr = "0123";
+    q.bindValue(0, testStr, QSql::Out);
+    QVERIFY_SQL(q, exec());
+    QCOMPARE(q.boundValue(0).toString(), QLatin1String("TEST"));
+
+    QVERIFY_SQL(q, exec("DROP PROCEDURE " + procName));
+}
+
 void tst_QSqlQuery::QTBUG_5251()
 {
     QFETCH( QString, dbName );