我正在编写一个ODBC数据库类,其中包含一个成员函数,用于从给定查询中获取一系列属性和元组。
我在下面的语句中只有一行代码会导致运行时错误在调试模式下抛出:
Unhandled exception at <mem loc> in <prog name>: 0xC0000005: Access violation writing location <mem loc>.
以下是ERROR
指出违规行的代码:
SQLINTEGER length = 0;
vector<vector<string>> data;
this->sReturn = SQLFetch(this->sHandle);
while (this->sReturn == SQL_SUCCESS) {
vector<string> tuple;
for (int i = 0; i < columnCount; i++) {
SQLPOINTER value = "";
switch (info[i].columnType) {
case 0 : //SQL_UNKNOWN_TYPE
throw DatabaseAttributeTypeUnknown("The database returned an attribute of an unknown type.");
break;
case 1 : //SQL_CHAR
this->sReturn = SQLGetData(this->sHandle, i + 1, info[i].columnType, value,
info[i].columnSize*sizeof(SQLCHAR),
ERROR &length);
break;
//Some more cases
}
}
有关为什么会抛出此错误的任何想法?以下是MSDN documentation on SQLGetData(),即为length
分配值。
感谢您的时间。
答案 0 :(得分:1)
当编译器将可执行代码映射到源代码中的代码行时,它们通常无法区分分成多行的语句中的行。因此,如果调试器说特定行发生错误,它实际上可以在整个语句中的任何位置,所以在某处:
this->sReturn = SQLGetData(this->sHandle, i + 1, info[i].columnType, value,
info[i].columnSize*sizeof(SQLCHAR),
&length);
这里唯一不稳定的指针是value
,它指向一个空的静态字符串,所以指向包含空字节的一个字符长的数组。此外,根据编译器选项,此数组可以位于只读数据段中。虽然SQLGetData()认为它指向一个大小至少为info[i].columnSize*sizeof(SQLCHAR)
个字节的位置,并且它将从SQL列中写入(不读取)数据。
我可能会错过其他细节,但我的第一个猜测是导致内存访问违规的原因。
答案 1 :(得分:0)
除了弗雷德里克所说的。你在64位编译代码吗?如果是这样,您将发现SQLGetData为最后一个参数而不是SQLINTEGER获取指向SQLLEN的指针:
SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
SQLPOINTER TargetValue, SQLLEN BufferLength,
SQLLEN *StrLen_or_Ind);
SQLLEN是64位窗口中的8个字节,而不是4个字节,因为SQLINTEGER是。