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 上调用了 SQLCancel 或 SQLCancelHandle。 然后,在 StatementHandle 上再次调用该函数。 函数已调用,在它完成执行之前, SQLCancel 或 SQLCancelHandle 是从多线程应用程序中的不同线程在 StatementHandle 上调用的。 |
HY010 | 函数序列错误 | (DM) 为 与 StatementHandle 关联的连接句柄调用了异步执行的函数。 调用 SQLBulkOperations 函数时,此异步函数仍在执行。 (DM) SQLExecute、 SQLExecDirect 或 SQLMoreResults 已为 StatementHandle 调用并返回SQL_PARAM_DATA_AVAILABLE。 此函数是在检索所有流式处理参数的数据之前调用的。 (DM) 指定的 StatementHandle 未处于执行状态。 该函数是在未首先调用 SQLExecDirect、 SQLExecute 或目录函数的情况下调用的。 (DM) 为 StatementHandle 调用了异步执行的函数 (不是此函数) ,并且调用此函数时仍在执行。 (DM) SQLExecute、 SQLExecDirect 或 SQLSetPos 已为 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 语句属性是在调用 SQLFetch 或 SQLFetchScroll 和 SQLBulkOperations 之间设置的。 |
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 字段中提供,可通过调用 SQLDescribeCol、 SQLColAttribute 或 SQLGetDescField.) |
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 插入数据,应用程序将执行以下一系列步骤:
执行返回结果集的查询。
将 SQL_ATTR_ROW_ARRAY_SIZE 语句属性设置为要插入的行数。
调用 SQLBindCol 以绑定它要插入的数据。 数据绑定到大小等于 SQL_ATTR_ROW_ARRAY_SIZE 值的数组。
注意
SQL_ATTR_ROW_STATUS_PTR 语句属性指向的数组的大小应等于 SQL_ATTR_ROW_ARRAY_SIZE 或SQL_ATTR_ROW_STATUS_PTR应为 null 指针。
SQL_ADD) 调用 SQLBulkOperations (StatementHandle 来执行插入。
如果应用程序已设置 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 (之前调用 SQLFetch 或 SQLFetchScroll,除非针对 ODBC 2 调用。x 驱动程序;请参阅向后兼容性和标准合规性) 。
如果在包含重复列的游标上调用操作参数为 SQL_ADD 的 SQLBulkOperations,则行为是驱动程序定义的。 驱动程序可以返回驱动程序定义的 SQLSTATE,将数据添加到结果集中显示的第一列,或执行其他驱动程序定义的行为。
使用书签执行批量汇报
若要将书签与 SQLBulkOperations 配合使用来执行批量更新,应用程序将按顺序执行以下步骤:
将 SQL_ATTR_USE_BOOKMARKS 语句属性设置为 SQL_UB_VARIABLE。
执行返回结果集的查询。
将 SQL_ATTR_ROW_ARRAY_SIZE 语句属性设置为要更新的行数。
调用 SQLBindCol 以绑定要更新的数据。 数据绑定到大小等于 SQL_ATTR_ROW_ARRAY_SIZE 值的数组。 它还调用 SQLBindCol 将列 0 (书签列) 绑定。
将想要更新的行的书签复制到绑定到第 0 列的数组中。
汇报绑定缓冲区中的数据。
备注
SQL_ATTR_ROW_STATUS_PTR 语句属性指向的数组的大小应等于 SQL_ATTR_ROW_ARRAY_SIZE 或SQL_ATTR_ROW_STATUS_PTR应为 null 指针。
SQL_UPDATE_BY_BOOKMARK) (StatementHandle 调用 SQLBulkOperations。
备注
如果应用程序已设置 SQL_ATTR_ROW_STATUS_PTR 语句属性,它可以检查此数组以查看操作的结果。
(可选) (StatementHandle 调用 SQLBulkOperations,SQL_FETCH_BY_BOOKMARK) 将数据提取到绑定的应用程序缓冲区,以验证是否已发生更新。
如果数据已更新,驱动程序会将相应行的行状态数组中的值更改为SQL_ROW_UPDATED。
SQLBulkOperations 执行的批量更新可以通过调用 SQLParamData 和 SQLPutData 来包含长数据。 有关详细信息,请参阅此函数参考后面的“为大容量插入和汇报提供长数据”。
如果书签在游标之间保留,则应用程序不需要在通过书签更新之前调用 SQLFetch 或 SQLFetchScroll 。 它可以使用从上一个游标中存储的书签。 如果书签不跨游标保留,则应用程序必须调用 SQLFetch 或 SQLFetchScroll 来检索书签。
如果在包含重复列的游标上调用操作参数为 SQL_UPDATE_BY_BOOKMARK 的 SQLBulkOperations,则行为是驱动程序定义的。 驱动程序可以返回驱动程序定义的 SQLSTATE、更新结果集中显示的第一列,或执行其他驱动程序定义的行为。
使用书签执行批量提取
若要使用书签和 SQLBulkOperations 执行批量提取,应用程序将按顺序执行以下步骤:
将 SQL_ATTR_USE_BOOKMARKS 语句属性设置为 SQL_UB_VARIABLE。
执行返回结果集的查询。
将 SQL_ATTR_ROW_ARRAY_SIZE 语句属性设置为要提取的行数。
调用 SQLBindCol 以绑定它要提取的数据。 数据绑定到大小等于 SQL_ATTR_ROW_ARRAY_SIZE 值的数组。 它还调用 SQLBindCol 将列 0 (书签列) 绑定。
将它感兴趣的行的书签复制到绑定到第 0 列的数组中。 (这假定应用程序已单独获取书签。)
备注
SQL_ATTR_ROW_STATUS_PTR 语句属性指向的数组的大小应等于 SQL_ATTR_ROW_ARRAY_SIZE 或SQL_ATTR_ROW_STATUS_PTR应为 null 指针。
SQL_FETCH_BY_BOOKMARK) (StatementHandle 调用 SQLBulkOperations。
如果应用程序已设置 SQL_ATTR_ROW_STATUS_PTR 语句属性,它可以检查此数组以查看操作的结果。
如果书签在游标之间保留,则应用程序无需在按书签提取之前调用 SQLFetch 或 SQLFetchScroll 。 它可以使用从上一个游标中存储的书签。 如果书签不跨游标保留,则应用程序必须调用 SQLFetch 或 SQLFetchScroll 一次才能检索书签。
使用书签执行批量删除
若要使用书签和 SQLBulkOperations 执行批量删除,应用程序将按顺序执行以下步骤:
将 SQL_ATTR_USE_BOOKMARKS 语句属性设置为 SQL_UB_VARIABLE。
执行返回结果集的查询。
将 SQL_ATTR_ROW_ARRAY_SIZE 语句属性设置为要删除的行数。
调用 SQLBindCol (书签列) 绑定列 0。
将想要删除的行的书签复制到绑定到第 0 列的数组中。
备注
SQL_ATTR_ROW_STATUS_PTR 语句属性指向的数组的大小应等于 SQL_ATTR_ROW_ARRAY_SIZE 或SQL_ATTR_ROW_STATUS_PTR应为 null 指针。
SQL_DELETE_BY_BOOKMARK) (StatementHandle 调用 SQLBulkOperations。
如果应用程序已设置 SQL_ATTR_ROW_STATUS_PTR 语句属性,它可以检查此数组以查看操作的结果。
如果书签在游标之间保留,则应用程序不必在书签删除之前调用 SQLFetch 或 SQLFetchScroll 。 它可以使用从上一个游标中存储的书签。 如果书签不跨游标保留,则应用程序必须调用 SQLFetch 或 SQLFetchScroll 一次才能检索书签。
为大容量插入和汇报提供长数据
可以通过调用 SQLBulkOperations 来为批量插入和更新提供长数据。 若要插入或更新长数据,除了本主题前面的“执行批量插入”和“使用书签执行批量汇报”部分中所述的步骤外,应用程序还会执行以下步骤。
使用 SQLBindCol 绑定数据时,应用程序会将应用程序定义的值(如列号)放置在执行时数据列的 TargetValuePtr 缓冲区中。 该值稍后可用于标识列。
应用程序将SQL_LEN_DATA_AT_EXEC (长度 的结果) 宏放置在 *StrLen_or_IndPtr 缓冲区中。 如果列的 SQL 数据类型SQL_LONGVARBINARY、SQL_LONGVARCHAR或特定于数据源的长数据类型,并且驱动程序为 SQLGetInfo 中的SQL_NEED_LONG_DATA_LEN信息类型返回“Y”, 则 length 是要为参数发送的数据字节数;否则,它必须是非否定值,并且将被忽略。
调用 SQLBulkOperations 时,如果存在执行时数据列,该函数将返回SQL_NEED_DATA并继续执行步骤 3,如下所示。 (如果没有执行时数据列,则表示该过程已完成。)
应用程序调用 SQLParamData 来检索要处理的第一个执行时数据列的 *TargetValuePtr 缓冲区的地址。 SQLParamData 返回SQL_NEED_DATA。 应用程序从 *TargetValuePtr 缓冲区检索应用程序定义的值。
备注
尽管执行时数据参数类似于执行时数据列,但 SQLParamData 为每个列返回的值是不同的。
执行时数据列是行集中的列,在使用 SQLBulkOperations 更新或插入行时,将使用 SQLPutData 发送数据。 它们与 SQLBindCol 绑定。 SQLParamData 返回的值是 *TargetValuePtr 缓冲区中正在处理的行的地址。
应用程序调用 SQLPutData 一次或多次以发送列的数据。 如果无法在 SQLPutData 中指定的 *TargetValuePtr 缓冲区中返回所有数据值,则需要多次调用;仅当将字符 C 数据发送到具有字符、二进制或数据源特定数据类型的列,或者将二进制 C 数据发送到具有字符、二进制或数据源特定数据类型的列时,才允许对同一列的 SQLPutData 进行多次调用。
应用程序再次调用 SQLParamData ,以指示已为列发送所有数据。
如果有更多执行时数据列, SQLParamData 将返回SQL_NEED_DATA以及要处理的下一个执行时数据列 的 TargetValuePtr 缓冲区的地址。 应用程序重复步骤 4 和 5。
如果没有更多执行时数据列,则表示该过程已完成。 如果成功执行语句, SQLParamData 将返回SQL_SUCCESS或SQL_SUCCESS_WITH_INFO;如果执行失败,则返回SQL_ERROR。 此时, SQLParamData 可以返回可由 SQLBulkOperations 返回的任何 SQLSTATE。
如果在 SQLBulkOperations 返回SQL_NEED_DATA之后,在 SQLParamData 或 SQLPutData 中取消了操作,并且针对执行时的所有数据列发送数据之前,应用程序只能为语句或与语句关联的连接调用 SQLCancel、SQLGetDiagField、SQLGetDiagRec、SQLGetFunctions、SQLParamData 或 SQLPutData。 如果它为语句或与语句关联的连接调用任何其他函数,则函数将返回SQL_ERROR,SQLSTATE HY010 (函数序列错误) 。
如果应用程序调用 SQLCancel ,而驱动程序仍需要执行时数据列的数据,则驱动程序将取消该操作。 然后,应用程序可以再次调用 SQLBulkOperations ;取消不会影响游标状态或当前游标位置。
行状态数组
行状态数组包含调用 SQLBulkOperations 后行集中每行数据的状态值。 调用 SQLFetch、 SQLFetchScroll、 SQLSetPos 或 SQLBulkOperations 后,驱动程序将设置此数组中的状态值。 如果在 SQLBulkOperations 之前尚未调用 SQLFetch 或 SQLFetchScroll ,则最初通过调用 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 函数 |