From b19372c11549bc1f88b3e59fa94745645503b8e6 Mon Sep 17 00:00:00 2001
From: Bill King <bill.king@nokia.com>
Date: Tue, 1 Sep 2009 13:08:02 +1000
Subject: Fixes determination of end of odbc string on deficient driver

Ported this fix backwards from 4.6 to 4.5
Adds some cleanups (using QVarLengthArray), and reverting to the
initial and correct calculation (when the driver doesn't deem fit to
return SQL_NO_DATA).
---
 src/sql/drivers/odbc/qsql_odbc.cpp           | 12 ++++----
 tests/auto/qsqldatabase/tst_qsqldatabase.cpp | 41 ++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp
index ae522ee..a5c713d 100644
--- a/src/sql/drivers/odbc/qsql_odbc.cpp
+++ b/src/sql/drivers/odbc/qsql_odbc.cpp
@@ -314,12 +314,12 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni
             colSize *= 2; // a tiny bit faster, since it saves a SQLGetData() call
         }
     }
-    char* buf = new char[colSize];
+    QVarLengthArray<char> buf(colSize);
     while (true) {
         r = SQLGetData(hStmt,
                         column+1,
                         unicode ? SQL_C_WCHAR : SQL_C_CHAR,
-                        (SQLPOINTER)buf,
+                        (SQLPOINTER)buf.data(),
                         colSize,
                         &lengthIndicator);
         if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
@@ -334,11 +334,12 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni
             // colSize-1: remove 0 termination when there is more data to fetch
             int rSize = (r == SQL_SUCCESS_WITH_INFO) ? (unicode ? colSize-2 : colSize-1) : lengthIndicator;
             if (unicode) {
-                fieldVal += QString((QChar*) buf, rSize / 2);
+                fieldVal += QString((const QChar*) buf.constData(), rSize / 2);
             } else {
-                fieldVal += QString::fromAscii(buf, rSize);
+                fieldVal += QString::fromAscii(buf.constData(), rSize);
             }
-            if (lengthIndicator - fieldVal.size() <= 0) {
+            memset(buf.data(), 0, colSize);
+            if (lengthIndicator < colSize) {
                 // workaround for Drivermanagers that don't return SQL_NO_DATA
                 break;
             }
@@ -350,7 +351,6 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni
             break;
         }
     }
-    delete[] buf;
     return fieldVal;
 }
 
diff --git a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp
index 782bff8..9ca48f5 100644
--- a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp
+++ b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp
@@ -180,6 +180,8 @@ private slots:
     void odbc_uintfield();
     void odbc_bindBoolean_data() { generic_data("QODBC"); }
     void odbc_bindBoolean();
+    void odbc_testqGetString_data() { generic_data("QODBC"); }
+    void odbc_testqGetString();
 
     void oci_serverDetach_data() { generic_data("QOCI"); }
     void oci_serverDetach(); // For task 154518
@@ -347,6 +349,7 @@ void tst_QSqlDatabase::dropTestTables(QSqlDatabase db)
             << qTableName("numericfields")
             << qTableName("qtest_ibaseblobs")
             << qTableName("qtestBindBool")
+            << qTableName("testqGetString")
             << qTableName("qtest_sqlguid")
             << qTableName("uint_table")
             << qTableName("uint_test")
@@ -2005,6 +2008,44 @@ void tst_QSqlDatabase::odbc_bindBoolean()
     QCOMPARE(q.value(1).toBool(), false);
 }
 
+void tst_QSqlDatabase::odbc_testqGetString()
+{
+    QFETCH(QString, dbName);
+    QSqlDatabase db = QSqlDatabase::database(dbName);
+    CHECK_DATABASE(db);
+
+    QSqlQuery q(db);
+    QVERIFY_SQL(q, exec("CREATE TABLE " + qTableName("testqGetString") + "(id int, vcvalue varchar(65538))"));
+
+    QString largeString;
+    largeString.fill('A', 65536);
+
+    // Bind and insert
+    QVERIFY_SQL(q, prepare("INSERT INTO " + qTableName("testqGetString") + " VALUES(?, ?)"));
+    q.bindValue(0, 1);
+    q.bindValue(1, largeString);
+    QVERIFY_SQL(q, exec());
+    q.bindValue(0, 2);
+    q.bindValue(1, largeString+QLatin1Char('B'));
+    QVERIFY_SQL(q, exec());
+    q.bindValue(0, 3);
+    q.bindValue(1, largeString+QLatin1Char('B')+QLatin1Char('C'));
+    QVERIFY_SQL(q, exec());
+
+    // Retrive
+    QVERIFY_SQL(q, exec("SELECT id, vcvalue FROM " + qTableName("testqGetString") + " ORDER BY id"));
+    QVERIFY_SQL(q, next());
+    QCOMPARE(q.value(0).toInt(), 1);
+    QCOMPARE(q.value(1).toString().length(), 65536);
+    QVERIFY_SQL(q, next());
+    QCOMPARE(q.value(0).toInt(), 2);
+    QCOMPARE(q.value(1).toString().length(), 65537);
+    QVERIFY_SQL(q, next());
+    QCOMPARE(q.value(0).toInt(), 3);
+    QCOMPARE(q.value(1).toString().length(), 65538);
+}
+
+
 void tst_QSqlDatabase::mysql_multiselect()
 {
     QFETCH(QString, dbName);
-- 
cgit v0.12