Details
-
Bug
-
Status: Closed (View Workflow)
-
Critical
-
Resolution: Fixed
-
3.0.2
-
None
-
Linux Centos 7.4.1708
Description
When a procedure returns more than 1 result set, fetching from the second result fails in SQLGetData().
The following SQL is used to set up the test:
CREATE OR REPLACE TABLE odbcbug(col1 INT, col2 INT); |
INSERT INTO odbcbug VALUES(1,2),(3,4),(5,6); |
delimiter //
|
CREATE OR REPLACE PROCEDURE odbcbugp1() |
BEGIN
|
SELECT col1, col2 FROM odbcbug; |
SELECT col1 FROM odbcbug; |
END; |
//
|
CREATE OR REPLACE PROCEDURE odbcbugp2() |
BEGIN
|
SELECT col1 FROM odbcbug; |
SELECT col1, col2 FROM odbcbug; |
END; |
//
|
And the following cod is used for testing:
#include <stdio.h>
|
#include <string.h>
|
#include <sqlext.h>
|
|
int main(int argc, char *argv[]) |
{
|
SQLHANDLE hEnv, hConn, hStmt;
|
SQLRETURN nRet;
|
SQLCHAR szConnStr[2048];
|
SQLCHAR szErrMsg[256];
|
SQLLEN nInd;
|
SQLSMALLINT nCols;
|
int i; |
SQLCHAR szSQLState[5];
|
SQLINTEGER nNativeErr;
|
SQLSMALLINT sLen;
|
SQLCHAR szDriverVer[256];
|
SQLCHAR *pSQL;
|
SQLCHAR szBuf[1024];
|
|
if(argc < 2) |
{
|
fprintf(stderr, "Usage: %s <SQL>\n", argv[0]); |
return 1; |
}
|
pSQL = argv[1];
|
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
|
SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); |
SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hConn);
|
|
strcpy(szConnStr, "DSN=MariaDB;UID=root;"); |
if((nRet = SQLDriverConnect(hConn, NULL, szConnStr, SQL_NTS, NULL, 0, |
&sLen, SQL_DRIVER_NOPROMPT)) != SQL_SUCCESS)
|
{
|
SQLError(hEnv, hConn, SQL_NULL_HSTMT, NULL, NULL, szErrMsg, sizeof(szErrMsg), NULL); |
fprintf(stderr, "Error in connecting to MariaDB:\n%s\n", szErrMsg); |
|
return 1; |
}
|
|
SQLAllocHandle(SQL_HANDLE_STMT, hConn, &hStmt);
|
if((nRet = SQLExecDirect(hStmt, pSQL, SQL_NTS)) != SQL_SUCCESS) |
{
|
SQLError(hEnv, hConn, hStmt, NULL, NULL, szErrMsg, sizeof(szErrMsg), NULL); |
fprintf(stderr, "Error in connecting to MariaDB:\n%s\nin\n%s\n", szErrMsg, pSQL); |
|
return 1; |
}
|
|
for(;;) |
{
|
SQLNumResultCols(hStmt, &nCols);
|
printf("Num cols: %d\n", nCols); |
|
while((nRet = SQLFetch(hStmt)) == SQL_SUCCESS) |
{
|
for(i = 0; i < nCols; i++) |
{
|
if((nRet = SQLGetData(hStmt, i + 1, SQL_C_CHAR, szBuf, sizeof(szBuf), |
&nInd)) != SQL_SUCCESS)
|
{
|
SQLError(hEnv, hConn, hStmt, NULL, NULL, szErrMsg, sizeof(szErrMsg), NULL); |
fprintf(stderr, "Error in SQLGetData:\n%s\n", szErrMsg); |
|
return 1; |
}
|
printf("Col: %d = /%s/\n", i + 1, nInd == SQL_NULL_DATA ? "null" : ((char *) szBuf)); |
}
|
}
|
|
if(nRet != SQL_NO_DATA) |
{
|
SQLError(hEnv, hConn, hStmt, NULL, NULL, szErrMsg, sizeof(szErrMsg), NULL); |
fprintf(stderr, "Error in SQLFetch:\n%s\n", szErrMsg); |
|
return 1; |
}
|
|
if((nRet = SQLMoreResults(hStmt)) != SQL_SUCCESS) |
{
|
if(nRet == SQL_NO_DATA) |
{
|
printf("No more results\n"); |
break; |
}
|
SQLError(hEnv, hConn, hStmt, szSQLState, &nNativeErr, szErrMsg, sizeof(szErrMsg), |
&sLen) ;
|
fprintf(stderr, "Err: %d SQL State: %5.5s\n", nRet, szSQLState); |
fprintf(stderr, "Native Error: %d\n", nNativeErr); |
fprintf(stderr, "Error in SQLMoreResults:\n%s\n", szErrMsg); |
|
return 1; |
}
|
}
|
return 0; |
}
|
With the above program compiled:
$ ./odbcbug "call odbcbugp1" |
Num cols: 2
|
Col: 1 = /1/ |
Col: 2 = /2/ |
Col: 1 = /3/ |
Col: 2 = /4/ |
Col: 1 = /5/ |
Col: 2 = /6/ |
Num cols: 1
|
Col: 1 = /1/ |
Col: 1 = /3/ |
Col: 1 = /5/ |
No more results |
$ ./odbcbug "call odbcbugp2" |
Num cols: 1
|
Col: 1 = /1/ |
Col: 1 = /3/ |
Col: 1 = /5/ |
Num cols: 2
|
Col: 1 = /1/ |
Segmentation fault (core dumped)
|
Note that this only fails when using ODBC 3.0.2, when running with 2.0.15 is works as expected.