获取 Long 数据
DBMS 将长数据定义为特定大小的任意字符或二进制数据,例如 255 个字符。 此数据可能足够小,可以存储在单个缓冲区中,例如包含几千个字符的一部分说明。 但是,它在内存中存储时间可能太长,例如长文本文档或位图。 由于此类数据不能存储在单个缓冲区中,因此在提取行中的其他数据后,将使用 SQLGetData 分部分从驱动程序中提取此数据。
注意
应用程序实际上可以使用 SQLGetData 检索任何类型的数据,而不仅仅是长数据,尽管只能分部分检索字符和二进制数据。 但是,如果数据足够小,无法容纳在单个缓冲区中,则通常没有理由使用 SQLGetData。 将缓冲区绑定到列并让驱动程序返回缓冲区中的数据要容易得多。
要从列检索长数据,应用程序首先会调用 SQLFetchScroll 或 SQLFetch 移动到行并提取绑定列的数据。 然后,应用程序调用 SQLGetData。 SQLGetData 的参数与 SQLBindCol 相同:语句句柄;列编号;应用程序变量的 C 数据类型、地址和字节长度;长度/指示器缓冲区的地址。 这两个函数具有相同的参数,因为它们基本上执行相同的任务:它们都向驱动程序描述应用程序变量,并指定应在该变量中返回特定列的数据。 主要区别在于,提取行后调用 SQLGetData(有时称为晚期绑定),SQLGetData 指定的绑定仅在调用期间持续。
对于单个列,SQLGetData 的行为类似于 SQLFetch:它检索该列的数据,将其转换为应用程序变量的类型,并在该变量中予以返回。 它还返回长度/指示器缓冲区中的数据的字节长度。 有关 SQLFetch 如何返回数据的详细信息,请参阅提取数据行。
SQLGetData 在一个重要方面不同于 SQLFetch。 如果针对同一列连续调用多次,则每个调用都会返回数据的连续部分。 最后一次调用以外的每个调用返回 SQL_SUCCESS_WITH_INFO 和 SQLSTATE 01004(字符串数据,右截断):最后一个调用返回 SQL_SUCCESS。 这是使用 SQLGetData 分部分检索长数据的方式。 如果没有更多要返回的数据,SQLGetData 将返回 SQL_NO_DATA。 应用程序负责将长数据放在一起,这可能意味着拼接数据的各个部分。 每个部分都以 null 结尾;如果拼接各部分,则应用程序必须删除 null 终止字符。 对于可变长度书签以及其他长数据,可以分部分检索数据。 每次调用中的长度/指示器缓冲区中返回的值随着上一次调用中返回的字节数而减少,尽管驱动程序通常无法发现可用数据量并返回 SQL_NO_TOTAL 字节长度。 例如:
// Declare a binary buffer to retrieve 5000 bytes of data at a time.
SQLCHAR BinaryPtr[5000];
SQLUINTEGER PartID;
SQLINTEGER PartIDInd, BinaryLenOrInd, NumBytes;
SQLRETURN rc;
SQLHSTMT hstmt;
// Create a result set containing the ID and picture of each part.
SQLExecDirect(hstmt, "SELECT PartID, Picture FROM Pictures", SQL_NTS);
// Bind PartID to the PartID column.
SQLBindCol(hstmt, 1, SQL_C_ULONG, &PartID, 0, &PartIDInd);
// Retrieve and display each row of data.
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {
// Display the part ID and initialize the picture.
DisplayID(PartID, PartIDInd);
InitPicture();
// Retrieve the picture data in parts. Send each part and the number
// of bytes in each part to a function that displays it. The number
// of bytes is always 5000 if there were more than 5000 bytes
// available to return (cbBinaryBuffer > 5000). Code to check if
// rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLGetData(hstmt, 2, SQL_C_BINARY, BinaryPtr, sizeof(BinaryPtr),
&BinaryLenOrInd)) != SQL_NO_DATA) {
NumBytes = (BinaryLenOrInd > 5000) || (BinaryLenOrInd == SQL_NO_TOTAL) ?
5000 : BinaryLenOrInd;
DisplayNextPictPart(BinaryPtr, NumBytes);
}
}
// Close the cursor.
SQLCloseCursor(hstmt);
使用 SQLGetData 有多个限制。 通常为使用 SQLGetData 访问的列:
必须按列数增加的顺序访问(因为从数据源中读取结果集的列的方式)。 例如,为第 5 列调用 SQLGetData,然后再为第 4 列调用它是错误的。
无法绑定。
必须有一个高于最后一个绑定列的列编号。 例如,如果最后一个绑定列是第 3 列,则为第 2 列调用 SQLGetData 是错误的。 因此,应用程序应确保将长数据列放在 select 列表的末尾。
如果调用 SQLFetch 或 SQLFetchScroll 来检索多行,则无法使用。 有关详细信息,请参阅使用块游标。
某些驱动程序不强制实施这些限制。 可互操作的应用程序应假定它们存在,或者通过使用 SQL_GETDATA_EXTENSIONS 选项调用 SQLGetInfo 来确定不强制实施哪些限制。
如果应用程序不需要字符或二进制数据列中的所有数据,则它可以通过在执行语句之前设置 SQL_ATTR_MAX_LENGTH 语句属性来减少基于 DBMS 的驱动程序中的网络流量。 这会限制将为任何字符或二进制列返回的数据字节数。 例如,假设列包含长文本文档。 浏览包含此列的表的应用程序可能只显示每个文档的第一页。 尽管可以在驱动程序中模拟此语句属性,但没有理由执行此操作。 具体而言,如果应用程序想要截断字符或二进制数据,则应使用 SQLBindCol 将小缓冲区绑定到列,并允许驱动程序截断数据。