我正在使用 SQL Server 2022 的标准版。它有一个设置强制严格加密的附加选项。我在服务器端设置了相同的内容。
在客户端计算机上,使用 SSMS,我能够连接并访问数据库用户表。但我无法从 C++ 应用程序执行相同操作。以下是我正在尝试的示例代码:
auto pDatabase = new CDatabase();
CString connString = L"DRIVER={ODBC Driver 18 for SQL Server};Network=DBMSSOCN;DATABASE=TESTTDE;Encrypt=strict;TrustServerCertificate=no;HostNameInCertificate=10.100.200.300;Mars_Connection=yes;SERVER=10.100.200.300\\TDE,2144;UID=Supervisor;PWD=password;";
auto reply = pDatabase->OpenEx(connString, CDatabase::noOdbcDialog);
CStringArray userNameList;
CString strUserName;
CStringW strUserNameW;
CString SQLString = L"select * from TESTTDE.dbo.UserTable;";
CRecordset userRecords(pDatabase);
userRecords.Open(CRecordset::forwardOnly, SQLString, CRecordset::readOnly);
while (!userRecords.IsEOF())
{
userRecords.GetFieldValue(L"Name", strUserNameW);
strUserName = CW2A(strUserNameW.Trim());
userNameList.Add(strUserName.Trim());
userRecords.MoveNext();
}
userRecords.Close();
userRecords.Open
生成异常,我无法访问数据库。有人能解释一下吗?我可以尝试什么来解决这个问题?
我使用的是自签名证书。如果我使用强制加密而不在服务器上启用强制严格加密,它就可以正常工作。
客户端异常:
传入的表格数据流 (TDS) 协议流不正确。流意外结束。状态:28000,本机:4002,来源:[Microsoft][ODBC Driver 18 for SQL Server][SQL Server]
服务器日志:
SQL Server 或端点配置为仅接受严格(TDS 8.0 及以上)连接。连接已关闭。
有什么可以阻止使用严格加密的自签名证书吗?对于服务器端的相同设置,我能够从 SSMS 在客户端运行查询并检索表数据。只有从示例应用程序我才能连接但不能运行查询。
一些额外的观察:使用示例应用程序中的低级 SQL API,即使启用了强制严格加密,我也能够从服务器获取数据。相同的代码添加如下:
SQLHANDLE env;
SQLHANDLE dbc;
SQLHANDLE stmt;
SQLRETURN ret;
SQLWCHAR* connStr = (SQLWCHAR*)L"Driver={ODBC Driver 18 for SQL Server};Server=10.100.200.300\\TDE;Database=TESTTDE;Uid=Supervisor;Pwd=password;Encrypt=strict;";
// Allocate environment handle
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
if (ret == SQL_ERROR) {
std::wcerr << L"Error allocating environment handle." << std::endl;
return;
}
// Set the ODBC version environment attribute
ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
if (ret == SQL_ERROR) {
checkDiagnostic(env, SQL_HANDLE_ENV);
SQLFreeHandle(SQL_HANDLE_ENV, env);
return;
}
// Allocate connection handle
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
if (ret == SQL_ERROR) {
checkDiagnostic(env, SQL_HANDLE_ENV);
SQLFreeHandle(SQL_HANDLE_ENV, env);
return;
}
// Connect to the data source
ret = SQLDriverConnectW(dbc, NULL, connStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
if (ret == SQL_ERROR) {
checkDiagnostic(dbc, SQL_HANDLE_DBC);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
return;
}
// Allocate statement handle
ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
if (ret == SQL_ERROR) {
checkDiagnostic(dbc, SQL_HANDLE_DBC);
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
return;
}
// Execute a query
SQLWCHAR* query = (SQLWCHAR*)L"SELECT * FROM UserTable";
ret = SQLExecDirectW(stmt, query, SQL_NTS);
if (ret == SQL_ERROR) {
checkDiagnostic(stmt, SQL_HANDLE_STMT);
}
else
{
SQLWCHAR name[256];
while (SQLFetch(stmt) == SQL_SUCCESS) {
ret = SQLGetData(stmt, 1, SQL_C_WCHAR, name, sizeof(name), NULL);
if (SQL_SUCCEEDED(ret)) {
AfxMessageBox((LPCTSTR)name);
}
}
}
// Clean up
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
我怀疑 MFC 类 API CRecordset::Open() 在支持 TDS 8.0 方面存在一些问题。