C++ msodbcsql17 SQLConnect 挂起
C++ msodbcsql17 SQLConnect hangs
我们有一个 C++ 应用程序,它使用 ODBC 连接到 SQL 服务器数据库。在CentOS 7应用服务器上是运行。它与 msodbcsql17 版本 17.4.2.1-1 完美配合,但与版本 17.6.1.1-1 一起中断。你能告诉我为什么吗?相关代码如下:
#include "DBODBC.h"
#include "ODBCResultSet.h"
#include <sqlext.h>
#include <sqlncli.h>
/* ----------------------------------------------------------------------------- */
/** Creates environment handle and sets ODBC version
* /returns True if intialization succeeds, false otherwise
*/
/* ----------------------------------------------------------------------------- */
bool DBODBC::Init()
{
DB::Init();
if (!Check(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_Env), m_Env,SQL_HANDLE_ENV ))
{
LOG_E("DBODBC::Init - Failed to create environment handle");
return false;
};
if (!Check(SQLSetEnvAttr(m_Env,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,0), m_Env,SQL_HANDLE_ENV))
{
LOG_E("DBODBC::Init - Failed to set ODBC version");
return false;
};
return true;
}
/* ----------------------------------------------------------------------------- */
/** Creates a connection to the database based on the parameters passed
* /param user Null terminated string containing username to be used to connect to the DB
* /param password Null terminated string containing password to be used to connect to the DB
* /param DBName Null terminated string containing ODBC datasource name of the DB to connect to
* /returns True if succeeded to connect to the DB, false otherwise
*/
/* ----------------------------------------------------------------------------- */
bool DBODBC::Connect(const char * user, const char * password, const char * DBName)
{
LOG_I(2, "DBODBC::Connect - Started");
if (IsConnected())
{
LOG_I(5, "DBODBC::Connect - DB connection is already up");
return false;
}
//allocate connection handle
if (SQLAllocHandle(SQL_HANDLE_DBC, m_Env, &m_Conn)==SQL_ERROR)
{
LOG_W("DBODBC::Connect - Failed to allocate connection handle");
return false;
}
SQLSetConnectAttr(m_Conn, SQL_COPT_SS_MARS_ENABLED, (SQLPOINTER)SQL_MARS_ENABLED_YES, SQL_IS_UINTEGER);
LOG_I(2, "DBODBC::Connect - Calling SQLConnect");
if (!Check(SQLConnect(m_Conn, (SQLCHAR*)DBName, SQL_NTS,(SQLCHAR*)user,SQL_NTS, (SQLCHAR*)password, SQL_NTS), m_Conn, SQL_HANDLE_DBC))
{
LOG_W("DBODBC::Connect - Failed to open connection to datasource \"%s\"", DBName);
return false;
}
LOG_I(5, "DBODBC::Connect - Successfully connected to %s", DBName);
m_bConnectionOk=true;
m_bIsConnected=true;
return true;
}
/* ----------------------------------------------------------------------------- */
/** Checks value returned by ODBC and collects diagnostic info if failed
*/
/* ----------------------------------------------------------------------------- */
bool DBODBC::Check(SQLRETURN RetCode, SQLHANDLE hHandle, SQLSMALLINT hType)
{
LOG_I(2, "DBODBC::Check - Started");
SQLSMALLINT iRec = 0;
SQLINTEGER iError;
SQLCHAR wszMessage[1000];
SQLCHAR wszState[SQL_SQLSTATE_SIZE+1];
bool retval;
switch (RetCode)
{
case SQL_SUCCESS_WITH_INFO:
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
wszState,
&iError,
wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
LOG_W("DBODBC::Check - [%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}
case SQL_SUCCESS:
return true;
case SQL_INVALID_HANDLE:
LOG_W("DBODBC::Check - SQL handle is invalid");
return false;
break;
case SQL_ERROR:
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
wszState,
&iError,
wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
LOG_W("DBODBC::Check - [%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}
return false;
break;
case SQL_NO_DATA:
//No data found, no need to log it, just return true;
return true;
break;
default:
LOG_W("DBODBC::Check - Unknown result %d", RetCode);
return false;
}
}
在日志中我可以看到它挂在 SQLConnect 方法调用上:
2073163264 - INFO (2) - [2020.12.11 15:13:10.728] - DBODBC::Check - Started
2073163264 - INFO (2) - [2020.12.11 15:13:10.728] - DBODBC::Check - Started
2073163264 - INFO (2) - [2020.12.11 15:13:10.729] - DBODBC::Init - Done
2073163264 - INFO (2) - [2020.12.11 15:13:10.729] - DBODBC::Connect - Started
2073163264 - INFO (2) - [2020.12.11 15:13:10.729] - DBODBC::Connect - Calling SQLConnect
此后不再记录,甚至 Check 方法中的“已启动”消息也未记录。根据 msodbcsql 文档 (https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function?view=sql-server-ver15),我们正确地使用了该库。此外,我在发行说明中找不到任何表明某些内容已更改的详细信息,我也应该升级我的应用程序。
编辑:
我删除了当前版本的msodbcsql17并安装了早期版本,甚至尝试了多个版本,它根本无法工作。我们有两台服务器,其中一台仍在 17.4.2.1-1 版本的 msodbcsql17 上,应用程序运行正常。其他服务器默认安装了新的17.6.1.1-1版本,应用无法运行,降级到17.4.2.1-1版本后无法运行
好吧,我似乎错过了我不知何故所做的一项检查:odbcinst.ini 实际上已经改变了!在 17.6 msodbc 安装期间,删除了一行。再次添加后,立即开始运行:
为什么删除了这一行,我不知道。或者,在全新安装的情况下,此行从未添加到 odbcinst.ini。不管怎样,现在可以了。
我们有一个 C++ 应用程序,它使用 ODBC 连接到 SQL 服务器数据库。在CentOS 7应用服务器上是运行。它与 msodbcsql17 版本 17.4.2.1-1 完美配合,但与版本 17.6.1.1-1 一起中断。你能告诉我为什么吗?相关代码如下:
#include "DBODBC.h"
#include "ODBCResultSet.h"
#include <sqlext.h>
#include <sqlncli.h>
/* ----------------------------------------------------------------------------- */
/** Creates environment handle and sets ODBC version
* /returns True if intialization succeeds, false otherwise
*/
/* ----------------------------------------------------------------------------- */
bool DBODBC::Init()
{
DB::Init();
if (!Check(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_Env), m_Env,SQL_HANDLE_ENV ))
{
LOG_E("DBODBC::Init - Failed to create environment handle");
return false;
};
if (!Check(SQLSetEnvAttr(m_Env,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,0), m_Env,SQL_HANDLE_ENV))
{
LOG_E("DBODBC::Init - Failed to set ODBC version");
return false;
};
return true;
}
/* ----------------------------------------------------------------------------- */
/** Creates a connection to the database based on the parameters passed
* /param user Null terminated string containing username to be used to connect to the DB
* /param password Null terminated string containing password to be used to connect to the DB
* /param DBName Null terminated string containing ODBC datasource name of the DB to connect to
* /returns True if succeeded to connect to the DB, false otherwise
*/
/* ----------------------------------------------------------------------------- */
bool DBODBC::Connect(const char * user, const char * password, const char * DBName)
{
LOG_I(2, "DBODBC::Connect - Started");
if (IsConnected())
{
LOG_I(5, "DBODBC::Connect - DB connection is already up");
return false;
}
//allocate connection handle
if (SQLAllocHandle(SQL_HANDLE_DBC, m_Env, &m_Conn)==SQL_ERROR)
{
LOG_W("DBODBC::Connect - Failed to allocate connection handle");
return false;
}
SQLSetConnectAttr(m_Conn, SQL_COPT_SS_MARS_ENABLED, (SQLPOINTER)SQL_MARS_ENABLED_YES, SQL_IS_UINTEGER);
LOG_I(2, "DBODBC::Connect - Calling SQLConnect");
if (!Check(SQLConnect(m_Conn, (SQLCHAR*)DBName, SQL_NTS,(SQLCHAR*)user,SQL_NTS, (SQLCHAR*)password, SQL_NTS), m_Conn, SQL_HANDLE_DBC))
{
LOG_W("DBODBC::Connect - Failed to open connection to datasource \"%s\"", DBName);
return false;
}
LOG_I(5, "DBODBC::Connect - Successfully connected to %s", DBName);
m_bConnectionOk=true;
m_bIsConnected=true;
return true;
}
/* ----------------------------------------------------------------------------- */
/** Checks value returned by ODBC and collects diagnostic info if failed
*/
/* ----------------------------------------------------------------------------- */
bool DBODBC::Check(SQLRETURN RetCode, SQLHANDLE hHandle, SQLSMALLINT hType)
{
LOG_I(2, "DBODBC::Check - Started");
SQLSMALLINT iRec = 0;
SQLINTEGER iError;
SQLCHAR wszMessage[1000];
SQLCHAR wszState[SQL_SQLSTATE_SIZE+1];
bool retval;
switch (RetCode)
{
case SQL_SUCCESS_WITH_INFO:
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
wszState,
&iError,
wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
LOG_W("DBODBC::Check - [%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}
case SQL_SUCCESS:
return true;
case SQL_INVALID_HANDLE:
LOG_W("DBODBC::Check - SQL handle is invalid");
return false;
break;
case SQL_ERROR:
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
wszState,
&iError,
wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
LOG_W("DBODBC::Check - [%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}
return false;
break;
case SQL_NO_DATA:
//No data found, no need to log it, just return true;
return true;
break;
default:
LOG_W("DBODBC::Check - Unknown result %d", RetCode);
return false;
}
}
在日志中我可以看到它挂在 SQLConnect 方法调用上:
2073163264 - INFO (2) - [2020.12.11 15:13:10.728] - DBODBC::Check - Started
2073163264 - INFO (2) - [2020.12.11 15:13:10.728] - DBODBC::Check - Started
2073163264 - INFO (2) - [2020.12.11 15:13:10.729] - DBODBC::Init - Done
2073163264 - INFO (2) - [2020.12.11 15:13:10.729] - DBODBC::Connect - Started
2073163264 - INFO (2) - [2020.12.11 15:13:10.729] - DBODBC::Connect - Calling SQLConnect
此后不再记录,甚至 Check 方法中的“已启动”消息也未记录。根据 msodbcsql 文档 (https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function?view=sql-server-ver15),我们正确地使用了该库。此外,我在发行说明中找不到任何表明某些内容已更改的详细信息,我也应该升级我的应用程序。
编辑:
我删除了当前版本的msodbcsql17并安装了早期版本,甚至尝试了多个版本,它根本无法工作。我们有两台服务器,其中一台仍在 17.4.2.1-1 版本的 msodbcsql17 上,应用程序运行正常。其他服务器默认安装了新的17.6.1.1-1版本,应用无法运行,降级到17.4.2.1-1版本后无法运行
好吧,我似乎错过了我不知何故所做的一项检查:odbcinst.ini 实际上已经改变了!在 17.6 msodbc 安装期间,删除了一行。再次添加后,立即开始运行:
为什么删除了这一行,我不知道。或者,在全新安装的情况下,此行从未添加到 odbcinst.ini。不管怎样,现在可以了。