|
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.
|