Description:
I use ODBC API in my project, When I specify the connection timeout and query timeout,it doesn't work!sometime my program will stop and wait for MyODBC return, but it doesn't return if my network was down or other problem!
so I write a test project to test it, I find that connection timeout always be 31536000 and query timeout is 0!
How to repeat:
just build the code and run it:
// TimeoutTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
//ODBC API
#include <sql.h>
#include <sqlext.h>
#include <odbcinst.h>
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"OdbcCP32.Lib")
int main(int argc, char* argv[])
{
SQLHENV hEnv; // Handle ODBC environment
SQLRETURN nRet; // result of functions
SQLHDBC hDBC; // Handle connection
SQLHSTMT hStmt; // Handle Statement
SQLUINTEGER nTimeout = 3; // Timeout
SQLCHAR nVersion = 0;
SQLCHAR pszSqlState[SQL_MAX_MESSAGE_LENGTH] = "";
SQLCHAR pszErrorMsg[SQL_MAX_MESSAGE_LENGTH] = "";
SQLINTEGER nNativeError = 0L;
SQLSMALLINT nErrorMsg = 0;
// 1. allocate Environment handle and register version
nRet = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&hEnv);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error AllocHandle\n");
return 0;
}
nRet = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_UINTEGER);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error SetEnv\n");
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 0;
}
nRet = SQLGetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)&nVersion, SQL_IS_INTEGER, NULL);
if ((nRet == SQL_SUCCESS) || (nRet == SQL_SUCCESS_WITH_INFO))
{
printf("ODBC Version is: %ld\n", nVersion);
}
else
{
printf("Error Get ODBC Version %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hEnv, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("Error %s (%d)\n State %s \n", pszErrorMsg, nErrorMsg, pszSqlState);
}
// 2. allocate connection handle, set timeout
nRet = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error AllocHDB %d\n", nRet);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 0;
}
nRet = SQLSetConnectAttr(hDBC, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)nTimeout, SQL_IS_INTEGER);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error SetConnectAttr %d\n", nRet);
}
nRet = SQLGetConnectAttr(hDBC, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)&nTimeout, SQL_IS_INTEGER, NULL);
if ((nRet == SQL_SUCCESS) || (nRet == SQL_SUCCESS_WITH_INFO))
{
printf("Login Timeout is: %ld\n", nTimeout);
}
else
{
printf("Error Get Login Timeout %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hDBC, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("Error %s (%d)\n State %s \n", pszErrorMsg, nErrorMsg, pszSqlState);
}
// 3. Connect to the datasource "test"
nRet = SQLConnect(hDBC, (SQLCHAR*) "mysql", SQL_NTS,
(SQLCHAR*) "test", SQL_NTS,
(SQLCHAR*) "test", SQL_NTS);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error SQLConnect %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hDBC, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("%s (%d)\n", pszErrorMsg, nErrorMsg);
SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 0;
}
printf("Connected !\n");
nRet = SQLSetConnectAttr(hDBC, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)nTimeout, SQL_IS_INTEGER);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error SetConnectAttr %d\n", nRet);
}
nRet = SQLGetConnectAttr(hDBC, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)&nTimeout, SQL_IS_INTEGER, NULL);
if ((nRet == SQL_SUCCESS) || (nRet == SQL_SUCCESS_WITH_INFO))
{
printf("Connection timeout is: %ld\n", nTimeout);
}
else
{
printf("Error Get Connection timeout %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hDBC, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("Error %s (%d)\n State %s \n", pszErrorMsg, nErrorMsg, pszSqlState);
}
nRet = SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error AllocStatement %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hDBC, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("%s (%d)\n", pszErrorMsg, nErrorMsg);
SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 0;
}
nRet = SQLSetStmtAttr(hStmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)nTimeout, SQL_IS_UINTEGER);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error Set Query Timeout %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hDBC, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("Error %s (%d)\n State %s \n", pszErrorMsg, nErrorMsg, pszSqlState);
SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
return 0;
}
nRet = SQLGetStmtAttr(hStmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)&nTimeout, SQL_IS_UINTEGER, NULL);
if ((nRet != SQL_SUCCESS) && (nRet != SQL_SUCCESS_WITH_INFO))
{
printf("Error Get Query Timeout %d\n", nRet);
SQLGetDiagRec(SQL_HANDLE_DBC, hDBC, 1, pszSqlState, &nNativeError,
pszErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &nErrorMsg);
printf("Error %s (%d)\n State %s \n", pszErrorMsg, nErrorMsg, pszSqlState);
}
else
{
printf("Query Timeout is %d\n", nTimeout);
}
//.............................
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
SQLDisconnect(hDBC);
SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 0;
}
Suggested fix:
Make MyODBC throw an exception when the timeout elapses.