一致性
推出版本: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 值, Handle 为 SQL_HANDLE_STMT,Handle 为 StatementHandle。 下表列出了 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,结果集中某列的数据值无法转换为调用 SQLBindCol 时 TargetType 参数指定的数据类型。 操作参数为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 调用了 SQLExecute、SQLExecDirect 或 SQLMoreResults,并返回了SQL_PARAM_DATA_AVAILABLE。 在检索所有流式处理参数的数据之前调用此函数。 (DM) 指定的 StatementHandle 未处于执行状态。 调用该函数时未先调用 SQLExecDirect、 SQLExecute 或目录函数。 (DM) 为 StatementHandle 调用异步执行函数(而不是此函数),并在调用此函数时仍在执行。 (DM) SQLExecute、 SQLExecDirect或 SQLSetPos被 调用了语 句Handle 并返回SQL_NEED_DATA。 在为所有数据执行参数或列发送数据之前调用此函数。 (DM)司机是ODBC 2型。x 驱动程序,并且在调用 SQLFetchScroll 或 SQLFetch 之前,先调用了 StatementHandle。 (DM) SQLBulkOperations 是在 StatementHandle 调用 SQLExtendedFetch 之后被调用的。 |
| HY011 | 无法立即设置属性 | (DM)司机是ODBC 2型。x 驱动程序,SQL_ATTR_ROW_STATUS_PTR语句属性在调用 SQLFetch 或 SQLFetchScroll 和 SQLBulkOperations 之间设置。 |
| 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字段中获得,可通过调用 SQLDescribeCol、 SQLColAttribute或 SQLGetDescField获得。) |
| 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。 如果应用程序调用 SQLFetch 或 SQLFetchScroll ,且 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 插入数据,应用程序执行以下步骤:
执行返回结果集的查询。
将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应为空指针。
调用 SQLBulkOperations(StatementHandle, SQL_ADD) 来执行插入。
如果应用程序设置了SQL_ATTR_ROW_STATUS_PTR语句属性,它可以检查该数组以查看操作结果。
如果应用程序在调用 SQLBulkOperations 前绑定了第 0 列,且 操作参数为 SQL_ADD,驱动程序会更新绑定的第 0 列缓冲区,并更新新插入行的书签值。 要实现这一点,应用程序必须在执行该语句前将SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_VARIABLE。 (这对ODBC 2不适用。x 驱动。)
SQLBulkOperations 可以通过调用 SQLParamData 和 SQLPutData 来分段添加长数据。 欲了解更多信息,请参见本函数参考文献后面的“为批量插入和更新提供长数据”。
应用程序在调用 SQLBulkOperations 之前无需先调用 SQLFetch 或 SQLFetchScroll(除非针对 ODBC 2 时)。x 驱动;参见向后兼容性与标准合规)。
如果在包含重复列的光标上调用 SQLBulkOperations,且 操作参数为 SQL_ADD,则该行为由驱动程序定义。 驱动程序可以返回驱动程序定义的 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应为空指针。
调用 SQLBulkOperations(StatementHandle, SQL_UPDATE_BY_BOOKMARK)。
注释
如果应用程序设置了SQL_ATTR_ROW_STATUS_PTR语句属性,它可以检查该数组以查看操作结果。
可选地调用 SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK) 将数据导入绑定的应用缓冲区,以验证更新是否已发生。
如果数据已被更新,驱动程序会将相应行的状态数组值更改为SQL_ROW_UPDATED。
SQLBulkOperations 执行的批量更新可以通过调用 SQLParamData 和 SQLPutData 来包含长数据。 欲了解更多信息,请参见本函数参考文献后面的“为批量插入和更新提供长数据”。
如果书签在各光标间持续存在,应用程序无需调用 SQLFetch 或 SQLFetchScroll 即可通过书签进行更新。 它可以使用之前光标存储的书签。 如果书签在光标间无法持久存在,应用程序必须调用 SQLFetch 或 SQLFetchScroll 来获取书签。
如果在包含重复列的光标上调用 SQLBulkOperations,且 操作参数为 SQL_UPDATE_BY_BOOKMARK,则该行为由驱动程序定义。 驱动程序可以返回驱动程序定义的 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应为空指针。
调用 SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK)。
如果应用程序设置了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应为空指针。
调用 SQLBulkOperations(StatementHandle, SQL_DELETE_BY_BOOKMARK)。
如果应用程序设置了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中返回“Y”作为SQL_NEED_LONG_DATA_LEN信息 类型,长度 是该参数要发送的数据字节数;否则,必须是非负值,且被忽略。
当调用 SQLBulkOperations 时,如果存在 data-at-execution 列,函数返回 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且所有执行时数据尚未发送前发生错误,应用程序只能调用 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。
代码示例
以下示例每次从客户表获取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 函数 |