大对象获取数据

由于ODBC在设计之初就没有为大对象类型有专门设计接口,因此ODBC接口大对象的获取与普通数据类型基本一致,可以用普通数据类型绑定,也可以用SQLGetData方式动态获取。 如果采用普通数据类型去绑定,且想一次性获取完整的LOB数据,则需要分配足够大小的内存空间。

除非你确定LOB列的数据并不是很大,可以通过普通的字符串或者二进制方式获取;建议使用SQLGetData方式,因为SQLGetData是读取LOB数据是可以分片读取的,对内存的占用和会比较少。

备注:应用程序可以使用 SQLGetData(而不只是长数据)检索任何类型的数据,尽管只能在部分中检索字符和二进制数据。 但是,如果数据太小,足以容纳在单个缓冲区中,通常没有理由使用 SQLGetData。 将缓冲区绑定到列并让驱动程序返回缓冲区中的数据,这要简单得多。

若要从某一列检索长数据,应用程序首先调用 SQLFetchScroll 或 SQLFetch 移动到某一行,并提取绑定列的数据。 然后,应用程序调用 SQLGetData。 SQLGetData 具有与 SQLBindCol相同的参数:语句句柄、列号、变量的 C 数据类型、地址和字节长度、长度/指示器缓冲区的地址,因为它们实质上是相同的任务: 它们都描述了驱动程序的应用程序变量,并指定应在该变量中返回特定列的数据。

SQLGetData 在一个重要方面与 SQLFetch 不同。 如果对同一列连续调用此方法,则每次调用都将返回连续的数据部分。 数据没有读取完成时,SQLGetData调用会返回 SQL_SUCCESS_WITH_INFO ,状态码为SQLSTATE 01004 (字符串数据,右截断) , 此时一般会继续循环,获取下一片数据;调用返回 SQL_SUCCESS时,代表数据以及获取完成,此时可以退出获取数据的循环;返回SQL_NO_DATA,意味着没有更多要返回的数据。

每次读取的数据片都以'0'结束;应用程序在做数据拼接时必须删除 '0'终止字符。 对于可变长度书签以及其他长数据,可以在部分中检索数据。 在每次调用时,长度/指示器缓冲区中返回的值会减少上一个调用中返回的字节数,但驱动程序通常不能发现可用数据量并返回 SQL_NO_TOTAL 的字节长度。

例如

// 变量定义
SQLCHAR       BinaryPtr[5000];
SQLUINTEGER   PartID;
SQLINTEGER    PartIDInd, BinaryLenOrInd, NumBytes;
SQLRETURN     rc;
SQLHSTMT      hstmt;
  // 创建一个结果集,picture字段为BLOB
SQLExecDirect(hstmt, "SELECT PartID, Picture FROM Pictures", SQL_NTS);
  // 只绑定PartID列。
SQLBindCol(hstmt, 1, SQL_C_ULONG, &PartID, 0, &PartIDInd);
  // 获取数据并显示
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {
   // 循环调用SQLGetData获取数据,直到返回值为SQL_NO_DATA
   // 以下写法没有处理SQLGetData返回SQL_ERROR的情况
   while ((rc = SQLGetData(hstmt, 2, SQL_C_BINARY, BinaryPtr, sizeof(BinaryPtr),&BinaryLenOrInd)) != SQL_NO_DATA)
   {
      NumBytes = (BinaryLenOrInd > 5000) || (BinaryLenOrInd == SQL_NO_TOTAL) ?  5000 : BinaryLenOrInd;
   }
}
  // 关闭游标
SQLCloseCursor(hstmt);

备注:

SQLGetData如果BufferLength参数传入值为0,代表不获取数据,通过StrLen_or_IndPtr返回数据的真实长度。 这种做法一般是第一次传入0,返回数据真实长度,然后根据真实长度分配缓存数据的内存,方便后续数据的获取。

备注:

如果通过SQLDescribeCol获得LOB列的长度,老的神通ODBC会直接返回LOB数据的最大长度4G,应用程序用这个长度来分配内存时会导致内存占用非常高, 因此新版本的ODBC/ODBCW(V3.0.14包含)及以后版本支持了LobColSize属性,LobColSize属性用于设置通过获得列元数据信息时对于LOB列的返回长度,默认为0,代表还是返回4GB长度; 可以通过数据源配置或者在连接字符串中设置LobColSize属性,但LobColSize建议是必须大于当前数据库中所有LOB数据的最大长度。
如果应用程序不需要字符列或二进制数据列中的所有数据,则可以在执行语句之前设置 SQL_ATTR_MAX_LENGTH 语句特性,从而减少基于 DBMS 的驱动程序中的网络流量。
这会限制将为任何字符列或二进制列返回的数据字节数。 例如,假设某列包含长文本文档,但设置SQL_ATTR_MAX_LENGTH属性对神通ODBC并不生效。