获取长数据

DBMS 将 长数据 定义为特定大小的任意字符或二进制数据,例如 255 个字符。 此数据可能足够小,可以存储在单个缓冲区中,例如几千个字符的一部分说明。 但是,在内存中存储时间可能太长,例如长文本文档或位图。 由于此类数据无法存储在单个缓冲区中,因此在提取行中的其他数据后,将使用SQLGetData从驱动程序中分部分检索这些数据。

注释

应用程序实际上可以使用 SQLGetData 检索任何类型的数据,而不仅仅是长数据,尽管在部件中只能检索字符和二进制数据。 但是,如果数据足够小,无法容纳在单个缓冲区中,则通常没有理由使用 SQLGetData。 将缓冲区绑定到列并让驱动程序返回缓冲区中的数据要容易得多。

若要从列检索长数据,应用程序首先调用 SQLFetchScrollSQLFetch 移动到行并提取绑定列的数据。 然后,应用程序调用 SQLGetDataSQLGetData 的参数与 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 列调用 SQLGetData 是错误的。

  • 无法绑定。

  • 列号必须高于最后一个绑定列。 例如,如果最后一个绑定列是第 3 列,那么调用第 2 列的 SQLGetData 是错误的。 因此,应用程序应确保将长数据列放在选择列表的末尾。

  • 如果调用 SQLFetch 或 SQLFetchScroll 来检索多行,则无法使用。 有关详细信息,请参阅 使用块游标

某些驱动程序不强制实施这些限制。 可互作的应用程序应假定它们存在,或者通过使用 SQL_GETDATA_EXTENSIONS 选项调用 SQLGetInfo 来确定不强制实施哪些限制。

如果应用程序不需要字符或二进制数据列中的所有数据,则它可以通过在执行语句之前设置 SQL_ATTR_MAX_LENGTH 语句属性来减少基于 DBMS 的驱动程序中的网络流量。 这会限制将针对任何字符或二进制列返回的数据字节数。 例如,假设列包含长文本文档。 浏览包含此列的表的应用程序可能只显示每个文档的第一页。 尽管可以在驱动程序中模拟此语句属性,但没有理由执行此作。 具体而言,如果应用程序想要截断字符或二进制数据,则应使用 SQLBindCol 将小缓冲区绑定到列,并允许驱动程序截断数据。