VC6 MFC程序通过ODBC连接SQL Server 2016无法获取全表列问题
我之前维护旧VC6 MFC程序时也碰到过类似的ODBC兼容性坑,结合你的情况,给你几个具体的排查和解决方向:
检查ODBC驱动版本与位数
VC6默认编译32位程序,而SQL Server 2016的新驱动分32位和64位版本。如果你的系统是64位,可能误装了64位ODBC驱动,导致32位的VC6程序无法正确获取元数据。建议卸载现有驱动,安装32位的ODBC Driver 17 for SQL Server(适配SQL Server 2016的稳定版本),然后重新配置ODBC数据源(要在C:\Windows\SysWOW64\odbcad32.exe里打开32位数据源管理器配置)。验证SQLColumns的参数正确性
SQL Server对对象的命名规则(比如所有者前缀dbo.)比Access和Postgres更严格。MFC的RecordSet调用SQLColumns时,如果没有指定正确的数据库和所有者参数,可能返回空结果集。你可以手动在ODBC测试工具里执行以下SQL语句验证:EXEC sp_columns @table_name = '你的表名', @table_owner = 'dbo', @table_qualifier = '你的数据库名'如果这条语句能返回列信息,说明你代码里的
SQLColumns参数缺失了必要的前缀,需要在调用时补充完整的表标识(比如把表名从MyTable改成dbo.MyTable,或者在RecordSet的初始化时指定数据库和所有者)。绕过MFC封装,直接用ODBC API测试
旧版本MFC的AllocAndCacheFieldInfo()和AllocRowset()对新ODBC驱动返回的元数据格式可能处理不当。你可以写一段测试代码,直接调用ODBC API执行SQLColumns,看是否能拿到结果:CDatabase db; if (db.Open(_T("你的ODBC数据源名称"))) { HSTMT hStmt = NULL; SQLAllocStmt(db.m_hdbc, &hStmt); // 指定完整的表参数:数据库、所有者、表名 SQLColumns(hStmt, (SQLCHAR*)_T("你的数据库名"), SQL_NTS, (SQLCHAR*)_T("dbo"), SQL_NTS, (SQLCHAR*)_T("你的表名"), SQL_NTS, NULL, 0); SQLRETURN ret = SQLFetch(hStmt); if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) { // 读取第一列的名称(SQLColumns结果集的第4列是列名) SQLCHAR colName[256] = {0}; SQLGetData(hStmt, 4, SQL_C_CHAR, colName, sizeof(colName), NULL); TRACE(_T("获取到列名:%s\n"), colName); } else { TRACE(_T("SQLColumns返回空结果\n")); } SQLFreeStmt(hStmt, SQL_DROP); db.Close(); }如果这段代码能正常获取列信息,说明问题出在MFC RecordSet的封装逻辑上。你可以考虑替换MFC的RecordSet元数据读取部分为直接ODBC调用,或者修改MFC源码中
AllocAndCacheFieldInfo的处理逻辑(比如调整字段索引的映射)。检查SQL Server数据库的兼容性级别
尝试将SQL Server 2016目标数据库的兼容性级别调低到SQL Server 2008或更早版本(比如兼容SQL Server 2005),旧版本的元数据返回格式可能更适配VC6的MFC代码。你可以在SQL Server Management Studio中执行以下语句修改:ALTER DATABASE 你的数据库名 SET COMPATIBILITY_LEVEL = 100; -- 100对应SQL Server 2008验证登录账号的权限
确保ODBC数据源使用的SQL Server登录账号具有读取系统视图INFORMATION_SCHEMA.COLUMNS和sys.columns的权限。虽然Access能连接表,但Access可能用了不同的权限路径,而MFC的SQLColumns依赖这些系统视图的读取权限。
内容的提问来源于stack exchange,提问作者Mõbius

