Bug #107307 | Inaccurate query result using SQLBindCol for SQL_C_DOUBLE type | ||
---|---|---|---|
Submitted: | 16 May 2022 16:42 | Modified: | 13 Jun 2022 19:49 |
Reporter: | Stephen Lin | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | Connector / ODBC | Severity: | S1 (Critical) |
Version: | 8.0.27 | OS: | Windows |
Assigned to: | CPU Architecture: | Any |
[16 May 2022 16:42]
Stephen Lin
[16 May 2022 16:43]
Stephen Lin
Update buy title
[17 May 2022 13:02]
Bogdan Degtyariov
Thank you for reporting an issue in Connector/ODBC. First and most important is this: SQLINTEGER ind = 0; RetCode = SQLBindCol(hStmt, 1, SQL_C_DOUBLE, (SQLPOINTER)&value, 0, (SQLLEN*)&ind); The above code will most likely cause buffer overrun and all sorts of unpredictable behavior because a 32-bit SQLINTEGER variable ind is used as 64-bit SQLLEN buffer. I need to check how it works with the correct buffer when `ind` variable is declared as SQLLEN ind = 0;
[17 May 2022 13:12]
Bogdan Degtyariov
I was able to repeat the problem even with the correct index buffer. The bug is verified. The test code is as this: DECLARE_TEST(t_bug107307) { SQLCHAR buff[128]; SQLRETURN rc; double value = 0; SQLLEN ind = 0; DECLARE_BASIC_HANDLES(henv1, hdbc1, hstmt1); alloc_basic_handles_with_opt(&henv1, &hdbc1, &hstmt1, NULL, NULL, NULL, NULL, "OPTION=1048576"); ok_sql(hstmt1, "DROP TABLE IF EXISTS t_bug107307"); ok_sql(hstmt1, "CREATE TABLE t_bug107307 (num0 DOUBLE)"); ok_sql(hstmt1, "INSERT INTO t_bug107307 VALUES (12.3), (-12.3), (15.7)," "(-15.7), (3.5), (-3.5), (0), (NULL), (10)"); ok_stmt(hstmt1, SQLPrepare(hstmt1, "SELECT * FROM t_bug107307", SQL_NTS)); ok_stmt(hstmt, SQLExecute(hstmt1)); ok_stmt(hstmt1, SQLBindCol(hstmt1, 1, SQL_C_DOUBLE, (SQLPOINTER)&value, 0, &ind)); for (int i = 0; ; i++) { rc = SQLFetch(hstmt1); if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { if (ind <= 0) { printf("Record %d: %s\n", i + 1, "NULL"); } else { printf("Record %d: %f\n", i + 1, value); } } else { if (rc != SQL_NO_DATA) { printf("Error\n"); } else { break; } } } ok_sql(hstmt1, "DROP TABLE IF EXISTS t_bug107307"); free_basic_handles(&henv1, &hdbc1, &hstmt1); return OK; } The output is Record 1: 12.330000 Record 2: -12.300000 Record 3: 15.700000 Record 4: -15.700000 Record 5: 3.500000 Record 6: -3.500000 Record 7: 0.000000 Record 8: NULL Record 9: 10.000000
[17 May 2022 20:15]
Stephen Lin
Bogdan, This defect and another defect I filed before were found when we run Tableau TDVT. Are you interested in running TDVT to test new MySQL ODBC driver releases? TDVT is publicly available on Github. I can help you set up if you are interested. https://tableau.github.io/connector-plugin-sdk/docs/tdvt Thanks, Stephen
[18 May 2022 12:24]
Bogdan Degtyariov
Posted by developer: A workaround for this problem: do not use option NO_CACHE=1 However, the incorrect handling of the result with NO_CACHE=1 must be fixed.
[3 Jun 2022 13:14]
Bogdan Degtyariov
Posted by developer: The problem is fixed. The patch is now pushed into the release branch. Now the type SQL_C_DOUBLE is returned correctly with NO_CACHE=1.
[13 Jun 2022 19:49]
Philip Olson
Posted by developer: Fixed as of the upcoming MySQL Connector/ODBC 8.0.30 release, and here's the proposed changelog entry from the documentation team: The SQL_C_DOUBLE type could return as an inaccurate result with NO_CACHE enabled. Thank you for the bug report.