SQLBulkOperations 函数

一致性
引入的版本:ODBC 3.0 标准合规性:ODBC

摘要
SQLBulkOperations 执行批量插入和批量书签操作,包括更新、删除和按书签提取。

语法

  
SQLRETURN SQLBulkOperations(  
     SQLHSTMT       StatementHandle,  
     SQLUSMALLINT   Operation);  

自变量

StatementHandle
[输入]语句句柄。

操作
[输入]要执行的操作:

SQL_ADD SQL_UPDATE_BY_BOOKMARK SQL_DELETE_BY_BOOKMARK SQL_FETCH_BY_BOOKMARK

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

返回

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

诊断

SQLBulkOperations 返回SQL_ERROR或SQL_SUCCESS_WITH_INFO时,可以通过使用 handleType 为 SQL_HANDLE_STMT 和 Handle of StatementHandle 调用 SQLGetDiagRec 来获取关联的 SQLSTATE 值。 下表列出了 SQLBulkOperations 通常返回的 SQLSTATE 值,并解释了此函数上下文中的每个值:表示法“ (DM) ”位于驱动程序管理器返回的 SQLSTATE 说明之前。 与每个 SQLSTATE 值关联的返回代码SQL_ERROR,除非另有说明。

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

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

(仅当应用程序使用 ODBC 2 时,才会引发此错误。x driver.)
01S07 小数截断 Operation 参数已SQL_FETCH_BY_BOOKMARK,应用程序缓冲区的数据类型未SQL_C_CHAR或SQL_C_BINARY,并且返回应用程序缓冲区的一列或多列的数据被截断。 (对于数字 C 数据类型,数字的小数部分已被截断。对于包含时间分量的时间、时间戳和间隔 C 数据类型,时间的小数部分被截断。)

(函数返回 SQL_SUCCESS_WITH_INFO.)
07006 受限数据类型属性冲突 Operation 参数SQL_FETCH_BY_BOOKMARK,结果集中列的数据值无法转换为在调用 SQLBindCol 时由 TargetType 参数指定的数据类型。

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

参数 Operation 已SQL_FETCH_BY_BOOKMARK,返回一个或多个绑定列的数值将导致有效数字丢失。
22007 日期/时间格式无效 Operation 参数SQL_ADD或SQL_UPDATE_BY_BOOKMARK,并且将日期或时间戳值分配给结果集中的列会导致年、月或日字段在范围外。

参数 Operation SQL_FETCH_BY_BOOKMARK,返回一个或多个绑定列的日期或时间戳值会导致年、月或日字段超出范围。
22008 日期/时间字段溢出 Operation 参数SQL_ADD或SQL_UPDATE_BY_BOOKMARK,对发送到结果集中列的数据的 datetime 算术性能导致日期/时间字段 (年、月、日、小时、分钟或第二个字段,结果) 超出字段允许的值范围,或者根据公历的日期时间自然规则无效。

Operation 参数SQL_FETCH_BY_BOOKMARK,并且对从结果集中检索的数据的 datetime 算术性能导致日期/时间字段 (年、月、日、小时、分钟或第二个字段) 结果超出字段允许的值范围,或者根据公历的日期时间自然规则无效。
22015 间隔字段溢出 Operation 参数SQL_ADD或SQL_UPDATE_BY_BOOKMARK,将确切的数字或间隔 C 类型分配给间隔 SQL 数据类型会导致有效数字丢失。

Operation 参数SQL_ADD或SQL_UPDATE_BY_BOOKMARK;分配给间隔 SQL 类型时,间隔 SQL 类型中没有 C 类型的值表示形式。

Operation 参数SQL_FETCH_BY_BOOKMARK,从确切的数字或间隔 SQL 类型分配给间隔 C 类型会导致前导字段中有效位数丢失。

操作参数SQL_FETCH_BY_BOOKMARK;分配给间隔 C 类型时,间隔 C 类型中没有 SQL 类型的值表示形式。
22018 强制转换规范的字符值无效 操作参数SQL_FETCH_BY_BOOKMARK;C 类型是精确或近似数值、日期时间或间隔数据类型;列的 SQL 类型是字符数据类型;列中的值不是绑定 C 类型的有效文本。

参数 Operation 是SQL_ADD或SQL_UPDATE_BY_BOOKMARK;SQL 类型是精确或近似数值、日期/时间或间隔数据类型;C 类型SQL_C_CHAR;列中的值不是绑定 SQL 类型的有效文本。
23000 完整性约束冲突 Operation 参数SQL_ADD、SQL_DELETE_BY_BOOKMARK或SQL_UPDATE_BY_BOOKMARK,并且违反了完整性约束。

Operation 参数SQL_ADD,未绑定的列定义为 NOT NULL 且没有默认值。

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

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

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

(DM) 指定的 StatementHandle 未处于执行状态。 该函数是在未首先调用 SQLExecDirectSQLExecute 或目录函数的情况下调用的。

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

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

(DM) 驱动程序是 ODBC 2。在调用 SQLFetchScroll 或 SQLFetch 之前,已为 StatementHandle 调用了 x 驱动程序和 SQLBulkOperations

StatementHandle 上调用 SQLExtendedFetch 后, (DM) SQLBulkOperations
HY011 现在无法设置属性 (DM) 驱动程序是 ODBC 2。x 驱动程序和 SQL_ATTR_ROW_STATUS_PTR 语句属性是在调用 SQLFetchSQLFetchScrollSQLBulkOperations 之间设置的。
HY013 内存管理错误 无法处理函数调用,因为无法访问基础内存对象,可能是因为内存不足。
HY090 无效的字符串或缓冲区长度 Operation 参数SQL_ADD或SQL_UPDATE_BY_BOOKMARK;数据值不是 null 指针;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或特定于数据源的长数据类型; SQLGetInfo 中的SQL_NEED_LONG_DATA_LEN信息类型为“Y”。

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

Operation 参数SQL_ADD、SQL_UPDATE_BY_BOOKMARK或SQL_DELETE_BY_BOOKMARK,并且SQL_ATTR_CONCURRENCY语句属性设置为SQL_CONCUR_READ_ONLY。

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

注释

注意

有关可以在 中调用 SQLBulkOperations 的语句以及它为与 ODBC 2 兼容而必须执行的操作的信息。x 应用程序,请参阅附录 G: 向后兼容性驱动程序指南中的块游标、可滚动游标和 向后兼容性部分。

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

  • 添加新行。

  • 更新一组行,其中每一行由书签标识。

  • 删除一组行,其中每行由书签标识。

  • 提取一组行,其中每行由书签标识。

调用 SQLBulkOperations 后,块游标位置未定义。 应用程序必须调用 SQLFetchScroll 来设置游标位置。 应用程序应仅使用 fetchOrientation 参数 SQL_FETCH_FIRST、SQL_FETCH_LAST、SQL_FETCH_ABSOLUTE 或 SQL_FETCH_BOOKMARK 调用 SQLFetchScroll。 如果应用程序使用fetchOrientation 参数 SQL_FETCH_PRIOR、SQL_FETCH_NEXT 或 SQL_FETCH_RELATIVE 调用 SQLFetch 或 SQLFetchScroll,则游标位置未定义。

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

应用程序在调用 SQLBulkOperations 时不需要设置 SQL_ATTR_ROW_OPERATION_PTR 语句属性,因为使用此函数执行批量操作时不能忽略行。

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

Operation 参数SQL_ADD或SQL_UPDATE_BY_BOOKMARK且与游标关联的查询规范选择列表包含对同一列的多个引用时,无论生成错误还是驱动程序忽略重复的引用并执行请求的操作,都是驱动程序定义的。

有关如何使用 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应为 null 指针。

  4. SQL_ADD) 调用 SQLBulkOperations (StatementHandle 来执行插入。

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

如果应用程序在调用 SQLBulkOperations 之前绑定列 0,其 Operation 参数为 SQL_ADD,驱动程序将使用新插入行的书签值更新绑定列 0 缓冲区。 为此,应用程序必须在执行语句之前将 SQL_ATTR_USE_BOOKMARKS 语句属性设置为SQL_UB_VARIABLE。 (这不适用于 ODBC 2。x driver.)

通过使用对 SQLParamData 和 SQLPutData 的调用,SQLBulkOperations 可以分部分添加长数据。 有关详细信息,请参阅此函数参考后面的“为大容量插入和汇报提供长数据”。

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

如果在包含重复列的游标上调用操作参数为 SQL_ADD 的 SQLBulkOperations,则行为是驱动程序定义的。 驱动程序可以返回驱动程序定义的 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应为 null 指针。

  7. SQL_UPDATE_BY_BOOKMARK) (StatementHandle 调用 SQLBulkOperations

    备注

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

  8. (可选) (StatementHandle 调用 SQLBulkOperations,SQL_FETCH_BY_BOOKMARK) 将数据提取到绑定的应用程序缓冲区,以验证是否已发生更新。

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

SQLBulkOperations 执行的批量更新可以通过调用 SQLParamData 和 SQLPutData 来包含长数据。 有关详细信息,请参阅此函数参考后面的“为大容量插入和汇报提供长数据”。

如果书签在游标之间保留,则应用程序不需要在通过书签更新之前调用 SQLFetchSQLFetchScroll 。 它可以使用从上一个游标中存储的书签。 如果书签不跨游标保留,则应用程序必须调用 SQLFetchSQLFetchScroll 来检索书签。

如果在包含重复列的游标上调用操作参数为 SQL_UPDATE_BY_BOOKMARK 的 SQLBulkOperations,则行为是驱动程序定义的。 驱动程序可以返回驱动程序定义的 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应为 null 指针。

  6. SQL_FETCH_BY_BOOKMARK) (StatementHandle 调用 SQLBulkOperations

  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应为 null 指针。

  6. SQL_DELETE_BY_BOOKMARK) (StatementHandle 调用 SQLBulkOperations

  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 中的SQL_NEED_LONG_DATA_LEN信息类型返回“Y”, 则 length 是要为参数发送的数据字节数;否则,它必须是非否定值,并且将被忽略。

  2. 调用 SQLBulkOperations 时,如果存在执行时数据列,该函数将返回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之后,在 SQLParamDataSQLPutData 中取消了操作,并且针对执行时的所有数据列发送数据之前,应用程序只能为语句或与语句关联的连接调用 SQLCancelSQLGetDiagFieldSQLGetDiagRecSQLGetFunctionsSQLParamDataSQLPutData。 如果它为语句或与语句关联的连接调用任何其他函数,则函数将返回SQL_ERROR,SQLSTATE HY010 (函数序列错误) 。

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

行状态数组

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

代码示例

以下示例一次从 Customers 表中提取 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 Function(SQLFetchScroll 函数)
获取描述符的单个字段 SQLGetDescField 函数
获取描述符的多个字段 SQLGetDescRec 函数
设置描述符的单个字段 SQLSetDescField 函数
设置描述符的多个字段 SQLSetDescRec 函数
定位游标、刷新行集中的数据,或者更新或删除行集中的数据 SQLSetPos 函数
设置语句属性 SQLSetStmtAttr 函数

另请参阅

ODBC API 参考
ODBC 头文件