From f869a12c1043271b2ce8987b07a863ba3c78d6c9 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Thu, 12 Apr 2012 22:26:08 +0200 Subject: [PATCH] QTBUG-18435 fix stored procedure output parameters on ODBC 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 Reviewed-by: Mark Brand --- src/sql/drivers/odbc/qsql_odbc.cpp | 11 ++++---- tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp | 32 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index 70471d0..9b1b7fa 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -1502,8 +1502,9 @@ bool QODBCResult::exec() int strSize = str.length() * sizeof(SQLTCHAR); if (bindValueType(i) & QSql::Out) { - QVarLengthArray ba(toSQLTCHAR(str)); - ba.reserve(str.capacity()); + QVarLengthArray 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 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; } diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index e73ce79..36ac9de 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -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 ); -- 2.7.4