http://www.easysoft.com/developer/languages/c/odbc_tutorial.html
我按照上面的教程使用 ODBC 查询 MSSQL 数据库。我让它工作了,现在我试图将它包装在一个 C++ 类中。我在以下代码块中看到了一些意外行为。
while (SQL_SUCCEEDED(ret = SQLFetch(stmt)))
{
vector<string> vRow;
// loop through columns
for (SQLUSMALLINT i = 1; i<= numCols; i++)
{
SQLINTEGER indicator;
char buf[500];
SQLRETURN data_ret;
data_ret = SQLGetData(stmt, i, SQL_C_CHAR, buf, sizeof(buf),
(SQLLEN*) &indicator); // <--- this call makes the first
// <--- entry of vRow disappear
if (SQL_SUCCEEDED(data_ret))
{
if (indicator == SQL_NULL_DATA)
{
strcpy(buf, "NULL");
}
vRow.push_back(string(buf)); // <--- This line seg faults
}
}
}
在第一次通过 for 循环时一切都很好,但在第二次通过时,我在执行 vRow.push_back(string(buf)); 时遇到分段错误。
单步执行 gdb 我发现问题实际上是由第二次调用 SQLGetData 引起的。执行该行后,我无法访问 vRow 的第一个元素。
(gdb) p vRow
$1 = std::vector of length 813681, capacity 813681 = {Cannot access memory at address 0x0
对我来说,这似乎 vRows 中的第一个条目是 buf 的浅拷贝,并且对 SQLGetData 的调用破坏了内存位置,但我读过的所有内容似乎都表明字符串进行了深拷贝。
我曾尝试将 buf 的深层副本“强制”成字符串,然后再将其推送到 vRow 上,但所有努力都表现出这种行为。
我正在使用带有这些标志的 g++ 进行编译 -std=c++0x -lboost_regex -lodbc
有人可以帮我弄清楚这里发生了什么吗?先感谢您。
更新 将指示变量从 SQLINTEGER 类型更改为 SQLLEN 修复了该问题。
在 sqltypes.h 头文件中,SQLLEN 是 long,但 SQLINTEGER 是 int。因此,对 SQLGetData 的调用本质上是将 long 转换为 int。