0

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。

4

2 回答 2

1

将指示变量从 SQLINTEGER 类型更改为 SQLLEN 解决了​​该问题。

在 sqltypes.h 头文件中,SQLLEN 是 long,但 SQLINTEGER 是 int。因此,对 SQLGetData 的调用本质上是将 long 转换为 int。

感谢大家的帮助。

于 2013-06-21T13:33:35.777 回答
0

确保在声明 buf 之后使用 '0' 对 bug 进行 memset。这样可以确保字符串末尾有一个反斜杠 0,并且不会导致 seg 错误。并确保传递 sizeof(buf)-1,因为最后一个字节需要为零,C 才能像字符串一样对待。

于 2013-06-20T13:48:54.040 回答