Bug #15211 ODBC timeouts can't be change with MyODBC!
Submitted: 24 Nov 2005 3:08 Modified: 7 Mar 2007 8:00
Reporter: stavck guan Email Updates:
Status: Duplicate Impact on me:
None 
Category:Connector / ODBC Severity:S2 (Serious)
Version:3.51.12 OS:Windows (Window XP)
Assigned to: CPU Architecture:Any

[24 Nov 2005 3:08] stavck guan
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.
[24 Nov 2005 11:15] Vasily Kishkin
Thanks for the bug report and the test case. I was able to reproduce the bug. Results are:
ODBC Version is: 3
Login Timeout is: 3
Connected !
Connection timeout is: 31536000
Query Timeout is 0

Test case is attached.
[24 Nov 2005 11:16] Vasily Kishkin
Test case

Attachment: test.c (text/plain), 5.65 KiB.

[7 Mar 2007 8:00] Bogdan Degtyariov
fixed (rev. 236) 
see the bug#19823