SQLBulkOperations 函数

一致性
推出版本:ODBC 3.0 标准合规:ODBC

总结
SQLBulkOperations 执行批量插入和批量书签操作,包括通过书签进行更新、删除和获取。

Syntax

  
SQLRETURN SQLBulkOperations(  
     SQLHSTMT       StatementHandle,  
     SQLUSMALLINT   Operation);  

Arguments

StatementHandle
[输入]语句句柄。

运算
[输入]执行操作:

SQL_ADD SQL_UPDATE_BY_BOOKMARK SQL_DELETE_BY_BOOKMARK SQL_FETCH_BY_BOOKMARK

有关详细信息,请参阅“注释”。

Returns

SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、和SQL_NEED_DATA、SQL_STILL_EXECUTING、SQL_ERROR或SQL_INVALID_HANDLE。

诊断

SQLBulkOperations 返回 SQL_ERROR 或 SQL_SUCCESS_WITH_INFO 时,可以通过调用 SQLGetDiagRec 获得关联的 SQLSTATE 值, HandleSQL_HANDLE_STMT,HandleStatementHandle。 下表列出了 SQLBulkOperations 通常返回的SQLSTATE值,并在该函数的上下文中对每个值进行了解释;“(DM)” 符号位于驱动程序管理器返回的 SQLSTATE 描述之前。 除非另有说明,否则与每个 SQLSTATE 值关联的返回代码SQL_ERROR。

对于所有能返回SQL_SUCCESS_WITH_INFO或SQL_ERROR的SQLSTATE(除01xxx SQLSTATE外),如果多行操作的一行或多行发生错误,则返回SQL_SUCCESS_WITH_INFO;如果单行操作出现错误,则返回SQL_ERROR。

SQLSTATE Error Description
01000 常规警告 特定于驱动程序的信息性消息。 (函数返回SQL_SUCCESS_WITH_INFO。)
01004 字符串数据右截断 操作 参数被 SQL_FETCH_BY_BOOKMARK,对于数据类型为SQL_C_CHAR或SQL_C_BINARY的列返回字符串或二进制数据,会导致非空白字符或非NULL二进制数据被截断。
01S01 行中错误 操作 参数被 SQL_ADD,执行操作时一行或多行出现错误,但至少一行成功添加了。 (函数返回SQL_SUCCESS_WITH_INFO。)

(该错误仅在应用程序使用 ODBC 2 时出现。x 驱动。)
01S07 小数截断 操作 参数被 SQL_FETCH_BY_BOOKMARK,应用缓冲区的数据类型未SQL_C_CHAR或SQL_C_BINARY,且返回到应用缓冲区中一个或多个列的数据被截断。 (对于数值C型数据类型,分数部分被截断。对于包含时间成分的时间、时间戳和区间C数据类型,时间的分数部分被截断。)

(函数返回SQL_SUCCESS_WITH_INFO。)
07006 受限数据类型属性冲突 操作参数被SQL_FETCH_BY_BOOKMARK,结果集中某列的数据值无法转换为调用 SQLBindColTargetType 参数指定的数据类型。

操作参数为SQL_UPDATE_BY_BOOKMARK或SQL_ADD,应用缓冲区中的数据值无法转换为结果集中某列的数据类型。
07009 无效描述子索引 参数 操作SQL_ADD ,列被绑定为大于结果集列数的列数。
21S02 派生表的程度与列列表不匹配 论点是SQL_UPDATE_BY_BOOKMARK;而且没有列可更新,因为所有列要么未绑定,要么只读,或者绑定长度/指示缓冲区的值都被SQL_COLUMN_IGNORE。
22001 字符串数据右截断 将字符或二进制值赋值到结果集中的列会导致非空(字符)或非空(二进制)字符或字节被截断。
22003 数值范围之外 操作参数为SQL_ADD或SQL_UPDATE_BY_BOOKMARK,结果集中列赋予数值时,数字的全部(而非分数部分)会被截断。

参数 Operation 是SQL_FETCH_BY_BOOKMARK的,返回一个或多个绑定列的数值会导致有效位丢失。
22007 日期/时间格式无效 操作参数是SQL_ADD或SQL_UPDATE_BY_BOOKMARK,结果集中的列赋予日期或时间戳值会导致年份、月份或日期字段超出范围。

参数 操作SQL_FETCH_BY_BOOKMARK ,返回一个或多个绑定列的日期或时间戳值会导致年份、月份或日期字段超出范围。
22008 日期/时间字段溢出 操作参数为SQL_ADD或SQL_UPDATE_BY_BOOKMARK,对数据发送到结果集中列时进行日期时间算术时,结果的datetime字段(年份、月份、日、小时、分钟或秒字段)超出该字段允许的值范围,或根据格里高利历的日期时间自然规则无效。

操作 参数被 SQL_FETCH_BY_BOOKMARK,对从结果集检索数据进行日期时间算术的执行,导致结果中的datetime字段(年份、月份、日、小时、分钟或秒字段)超出该字段允许的值范围,或根据格里高利历的日期时间自然规则无效。
22015 间隔字段溢出 操作参数为SQL_ADD或 SQL_UPDATE_BY_BOOKMARK,而将精确的数值或区间 C 类型赋入区间 SQL 数据类型会导致有效位丢失。

行动论点要么是“ SQL_ADD 要么SQL_UPDATE_BY_BOOKMARK;在赋入区间SQL类型时,区间SQL类型中没有C类型的值表示。

操作 参数SQL_FETCH_BY_BOOKMARK ,从精确的数值或区间SQL类型分配到区间C类型会导致首字段丢失有效数字。

行动 论点 SQL_FETCH_BY_BOOKMARK;当将 C 区间类型分配到区间 C 时,没有表示区间 C 类型中 SQL 类型的值。
22018 强制转换规范的字符值无效 行动 论点 SQL_FETCH_BY_BOOKMARK;C 类型是精确或近似数值、日期时间或区间数据类型;列的SQL类型是字符数据类型;且列中的值不是绑定C类型的有效文字。

论点是SQL_ADD或SQL_UPDATE_BY_BOOKMARK;SQL 类型是精确或近似数值、日期时间或区间数据类型;C型车型SQL_C_CHAR;且列中的值不是绑定SQL类型的有效文字。
23000 完整性约束冲突 操作论证是SQL_ADD、SQL_DELETE_BY_BOOKMARK或SQL_UPDATE_BY_BOOKMARK,并且完整性约束被违反。

操作 参数被 SQL_ADD,未绑定的列定义为NOT NULL,且无默认值。

操作 参数被 SQL_ADD,绑定 StrLen_or_IndPtr 缓冲区中指定的长度为SQL_COLUMN_IGNORE,且列没有默认值。
24000 游标状态无效 StatementHandle 处于执行状态,但没有与 StatementHandle 关联的结果集。
40001 序列化失败 由于资源死锁与另一个事务,事务已回滚。
40003 语句完成未知 执行此函数期间关联的连接失败,无法确定事务的状态。
42000 语法错误或访问冲突 驱动程序无法锁定该行以执行操作参数中请求的操作。
44000 WITH CHECK OPTION 冲突 操作参数为SQL_ADD或SQL_UPDATE_BY_BOOKMARK,插入或更新是在通过指定WITH CHECK OPTION创建的已查看表(或从该表派生的表)上执行,使得一个或多个受插入或更新影响的行不再出现在被查看的表中。
HY000 常规错误 发生错误:没有特定的 SQLSTATE,也没有定义特定于实现的 SQLSTATE。 *MessageText 缓冲区中 SQLGetDiagRec 返回的错误消息描述错误及其原因。
HY001 内存分配错误 驱动程序无法分配支持执行或完成函数所需的内存。
HY008 操作已取消 StatementHandle 启用了异步处理。 调用了该函数,在完成执行之前,对 StatementHandle 调用了 SQLCancel 或 SQLCancelHandle。 然后,在 StatementHandle再次调用该函数。

调用了函数,在完成执行之前,SQLCancel 或 SQLCancelHandle 从多线程应用程序中的不同线程调用 StatementHandle
HY010 函数序列错误 (DM) 为与 StatementHandle 关联的连接句柄调用异步执行函数。 当调用 SQLBulkOperations 函数时,该异步函数仍在执行。

(DM) 为 StatementHandle 调用了 SQLExecuteSQLExecDirectSQLMoreResults,并返回了SQL_PARAM_DATA_AVAILABLE。 在检索所有流式处理参数的数据之前调用此函数。

(DM) 指定的 StatementHandle 未处于执行状态。 调用该函数时未先调用 SQLExecDirectSQLExecute 或目录函数。

(DM) 为 StatementHandle 调用异步执行函数(而不是此函数),并在调用此函数时仍在执行。

(DM) SQLExecuteSQLExecDirectSQLSetPos被 调用了语 句Handle 并返回SQL_NEED_DATA。 在为所有数据执行参数或列发送数据之前调用此函数。

(DM)司机是ODBC 2型。x 驱动程序,并且在调用 SQLFetchScrollSQLFetch 之前,先调用了 StatementHandle

(DM) SQLBulkOperations 是在 StatementHandle 调用 SQLExtendedFetch 之后被调用的。
HY011 无法立即设置属性 (DM)司机是ODBC 2型。x 驱动程序,SQL_ATTR_ROW_STATUS_PTR语句属性在调用 SQLFetchSQLFetchScrollSQLBulkOperations 之间设置。
HY013 内存管理错误 无法处理函数调用,因为基础内存对象无法访问,可能是因为内存条件低。
HY090 字符串或缓冲区长度无效 行动论点要么是“ SQL_ADD 要么SQL_UPDATE_BY_BOOKMARK;数据值不是空指针;C 数据类型为 SQL_C_BINARY 或 SQL_C_CHAR;列长值小于0,但不等于SQL_DATA_AT_EXEC、SQL_COLUMN_IGNORE、SQL_NTS或SQL_NULL_DATA,也不小于或等于SQL_LEN_DATA_AT_EXEC_OFFSET。

长度/指示缓冲区中的值为SQL_DATA_AT_EXEC;SQL 类型要么是 SQL_LONGVARCHAR、SQL_LONGVARBINARY,要么是 long 的特定数据源数据类型; SQLGetInfo 中的SQL_NEED_LONG_DATA_LEN信息类型是“Y”。

操作 参数被 SQL_ADD,SQL_ATTR_USE_BOOKMARK语句属性设置为SQL_UB_VARIABLE,列0绑定了一个缓冲区,该缓冲区长度不等于该结果集书签的最大长度。 (该长度可在IRD的SQL_DESC_OCTET_LENGTH字段中获得,可通过调用 SQLDescribeColSQLColAttributeSQLGetDescField获得。)
HY092 无效属性标识符 (DM) 操作参数指定的 值无效。

操作参数为SQL_ADD、SQL_UPDATE_BY_BOOKMARK或SQL_DELETE_BY_BOOKMARK,SQL_ATTR_CONCURRENCY语句属性设置为SQL_CONCUR_READ_ONLY。

操作参数分别为SQL_DELETE_BY_BOOKMARK、SQL_FETCH_BY_BOOKMARK或SQL_UPDATE_BY_BOOKMARK,书签列未绑定,且SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_OFF。
HY117 连接因未知事务状态而挂起。 仅允许断开连接和只读函数。 (DM) 有关挂起状态的详细信息,请参阅 SQLEndTran 函数
HYC00 未实现可选功能 驱动程序或数据源不支持 操作 参数中请求的操作。
HYT00 已超时 在数据源返回结果集之前,查询超时期限已过期。 超时周期通过 SQLSetStmtAttr 设置, 属性参数为 SQL_ATTR_QUERY_TIMEOUT。
HYT01 超过连接超时时间 在数据源响应请求之前,连接超时期限已过期。 连接超时期限通过 SQLSetConnectAttr 设置,SQL_ATTR_CONNECTION_TIMEOUT。
IM001 驱动程序不支持此函数 (DM) 与 StatementHandle 关联的驱动程序不支持该函数。
IM017 在异步通知模式下禁用轮询 每当使用通知模型时,轮询将被禁用。
IM018 尚未调用 SQLCompleteAsync 来完成此句柄上的上一个异步操作。 如果句柄上的上一个函数调用返回SQL_STILL_EXECUTING并且启用通知模式, 则必须在句柄上调用 SQLCompleteAsync 才能执行后期处理并完成操作。

Comments

Caution

关于可以调用哪些语句状态, SQLBulkOperations 可以调用,以及它为与 ODBC 2 兼容必须做什么。x个应用程序, 请参见附录G:向后兼容驱动指南中的 块光标、可滚动光标和向后兼容性 部分。

应用程序使用 SQLBulkOperations 对对应当前查询的基表或视图执行以下操作:

  • 添加新行。

  • 更新一组行,每行用书签标识。

  • 删除一组行,每行用书签标识。

  • 获取一组行,每行用书签标识。

调用 SQLBulkOperations 后,块光标位置未定义。 应用程序需要调用 SQLFetchScroll 来设置光标位置。 应用程序应仅在 FetchOrientation 参数为 SQL_FETCH_FIRST、SQL_FETCH_LAST、SQL_FETCH_ABSOLUTE 或 SQL_FETCH_BOOKMARK 时调用 SQLFetchScroll。 如果应用程序调用 SQLFetchSQLFetchScroll ,且 FetchOrientation 参数为 SQL_FETCH_PRIOR、SQL_FETCH_NEXT 或 SQL_FETCH_RELATIVE,则光标位置未定义。

在调用 SQLBulkOperations 的批量操作中,可以通过将调用 SQLBindCol 中指定的列长度/指示缓冲区设置为 SQL_COLUMN_IGNORE 来忽略列。

应用程序在调用 SQLBulkOperations 时无需设置 SQL_ATTR_ROW_OPERATION_PTR 语句属性,因为在使用该函数进行批量操作时,行不可忽视。

SQL_ATTR_ROWS_FETCHED_PTR语句属性指向的缓冲区包含调用 SQLBulkOperations所影响的行数。

操作 参数被SQL_ADD或SQL_UPDATE_BY_BOOKMARK,且与光标关联的查询规范的select-list包含多个指向同一列的引用时,驱动程序定义是否生成错误,或者驱动程序忽略重复引用并执行请求操作。

有关如何使用 SQLBulkOperations 的更多信息,请参见 用 SQLBulkOperations 更新数据

进行散装插入

要用 SQLBulkOperations 插入数据,应用程序执行以下步骤:

  1. 执行返回结果集的查询。

  2. 将SQL_ATTR_ROW_ARRAY_SIZE语句属性设置为它想插入的行数。

  3. 调用 SQLBindCol 绑定它想插入的数据。 数据被绑定到大小等于SQL_ATTR_ROW_ARRAY_SIZE值的数组。

    注释

    SQL_ATTR_ROW_STATUS_PTR语句属性所指向数组的大小应当等于SQL_ATTR_ROW_ARRAY_SIZE,或者SQL_ATTR_ROW_STATUS_PTR应为空指针。

  4. 调用 SQLBulkOperationsStatementHandle, SQL_ADD) 来执行插入。

  5. 如果应用程序设置了SQL_ATTR_ROW_STATUS_PTR语句属性,它可以检查该数组以查看操作结果。

如果应用程序在调用 SQLBulkOperations 前绑定了第 0 列,且 操作参数为 SQL_ADD,驱动程序会更新绑定的第 0 列缓冲区,并更新新插入行的书签值。 要实现这一点,应用程序必须在执行该语句前将SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_VARIABLE。 (这对ODBC 2不适用。x 驱动。)

SQLBulkOperations 可以通过调用 SQLParamData 和 SQLPutData 来分段添加长数据。 欲了解更多信息,请参见本函数参考文献后面的“为批量插入和更新提供长数据”。

应用程序在调用 SQLBulkOperations 之前无需先调用 SQLFetchSQLFetchScroll(除非针对 ODBC 2 时)。x 驱动;参见向后兼容性与标准合规)。

如果在包含重复列的光标上调用 SQLBulkOperations,且 操作参数为 SQL_ADD,则该行为由驱动程序定义。 驱动程序可以返回驱动程序定义的 SQLSTATE,将数据添加到结果集中出现的第一列,或执行其他驱动程序定义的行为。

通过使用书签进行批量更新

为了通过使用 SQLBulkOperations 的书签进行批量更新,应用程序依次执行以下步骤:

  1. 将SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_VARIABLE。

  2. 执行返回结果集的查询。

  3. 将SQL_ATTR_ROW_ARRAY_SIZE语句属性设置为它想更新的行数。

  4. 调用 SQLBindCol 绑定它想更新的数据。 数据被绑定到大小等于SQL_ATTR_ROW_ARRAY_SIZE值的数组。 它还调用 SQLBindCol 绑定第 0 列(书签列)。

  5. 将它感兴趣更新行的书签复制到绑定到第0列的数组中。

  6. 更新绑定缓冲区中的数据。

    注释

    SQL_ATTR_ROW_STATUS_PTR语句属性所指向的数组大小应为SQL_ATTR_ROW_ARRAY_SIZE,否则SQL_ATTR_ROW_STATUS_PTR应为空指针。

  7. 调用 SQLBulkOperationsStatementHandle, SQL_UPDATE_BY_BOOKMARK)。

    注释

    如果应用程序设置了SQL_ATTR_ROW_STATUS_PTR语句属性,它可以检查该数组以查看操作结果。

  8. 可选地调用 SQLBulkOperationsStatementHandle, SQL_FETCH_BY_BOOKMARK) 将数据导入绑定的应用缓冲区,以验证更新是否已发生。

  9. 如果数据已被更新,驱动程序会将相应行的状态数组值更改为SQL_ROW_UPDATED。

SQLBulkOperations 执行的批量更新可以通过调用 SQLParamDataSQLPutData 来包含长数据。 欲了解更多信息,请参见本函数参考文献后面的“为批量插入和更新提供长数据”。

如果书签在各光标间持续存在,应用程序无需调用 SQLFetchSQLFetchScroll 即可通过书签进行更新。 它可以使用之前光标存储的书签。 如果书签在光标间无法持久存在,应用程序必须调用 SQLFetchSQLFetchScroll 来获取书签。

如果在包含重复列的光标上调用 SQLBulkOperations,且 操作参数为 SQL_UPDATE_BY_BOOKMARK,则该行为由驱动程序定义。 驱动程序可以返回驱动程序定义的 SQLSTATE,更新结果集中出现的第一列,或执行其他驱动程序定义的行为。

使用书签进行批量取物

为了使用 SQLBulkOperations进行书签批量取物,应用程序按顺序执行以下步骤:

  1. 将SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_VARIABLE。

  2. 执行返回结果集的查询。

  3. 将SQL_ATTR_ROW_ARRAY_SIZE语句属性设置为它想要获取的行数。

  4. 调用 SQLBindCol 绑定它想要获取的数据。 数据被绑定到大小等于SQL_ATTR_ROW_ARRAY_SIZE值的数组。 它还调用 SQLBindCol 绑定第 0 列(书签列)。

  5. 将它感兴趣的行的书签复制到绑定到第0列数组中。 (这假设应用已经单独获得了书签。)

    注释

    SQL_ATTR_ROW_STATUS_PTR语句属性所指向的数组大小应为SQL_ATTR_ROW_ARRAY_SIZE,否则SQL_ATTR_ROW_STATUS_PTR应为空指针。

  6. 调用 SQLBulkOperationsStatementHandle, SQL_FETCH_BY_BOOKMARK)。

  7. 如果应用程序设置了SQL_ATTR_ROW_STATUS_PTR语句属性,它可以检查该数组以查看操作结果。

如果书签在各光标间持续存在,应用程序无需在通过书签获取前调用 SQLFetchSQLFetchScroll 。 它可以使用之前光标存储的书签。 如果书签在各光标间无法持久存在,应用程序必须调用一次 SQLFetchSQLFetchScroll 来获取书签。

使用书签进行批量删除

要使用 SQLBulkOperations的书签进行批量删除,应用程序按顺序执行以下步骤:

  1. 将SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_VARIABLE。

  2. 执行返回结果集的查询。

  3. 将SQL_ATTR_ROW_ARRAY_SIZE语句属性设置为它想删除的行数。

  4. 调用 SQLBindCol 绑定第 0 列(书签列)。

  5. 将它感兴趣删除的行的书签复制到绑定到第0列的数组中。

    注释

    SQL_ATTR_ROW_STATUS_PTR语句属性所指向的数组大小应为SQL_ATTR_ROW_ARRAY_SIZE,否则SQL_ATTR_ROW_STATUS_PTR应为空指针。

  6. 调用 SQLBulkOperationsStatementHandle, SQL_DELETE_BY_BOOKMARK)。

  7. 如果应用程序设置了SQL_ATTR_ROW_STATUS_PTR语句属性,它可以检查该数组以查看操作结果。

如果书签在各光标间持续存在,应用程序无需调用 SQLFetchSQLFetchScroll 即可删除书签。 它可以使用之前光标存储的书签。 如果书签在各光标间无法持久存在,应用程序必须调用一次 SQLFetchSQLFetchScroll 来获取书签。

为批量插入和更新提供长数据

通过调用 SQLBulkOperations 可以为批量插入和更新提供长数据。 为了插入或更新长数据,应用程序除了本主题前述“执行批量插入”和“使用书签执行批量更新”部分描述的步骤外,还会执行以下步骤。

  1. 当它通过 SQLBindCol 绑定数据时,应用程序会在 *TargetValuePtr 缓冲区(用于执行时数据列)中放置应用定义的值,如列号。 该值可以稍后用来识别列。

    应用程序将SQL_LEN_DATA_AT_EXEC(长度)宏的结果放入 *StrLen_or_IndPtr 缓冲区。 如果列的SQL数据类型是SQL_LONGVARBINARY、SQL_LONGVARCHAR或长的数据源特定类型,且驱动程序在 SQLGetInfo中返回“Y”作为SQL_NEED_LONG_DATA_LEN信息 类型,长度 是该参数要发送的数据字节数;否则,必须是非负值,且被忽略。

  2. 当调用 SQLBulkOperations 时,如果存在 data-at-execution 列,函数返回 SQL_NEED_DATA,并进入步骤 3,随后进行。 (如果没有执行时的数据列,则过程完成。)

  3. 应用程序调用 SQLParamData ,获取第一个执行时数据列的 *TargetValuePtr 缓冲区地址。 SQLParamData 返回SQL_NEED_DATA。 应用程序从 *TargetValuePtr 缓冲区检索应用定义的值。

    注释

    尽管数据执行参数类似于执行时的数据列,但 SQLParamData 返回的值对于每个列都是不同的。

    执行时数据列是行集中中的列,当用 SQLBulkOperations 更新或插入行时,数据将通过 SQLPutData 发送。 它们与 SQLBindCol 绑定。 SQLParamData 返回的值是正在处理的 *TargetValuePtr 缓冲区中行的地址。

  4. 应用程序调用 SQLPutData 一次或多次以发送该列的数据。 如果无法在 SQLPutData 指定中的 *TargetValuePtr 缓冲区返回所有数据值,则需要多次调用;只有在将字符C数据发送到带有字符、二进制或特定数据源数据类型的列,或将二进制C数据发送到具有字符、二进制或数据源特定数据类型的列时,才允许对同一列多次调用SQLPutData

  5. 应用程序再次调用 SQLParamData ,以表示该列的所有数据已发送完毕。

    • 如果有更多执行时数据列, SQLParamData 返回SQL_NEED_DATA和下一个执行时数据列的 TargetValuePtr 缓冲区地址。 应用程序重复步骤 4 和 5。

    • 如果没有更多执行时数据列,则过程完成。 如果语句成功执行, SQLParamData 返回SQL_SUCCESS或SQL_SUCCESS_WITH_INFO;如果执行失败,则返回SQL_ERROR。 此时, SQLParamData 可以返回 SQLBulkOperations能返回的任何SQLSTATE。

如果操作被取消或在 SQLBulkOperations 返回SQL_NEED_DATA且所有执行时数据尚未发送前发生错误,应用程序只能调用 SQLCancelSQLGetDiagFieldSQLGetDiagRecSQLGetFunctionsSQLParamDataSQLPutData,以获取该语句或与该语句关联的连接。 如果调用该语句或与该语句关联的连接的其他函数,函数返回SQL_ERROR和SQLSTATE HY010(函数序列错误)。

如果应用程序调用 SQLCancel ,而驱动程序仍需要执行时数据列的数据,驱动会取消该操作。 应用程序随后可以再次调用 SQLBulkOperations ;取消不会影响光标状态或当前光标位置。

行状态数组

行状态数组包含调用 SQLBulkOperations 后行集中每一行数据的状态值。 驱动程序在调用 SQLFetchSQLFetchScrollSQLSetPosSQLBulkOperations 后,设置该数组的状态值。 如果在SQLBulkOperations之前没有调用SQLFetchSQLFetchScroll,则该数组最初由调用SQLBulkOperations填充。 该数组由 SQL_ATTR_ROW_STATUS_PTR 语句属性指向。 行状态数组中的元素数必须等于行集中的行数(由SQL_ATTR_ROW_ARRAY_SIZE语句属性定义)。 有关该行状态数组的信息,请参见 SQLFetch

代码示例

以下示例每次从客户表获取10行数据。 然后它会提示用户执行一个操作。 为了减少网络流量,示例缓冲区会在绑定数组中本地更新、删除并插入,但偏移量超过行集数据。 当用户选择向数据源发送更新、删除和插入时,代码会适当设置绑定偏移量并调用 SQLBulkOperations。 为了简化起见,用户不能缓冲超过10次更新、删除或插入。

// SQLBulkOperations_Function.cpp  
// compile with: ODBC32.lib  
#include <windows.h>  
#include <sqlext.h>  
#include "stdio.h"  
  
#define UPDATE_ROW 100  
#define DELETE_ROW 101  
#define ADD_ROW 102  
#define SEND_TO_DATA_SOURCE 103  
#define UPDATE_OFFSET 10  
#define INSERT_OFFSET 20  
#define DELETE_OFFSET 30  
  
// Define structure for customer data (assume 10 byte maximum bookmark size).  
typedef struct tagCustStruct {  
   SQLCHAR Bookmark[10];  
   SQLINTEGER BookmarkLen;  
   SQLUINTEGER CustomerID;  
   SQLINTEGER CustIDInd;  
   SQLCHAR CompanyName[51];  
   SQLINTEGER NameLenOrInd;  
   SQLCHAR Address[51];  
   SQLINTEGER AddressLenOrInd;  
   SQLCHAR Phone[11];  
   SQLINTEGER PhoneLenOrInd;  
} CustStruct;  
  
// Allocate 40 of these structures. Elements 0-9 are for the current rowset,  
// elements 10-19 are for the buffered updates, elements 20-29 are for  
// the buffered inserts, and elements 30-39 are for the buffered deletes.  
CustStruct CustArray[40];  
SQLUSMALLINT RowStatusArray[10], Action, RowNum, NumUpdates = 0, NumInserts = 0,  
NumDeletes = 0;  
SQLLEN BindOffset = 0;  
SQLRETURN retcode;  
SQLHENV henv = NULL;  
SQLHDBC hdbc = NULL;  
SQLHSTMT hstmt = NULL;  
  
int main() {  
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);   
  
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);   
   retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  
   retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);  
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  
   // Set the following statement attributes:  
   // SQL_ATTR_CURSOR_TYPE:           Keyset-driven  
   // SQL_ATTR_ROW_BIND_TYPE:         Row-wise  
   // SQL_ATTR_ROW_ARRAY_SIZE:        10  
   // SQL_ATTR_USE_BOOKMARKS:         Use variable-length bookmarks  
   // SQL_ATTR_ROW_STATUS_PTR:        Points to RowStatusArray  
   // SQL_ATTR_ROW_BIND_OFFSET_PTR:   Points to BindOffset  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(CustStruct), 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_VARIABLE, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &BindOffset, 0);  
  
   // Bind arrays to the bookmark, CustomerID, CompanyName, Address, and Phone columns.  
   retcode = SQLBindCol(hstmt, 0, SQL_C_VARBOOKMARK, CustArray[0].Bookmark, sizeof(CustArray[0].Bookmark), &CustArray[0].BookmarkLen);  
   retcode = SQLBindCol(hstmt, 1, SQL_C_ULONG, &CustArray[0].CustomerID, 0, &CustArray[0].CustIDInd);  
   retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, CustArray[0].CompanyName, sizeof(CustArray[0].CompanyName), &CustArray[0].NameLenOrInd);  
   retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, CustArray[0].Address, sizeof(CustArray[0].Address), &CustArray[0].AddressLenOrInd);  
   retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, CustArray[0].Phone, sizeof(CustArray[0].Phone), &CustArray[0].PhoneLenOrInd);  
  
   // Execute a statement to retrieve rows from the Customers table.  
   retcode = SQLExecDirect(hstmt, (SQLCHAR*)"SELECT CustomerID, CompanyName, Address, Phone FROM Customers", SQL_NTS);  
  
   // Fetch and display the first 10 rows.  
   retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
   // DisplayCustData(CustArray, 10);  
  
   // Call GetAction to get an action and a row number from the user.  
   // while (GetAction(&Action, &RowNum)) {  
   Action = SQL_FETCH_NEXT;  
   RowNum = 2;  
   switch (Action) {  
      case SQL_FETCH_NEXT:  
      case SQL_FETCH_PRIOR:  
      case SQL_FETCH_FIRST:  
      case SQL_FETCH_LAST:  
      case SQL_FETCH_ABSOLUTE:  
      case SQL_FETCH_RELATIVE:  
         // Fetch and display the requested data.  
         SQLFetchScroll(hstmt, Action, RowNum);  
         // DisplayCustData(CustArray, 10);  
         break;  
  
      case UPDATE_ROW:  
         // Check if we have reached the maximum number of buffered updates.  
         if (NumUpdates < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered updates section of CustArray, copy the bookmark of the row  
            // being updated to the same element, and increment the update counter.  
            // Checking to see we have not already buffered an update for this  
            // row not shown.  
            // GetNewCustData(CustArray, UPDATE_OFFSET + NumUpdates);  
            memcpy(CustArray[UPDATE_OFFSET + NumUpdates].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
            CustArray[UPDATE_OFFSET + NumUpdates].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
            NumUpdates++;  
         } else {  
            printf("Buffers full. Send buffered changes to the data source.");  
         }  
         break;  
      case DELETE_ROW:  
         // Check if we have reached the maximum number of buffered deletes.  
         if (NumDeletes < 10) {  
            // Copy the bookmark of the row being deleted to the next available element  
            // of the buffered deletes section of CustArray and increment the delete  
            // counter. Checking to see we have not already buffered an update for  
            // this row not shown.  
            memcpy(CustArray[DELETE_OFFSET + NumDeletes].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
  
            CustArray[DELETE_OFFSET + NumDeletes].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
  
            NumDeletes++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case ADD_ROW:  
         // reached maximum number of buffered inserts?  
         if (NumInserts < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered inserts section of CustArray and increment insert counter.  
            // GetNewCustData(CustArray, INSERT_OFFSET + NumInserts);  
            NumInserts++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case SEND_TO_DATA_SOURCE:  
         // If there are any buffered updates, inserts, or deletes, set the array size  
         // to that number, set the binding offset to use the data in the buffered  
         // update, insert, or delete part of CustArray, and call SQLBulkOperations to  
         // do the updates, inserts, or deletes. Because we will never have more than  
         // 10 updates, inserts, or deletes, we can use the same row status array.  
         if (NumUpdates) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumUpdates, 0);  
            BindOffset = UPDATE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_UPDATE_BY_BOOKMARK);  
            NumUpdates = 0;  
         }  
  
         if (NumInserts) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumInserts, 0);  
            BindOffset = INSERT_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_ADD);  
            NumInserts = 0;  
         }  
  
         if (NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumDeletes, 0);  
            BindOffset = DELETE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_DELETE_BY_BOOKMARK);  
            NumDeletes = 0;  
         }  
  
         // If there were any updates, inserts, or deletes, reset the binding offset  
         // and array size to their original values.  
         if (NumUpdates || NumInserts || NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
            BindOffset = 0;  
         }  
         break;  
   }  
   // }  
  
   // Close the cursor.  
   SQLFreeStmt(hstmt, SQL_CLOSE);  
}  
有关以下内容的信息 请参阅
将缓冲区绑定到结果集中的列 SQLBindCol 函数
取消语句处理 SQLCancel 函数
提取数据块或滚动结果集 SQLFetchScroll 函数
获取描述符的单一字段 SQLGetDescField 函数
获取描述符的多个字段 SQLGetDescRec 函数
设置描述符的单一字段 SQLSetDescField 函数
描述符的多个字段设置 SQLSetDescRec 函数
光标位置、刷新行集内数据,或更新或删除行集中的数据 SQLSetPos 函数
设置语句属性 SQLSetStmtAttr 函数