我正在构建一个使用ODBC连接到MS SQL Server 2008的应用程序。它会自动检测列的类型,长度(如果适用),分配用于获取的缓冲区,并在不再需要时释放它们。我需要有关例如确切长度的信息。 varchar列,所以我发出一个命令,只为SQLDescribeCol
之后的每一列{ - 1}}。
问题
发出查询时:
SQLExecute
我收到来自select 'F'
的回复,该列没有名称且长度为1.我分配1 + 1个wchars的缓冲区并调用SQLDescribeCol
,返回{{1} }}。错误状态和文本是SQLFetch
和SQL_SUCCESS_WITH_INFO
,并且在获取后没有数据在缓冲区中。在获取之前我使用01004
,其中最后一个参数是指向整数的指针,它在获取字符串后保存字符串的长度。它的价值是2.当我改变F' F' F' F'为了' FFF',结果字符串长度扩展为6.五个字符文本的大小为10.这意味着我写的字符的两倍。
直接从列中提取的长缓冲区不会发生这种情况。 ColLength +一个wchar(用于null终止符)就足够了。
随笔
这与字符witdh有什么关系吗?我发出的所有查询都是用wchars编写的,数据库整理是POLISH_CI_AS(我不知道MSSQL是否还有其他属性而不是整理,例如字符宽度或沿着这些行的任何东西)。虽然当我改变分配器功能以分配两倍于所需的wchars时,我得到了正确的数据(我的意思是我得到那么少的' F'并且在那个' F& #39;,它应该是的地方。
请指教。有什么办法可以避免分配两倍于我需要的内存吗?
编辑 - 代码示例
String data, right truncated
我希望这个例子能够以某种方式描述我的情况。这是我为此目的而写的一个类,所以这里可能看不到一些(de-)分配或初始化。总而言之,我在SQLBindCol
返回的列大小与short resultavail=0;
SQLHSTMT hstmt = NULL;
cResultColMetaData rcm; //class defined elsewhere, holds info about a column
//handle allocations, and all that's required to connect is not included
SQLRETURN retcode = SQLPrepare(hstmt, L"SELECT 'F'", SQL_NTS); //success
retcode = SQLNumParams (hstmt, &numParams); //success, no parameters
retcode = SQLExecute(hstmt); //success
retcode = SQLNumResultCols(hstmt, &resultavail); //success, resultavail holds "1"
wchar_t CName[200]; CName[0]=(wchar_t)0;
SQLSMALLINT howmuch=0;
retcode = SQLDescribeCol(hstmt, i+1, CName, 200, &howmuch, &rcm.type, &rcm.colsize, &rcm.decdigits, &rcm.nullable);
//success, at this point rcm.type is varchar and rcm.colsize is 1. I allocate a buffer
switch(rcm.type){
//(...)
case SQL_VARCHAR:
{
int sizev = rcm.colsize+1;
wchar_t *str = new wchar_t[sizev];
SQLINTEGER x = 0; //initialized to zero
retcode = SQLBindCol(hstmt, 1, SQL_C_WCHAR, str, sizev, &x); //success
}
}
retcode = SQLFetch(hstmt); //result = SQL_SUCCESS_WITH_INFO,
//variable x now holds 2, no data in str buffer.
在SQLDescribeCol
变量中返回的内容之间存在差异。
请帮我确定原因。
答案 0 :(得分:1)
我重新阅读了SQLBindCol
上的MSDN文档,我找到了原因。我使用的是wchars,因此我报告的函数SQLBindCol
的缓冲区长度应该乘以sizeof(wchar_t),因为此参数位于 BYTES < / strong>,而不是字符。
早些时候,我写过直接从列获取的长缓冲区不会发生这种情况。这个说法不正确。问题只是没有显示出来。当SQLDescribeCol
返回MAX列大小时,而不是它的ACTUAL数据字符长度,此时甚至不知道(在提取之前)。所以我一直在分配足够的缓冲区,只将其中的一半报告给SQLBindCol
。如果我检索的其他字符串数据超过MAX列大小的一半,我会更早地发现这个问题,并且可能不会浪费我调试它的时间。