SQLSetPos 函数

一致性
引入的版本:ODBC 1.0 标准符合性:ODBC

摘要
SQLSetPos 设置行集中的游标位置,并允许应用程序刷新行集中的数据,或者更新或删除结果集中的数据。

语法

  
SQLRETURN SQLSetPos(  
      SQLHSTMT        StatementHandle,  
      SQLSETPOSIROW   RowNumber,  
      SQLUSMALLINT    Operation,  
      SQLUSMALLINT    LockType);  

参数

StatementHandle
[输入]语句句柄。

RowNumber
[输入]行集中行的位置,该行对其执行 Operation 参数指定的 操作。 如果 RowNumber 为 0,则操作将应用于行集中的每一行。

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

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

SQL_POSITION SQL_REFRESH SQL_UPDATE SQL_DELETE

注意

ODBC 3.x 已弃用 Operation 参数的SQL_ADD值。 ODBC 3.x 驱动程序需要支持SQL_ADD以实现向后兼容性。 此功能已替换为对 SQLBulkOperations 的 调用,其 操作 为 SQL_ADD。 当 ODBC 3.x 应用程序使用 ODBC 2.x 驱动程序时,驱动程序管理器会将对 SQLBulkOperations 的调用与 操作 SQL_ADD映射到 SQLSetPos操作 为 SQL_ADD。

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

LockType
[输入]指定在执行 Operation 参数中指定的操作后如何锁定行。

SQL_LOCK_NO_CHANGE SQL_LOCK_EXCLUSIVE SQL_LOCK_UNLOCK

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

返回

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

诊断

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

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

SQLSTATE 错误 说明
01000 常规警告 特定于驱动程序的信息性消息。 (函数返回 SQL_SUCCESS_WITH_INFO.)
01001 游标操作冲突 Operation 参数SQL_DELETE或SQL_UPDATE,并且未删除或更新任何行或多行。 (有关多行更新的详细信息,请参阅 SQLSetStmtAttr.) (函数返回 SQL_SUCCESS_WITH_INFO.SQL_ATTR_SIMULATE_CURSOR 属性的说明)

Operation 参数SQL_DELETE或SQL_UPDATE,操作由于乐观并发而失败。 (函数返回 SQL_SUCCESS_WITH_INFO.)
01004 字符串数据右截断 Operation 参数已SQL_REFRESH,并且为数据类型为 SQL_C_CHAR 或 SQL_C_BINARY的列返回的字符串或二进制数据会导致截断非空字符或非 NULL 二进制数据。
01S01 行中出现错误 RowNumber 参数为 0,在执行 Operation 参数指定的操作时,一行或多行中出现错误。

如果多行操作的一行或多行(但不是全部)出现错误,则返回 (SQL_SUCCESS_WITH_INFO;如果在单行操作上发生错误,则返回SQL_ERROR。)

(仅当 SQLSetPosSQLExtendedFetch 之后调用时,如果驱动程序是 ODBC 2.x 驱动程序且未使用游标库,则返回此 SQLSTATE。)
01S07 小数截断 Operation 参数SQL_REFRESH,应用程序缓冲区的数据类型未SQL_C_CHAR或SQL_C_BINARY,并且一个或多个列返回到应用程序缓冲区的数据被截断。 对于数值数据类型,数字的小数部分被截断。 对于包含时间分量的时间、时间戳和间隔数据类型,时间的小数部分将被截断。

(函数返回 SQL_SUCCESS_WITH_INFO.)
07006 受限数据类型属性冲突 在调用 SQLBindCol 时,无法将结果集中列的数据值转换为 TargetType 指定的数据类型。
07009 描述符索引无效 参数 Operation 已SQL_REFRESH或SQL_UPDATE,并且一列绑定了大于结果集中列数的列号。
21S02 派生表的程度与列列表不匹配 参数 Operation 已SQL_UPDATE,并且没有可更新的列,因为所有列都是未绑定的、只读的,或者绑定长度/指示器缓冲区中的值SQL_COLUMN_IGNORE。
22001 字符串数据,右截断 Operation 参数已SQL_UPDATE,将字符或二进制值赋给列会导致截断) 字符的非空 (或二进制) 字符或字节的非 null (。
22003 数值范围外 参数 Operation 已SQL_UPDATE,将数值赋给结果集中的列会导致整个 (而不是小数部分) 部分被截断。

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

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

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

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

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

Operation 参数SQL_ REFRESH;分配给间隔 C 类型时,间隔 C 类型中没有 SQL 类型的值表示形式。
22018 强制转换规范的字符值无效 Operation 参数已SQL_REFRESH;C 类型为精确或近似数值、datetime 或 interval 数据类型;列的 SQL 类型为字符数据类型;列中的值不是绑定 C 类型的有效文本。

参数 Operation 已SQL_UPDATE;SQL 类型为精确或近似数值、datetime 或 interval 数据类型;C 类型SQL_C_CHAR;列中的值不是绑定 SQL 类型的有效文本。
23000 完整性约束冲突 参数 Operation 已SQL_DELETE或SQL_UPDATE,并且违反了完整性约束。
24000 游标状态无效 StatementHandle 处于已执行状态,但没有结果集与 StatementHandle 关联。

(DM) StatementHandle 上已打开游标,但尚未调用 SQLFetchSQLFetchScroll

在 StatementHandle 上打开游标,并且已调用 SQLFetchSQLFetchScroll,但游标位于结果集开始之前或结果集末尾之后。

参数 Operation 是SQL_DELETE、SQL_REFRESH或SQL_UPDATE,光标位于结果集开始之前或结果集末尾之后。
40001 序列化失败 由于与另一个事务发生资源死锁,事务已回滚。
40003 语句完成未知 在执行此函数期间,关联的连接失败,并且无法确定事务的状态。
42000 语法错误或访问冲突 驱动程序无法根据需要锁定行,以执行参数 Operation 中请求的操作。

驱动程序无法按照参数 LockType 中的要求锁定行。
44000 WITH CHECK OPTION 冲突 Operation 参数已SQL_UPDATE,并且对视图表或派生自查看表(通过指定 WITH CHECK OPTION 创建的表)执行更新,这样,受更新影响的一个或多个行将不再出现在查看的表中。
HY000 常规错误 发生错误,其中没有特定的 SQLSTATE,也没有定义特定于实现的 SQLSTATE。 SQLGetDiagRec*MessageText 缓冲区中返回的错误消息描述了错误及其原因。
HY001 内存分配错误 驱动程序无法分配支持执行或完成函数所需的内存。
HY008 操作已取消 已为 StatementHandle 启用异步处理。 调用了函数,在它完成执行之前,在 StatementHandle 上调用了 SQLCancel 或 SQLCancelHandle,然后在 StatementHandle 上再次调用该函数。

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

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

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

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

(DM) 驱动程序是 ODBC 2.x 驱动程序,在调用 SQLFetch 后,为 StatementHandle 调用了 SQLSetPos
HY011 现在无法设置属性 (DM) 驱动程序是 ODBC 2.x 驱动程序;已设置 SQL_ATTR_ROW_STATUS_PTR 语句属性;然后在调用 SQLFetchSQLFetchScrollSQLExtendedFetch 之前调用 SQLSetPos
HY013 内存管理错误 无法处理函数调用,因为无法访问基础内存对象,可能是由于内存不足。
HY090 无效的字符串或缓冲区长度 Operation 参数SQL_UPDATE,数据值为 null 指针,列长度值不是 0、SQL_DATA_AT_EXEC、SQL_COLUMN_IGNORE、SQL_NULL_DATA 或小于或等于 SQL_LEN_DATA_AT_EXEC_OFFSET。

操作参数SQL_UPDATE;数据值不是 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”。
HY092 属性标识符无效 (DM) 为 Operation 参数指定的值无效。

(DM) 为 LockType 参数指定的值无效。

Operation 参数SQL_UPDATE或SQL_DELETE,SQL_ATTR_CONCURRENCY 语句属性已SQL_ATTR_CONCUR_READ_ONLY。
HY107 行值范围外 为参数 RowNumber 指定的值大于行集中的行数。
HY109 游标位置无效 StatementHandle 关联的游标定义为仅向前游标,因此游标不能定位在行集中。 请参阅 SQLSetStmtAttr 中 SQL_ATTR_CURSOR_TYPE 属性的说明。

Operation 参数SQL_UPDATE、SQL_DELETE或SQL_REFRESH,RowNumber 参数标识的行已被删除或未提取。

(DM) RowNumber 参数为 0, 而 Operation 参数为SQL_POSITION。

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

注释

注意

有关 语句中可以调用 SQLSetPos 的信息以及它需要执行的操作才能与 ODBC 2.x 应用程序兼容,请参阅 块游标、可滚动游标和向后兼容性

RowNumber 参数

RowNumber 参数指定行集中执行 Operation 参数指定操作的行号。 如果 RowNumber 为 0,则操作将应用于行集中的每一行。 RowNumber 必须是从 0 到行集中行数的值。

注意

在 C 语言中,数组从 0 开始, RowNumber 参数从 1 开始。 例如,若要更新行集的第五行,应用程序将修改数组索引 4 处的行集缓冲区,但将 RowNumber 指定为 5。

所有操作将游标定位在 RowNumber 指定的行上。 以下操作需要游标位置:

  • 定位的 update 和 delete 语句。

  • 调用 SQLGetData

  • 使用SQL_DELETE、SQL_REFRESH和SQL_UPDATE选项调用 SQLSetPos

例如,如果对 SQLSetPos 的调用的 RowNumber 为 2,并且操作为 SQL_DELETE,则游标位于行集的第二行,并且删除该行。 实现行状态数组 (第二行的 SQL_ATTR_ROW_STATUS_PTR 语句属性) 指向的条目更改为SQL_ROW_DELETED。

应用程序可以在调用 SQLSetPos 时指定游标位置。 通常,它使用SQL_POSITION或SQL_REFRESH操作调用 SQLSetPos ,以在执行定位更新或删除语句或调用 SQLGetData 之前定位游标。

操作参数

Operation 参数支持以下操作。 若要确定数据源支持的选项,应用程序会根据游标) 的类型,使用SQL_DYNAMIC_CURSOR_ATTRIBUTES1、SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1、SQL_KEYSET_CURSOR_ATTRIBUTES1或SQL_STATIC_CURSOR_ATTRIBUTES1信息类型 (调用 SQLGetInfo

操作

参数
操作
SQL_POSITION 驱动程序将光标置于 RowNumber 指定的行上。

对于SQL_POSITION 操作,将忽略由 SQL_ATTR_ROW_OPERATION_PTR 语句属性指向的行状态数组的内容。
SQL_REFRESH 驱动程序将游标定位在 RowNumber 指定的行上,并刷新该行的行集缓冲区中的数据。 有关驱动程序如何在行集缓冲区中返回数据的详细信息,请参阅 SQLBindCol 中按行和按列绑定的说明。

操作为 SQL_REFRESHSQLSetPos 更新当前提取行集中行的状态和内容。 这包括刷新书签。 由于缓冲区中的数据已刷新但未重新填充,因此行集中的成员身份是固定的。 这与调用 SQLFetchScroll 时执行的刷新不同,该调用的 FetchOrientation 为 SQL_FETCH_RELATIVE, RowNumber 等于 0,后者从结果集中重新提取行集,以便在驱动程序和游标支持这些操作时显示添加的数据并删除已删除的数据。

使用 SQLSetPos 成功刷新不会更改SQL_ROW_DELETED的行状态。 行集中已删除的行将继续标记为已删除,直到下一次提取。 如果游标支持打包 (随后的 SQLFetchSQLFetchScroll 未) 返回已删除的行,则这些行将在下次提取时消失。

使用 SQLSetPos 执行刷新时,不会显示添加的行。 此行为不同于 SQLFetchScroll其 FetchType 为 SQL_FETCH_RELATIVE 且 RowNumber 等于 0,后者也会刷新当前行集,但如果游标支持这些操作,则会显示添加的记录或打包删除的记录。

如果行状态数组) 存在,使用 SQLSetPos 成功刷新会将SQL_ROW_ADDED的行状态更改为SQL_ROW_SUCCESS (。

如果行状态数组) 存在,使用 SQLSetPos 成功刷新会将行状态SQL_ROW_UPDATED更改为行的新状态 (。

如果对行执行 SQLSetPos 操作时出错,则行状态设置为SQL_ROW_ERROR (行状态数组是否存在) 。

对于使用 SQL_CONCUR_ROWVER 或 SQL_CONCUR_VALUES SQL_ATTR_CONCURRENCY 语句属性打开的游标,使用 SQLSetPos 刷新可能会更新数据源用于检测行已更改的乐观并发值。 如果发生这种情况,则每当从服务器刷新行集缓冲区时,都会更新用于确保游标并发的行版本或值。 对于刷新的每一行,都会发生这种情况。

对于SQL_REFRESH 操作,将忽略 SQL_ATTR_ROW_OPERATION_PTR 语句属性指向的行状态数组的内容。
SQL_UPDATE 驱动程序将游标定位在 RowNumber 指定的行上,并使用行集缓冲区中的值更新基础数据行 (SQLBindCol 中的 TargetValuePtr 参数) 。 它从长度/指示器缓冲区中检索数据的长度, (SQLBindCol) 中的 StrLen_or_IndPtr 参数。 如果任何列的长度SQL_COLUMN_IGNORE,则不会更新该列。 更新行后,如果行状态数组) 存在,驱动程序会将行状态数组的相应元素更改为SQL_ROW_UPDATED或SQL_ROW_SUCCESS_WITH_INFO (。

如果在包含重复列的游标上调用 Operation 参数为 SQL_UPDATE 的 SQLSetPos,则行为由驱动程序定义。 驱动程序可以返回驱动程序定义的 SQLSTATE,可以更新结果集中显示的第一列,也可以执行其他驱动程序定义的行为。

SQL_ATTR_ROW_OPERATION_PTR 语句属性指向的行操作数组可用于指示在批量更新期间应忽略当前行集中的行。 有关详细信息,请参阅此函数参考后面的“状态和操作数组”。
SQL_DELETE 驱动程序将光标置于 RowNumber 指定的行上,并删除基础数据行。 它将行状态数组的相应元素更改为SQL_ROW_DELETED。 删除行后,以下语句对行无效:定位的 update 和 delete 语句、对 SQLGetData 的调用,以及对 SQLSetPos 的调用,操作设置为除SQL_POSITION以外的任何内容。 对于支持打包的驱动程序,当从数据源检索新数据时,将从游标中删除该行。

该行是否保持可见取决于游标类型。 例如,已删除的行对静态游标和键集驱动的游标可见,但对动态游标不可见。

SQL_ATTR_ROW_OPERATION_PTR 语句属性指向的行操作数组可用于指示在批量删除期间应忽略当前行集中的行。 有关详细信息,请参阅此函数参考后面的“状态和操作数组”。

LockType 参数

LockType 参数为应用程序提供了一种控制并发的方法。 在大多数情况下,支持并发级别和事务的数据源仅支持 LockType 参数的SQL_LOCK_NO_CHANGE值。 LockType 参数通常仅用于基于文件的支持。

LockType 参数指定执行 SQLSetPos 后行的锁定状态。 如果驱动程序无法锁定行以执行请求的操作或满足 LockType 参数,它将返回SQL_ERROR和 SQLSTATE 42000 (语法错误或访问冲突) 。

尽管 LockType 参数是为单个语句指定的,但锁对连接上的所有语句拥有相同的特权。 具体而言,由连接上的一个语句获取的锁可以通过同一连接上的不同语句解锁。

通过 SQLSetPos 锁定的行一直处于锁定状态,直到应用程序为 LockType 设置为 SQL_LOCK_UNLOCK 的行调用 SQLSetPos,或者直到应用程序使用 SQL_CLOSE 选项调用语句的 SQLFreeHandleSQLFreeStmt。 对于支持事务的驱动程序,当应用程序调用 SQLEndTran 来提交或回滚连接 ((如果在提交或回滚事务时关闭游标)时,通过 SQLSetPos 锁定的行将解锁,SQL_CURSOR_COMMIT_BEHAVIOR SQLGetInfo) 返回的信息类型和SQL_CURSOR_ROLLBACK_BEHAVIOR信息类型。

LockType 参数支持以下类型的锁。 若要确定数据源支持哪些锁,应用程序使用SQL_DYNAMIC_CURSOR_ATTRIBUTES1、SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1、SQL_KEYSET_CURSOR_ATTRIBUTES1或SQL_STATIC_CURSOR_ATTRIBUTES1信息类型 (调用 SQLGetInfo ,具体取决于游标) 的类型。

LockType 参数 锁类型
SQL_LOCK_NO_CHANGE 驱动程序或数据源确保该行处于与调用 SQLSetPos 之前相同的锁定或解锁状态。 LockType 的此值允许不支持显式行级锁定的数据源使用当前并发和事务隔离级别所需的任何锁定。
SQL_LOCK_EXCLUSIVE 驱动程序或数据源以独占方式锁定行。 不同连接或其他应用程序中的语句不能用于获取行上的任何锁。
SQL_LOCK_UNLOCK 驱动程序或数据源解锁行。

如果驱动程序支持SQL_LOCK_EXCLUSIVE但不支持SQL_LOCK_UNLOCK,则锁定的行将保持锁定状态,直到上一段落中所述的函数调用之一发生。

如果驱动程序支持 SQL_LOCK_EXCLUSIVE 但不支持SQL_LOCK_UNLOCK,则锁定的行将保持锁定状态,直到应用程序使用 SQL_CLOSE 选项调用 SQLFreeHandle 语句或 SQLFreeStmt 。 如果驱动程序支持事务并在提交或回滚事务时关闭游标,则应用程序将调用 SQLEndTran

对于 SQLSetPos 中的更新和删除操作,应用程序使用 LockType 参数,如下所示:

  • 为了保证行在检索后不会更改,应用程序调用 SQLSetPos ,其中 Operation 设置为 SQL_REFRESH, LockType 设置为 SQL_LOCK_EXCLUSIVE。

  • 如果应用程序将 LockType 设置为 SQL_LOCK_NO_CHANGE,则驱动程序保证仅当应用程序为 SQL_ATTR_CONCURRENCY 语句属性指定SQL_CONCUR_LOCK时,更新或删除操作才会成功。

  • 如果应用程序为 SQL_ATTR_CONCURRENCY 语句属性指定SQL_CONCUR_ROWVER或SQL_CONCUR_VALUES,则驱动程序将比较行版本或值,如果自应用程序提取行后行已更改,则驱动程序将拒绝该操作。

  • 如果应用程序为 SQL_ATTR_CONCURRENCY 语句属性指定SQL_CONCUR_READ_ONLY,驱动程序将拒绝任何更新或删除操作。

有关 SQL_ATTR_CONCURRENCY 语句属性的详细信息,请参阅 SQLSetStmtAttr

状态和操作数组

调用 SQLSetPos 时使用以下状态和操作数组:

  • (IRD 中的SQL_DESC_ARRAY_STATUS_PTR字段所指向的行状态数组,SQL_ATTR_ROW_STATUS_ARRAY 语句属性) 包含行集中每行数据的状态值。 驱动程序在调用 SQLFetch、SQLFetchScrollSQLBulkOperationsSQLSetPos 后设置此数组中的状态值。 此数组由 SQL_ATTR_ROW_STATUS_PTR 语句属性指向。

  • (ARD 中的 SQL_DESC_ARRAY_STATUS_PTR 字段所指向的行操作数组,SQL_ATTR_ROW_OPERATION_ARRAY 语句属性) 包含行集中每行的值,该值指示是忽略还是执行批量操作的 SQLSetPos 调用。 数组中的每个元素都设置为SQL_ROW_PROCEED (默认) 或SQL_ROW_IGNORE。 此数组由 SQL_ATTR_ROW_OPERATION_PTR 语句属性指向。

状态和操作数组中的元素数必须等于行集中 () SQL_ATTR_ROW_ARRAY_SIZE语句属性定义的行数。

有关行状态数组的信息,请参阅 SQLFetch。 有关行操作数组的信息,请参阅本节后面的“忽略批量操作中的行”。

使用 SQLSetPos

在应用程序调用 SQLSetPos 之前,它必须执行以下一系列步骤:

  1. 如果应用程序调用操作设置为 SQL_UPDATE 的 SQLSetPos,请为每个列调用 SQLBindCol (或 SQLSetDescRec) ,以指定其数据类型并绑定列数据和长度的缓冲区。

  2. 如果应用程序调用操作设置为 SQL_DELETE 或 SQL_UPDATE 的 SQLSetPos,请调用 SQLColAttribute 以确保要删除或更新的列可更新。

  3. 调用 SQLExecDirectSQLExecute 或目录函数来创建结果集。

  4. 调用 SQLFetchSQLFetchScroll 以检索数据。

有关使用 SQLSetPos 的详细信息,请参阅 使用 SQLSetPos 更新数据

使用 SQLSetPos 删除数据

若要使用 SQLSetPos 删除数据,应用程序调用将 RowNumber 设置为要删除的行号,操作设置为 SQL_DELETE 的 SQLSetPos

删除数据后,驱动程序会将相应行的实现行状态数组中的值更改为SQL_ROW_DELETED (或SQL_ROW_ERROR) 。

使用 SQLSetPos 更新数据

应用程序可以在绑定数据缓冲区中传递列的值,也可以传递对 SQLPutData 的一个或多个调用。 使用 SQLPutData 传递数据的列称为 执行时数据。 它们通常用于发送SQL_LONGVARBINARY列和SQL_LONGVARCHAR列的数据,可以与其他列混合。

若要使用 SQLSetPos 更新数据,应用程序:

  1. 将值置于与 SQLBindCol 绑定的数据和长度/指示器缓冲区中:

    • 对于普通列,应用程序将新列值放在 *TargetValuePtr 缓冲区中,将该值的长度放在 *StrLen_or_IndPtr 缓冲区中。 如果不应更新行,应用程序会将SQL_ROW_IGNORE放在行操作数组的该行的 元素中。

    • 对于执行时数据列,应用程序将应用程序定义的值(如列号)放在 *TargetValuePtr 缓冲区中。 该值稍后可用于标识列。

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

  2. 调用将 Operation 参数设置为 SQL_UPDATE 的 SQLSetPos 以更新数据行。

    • 如果没有执行时数据列,则该过程已完成。

    • 如果存在任何执行时数据列,该函数将返回SQL_NEED_DATA并继续执行步骤 3。

  3. 调用 SQLParamData 以检索要处理的第一个数据列的 *TargetValuePtr 缓冲区的地址。 SQLParamData 返回SQL_NEED_DATA。 应用程序从 *TargetValuePtr 缓冲区检索应用程序定义的值。

    注意

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

    注意

    执行时数据参数是 SQL 语句中的参数,当使用 SQLExecDirect 或 SQLExecute 执行语句时,将使用 SQLPutData 发送数据。 它们与 SQLBindParameter 绑定,或使用 SQLSetDescRec 设置描述符进行绑定。 SQLParamData 返回的值是在 ParameterValuePtr 参数中传递给 SQLBindParameter 的 32 位值。

    注意

    执行时数据列是行集中的列,在使用 SQLSetPos 更新行时,将使用 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 可以返回可由 SQLSetPos 返回的任何 SQLSTATE。

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

如果操作被取消或 SQLParamDataSQLPutData 中发生错误, 在 SQLSetPos 返回SQL_NEED_DATA之后,在针对所有执行时数据列发送数据之前,应用程序只能为语句或与语句关联的连接调用 SQLCancelSQLGetDiagFieldSQLGetDiagRecSQLGetFunctionsSQLParamDataSQLPutData 。 如果它为 语句或与语句关联的连接调用任何其他函数,则函数将返回SQL_ERROR和 SQLSTATE HY010 (函数序列错误) 。

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

当与游标关联的查询规范的 SELECT-list 包含对同一列的多个引用时,无论是生成错误还是驱动程序忽略重复的引用并执行所请求的操作都是驱动程序定义的。

执行批量操作

如果 RowNumber 参数为 0,则驱动程序对行集中值为 SQL_ROW_PROCEED SQL_ATTR_ROW_OPERATION_PTR 语句属性指向的行操作数组中的每一行执行 Operation 参数中指定的操作。 这是 SQL_DELETE、SQL_REFRESH 或 SQL_UPDATE 的 Operation 参数的 RowNumber 参数的有效值,但不是SQL_POSITION。 操作为 SQL_POSITION 且 RowNumber 等于 0 的 SQLSetPos 将返回 SQLSTATE HY109 (游标位置) 无效。

如果发生与整个行集相关的错误(例如 SQLSTATE HYT00 (超时) 过期),驱动程序将返回SQL_ERROR和相应的 SQLSTATE。 行集缓冲区的内容未定义,游标位置保持不变。

如果发生与单个行相关的错误,驱动程序将:

  • 将 SQL_ATTR_ROW_STATUS_PTR 语句属性指向的行状态数组中行的 元素设置为SQL_ROW_ERROR。

  • 在错误队列中为错误发布一个或多个附加 SQLSTATE,并在诊断数据结构中设置SQL_DIAG_ROW_NUMBER字段。

处理错误或警告后,如果驱动程序完成行集中剩余行的操作,则返回SQL_SUCCESS_WITH_INFO。 因此,对于返回错误的每一行,错误队列包含零个或多个其他 SQLSTATE。 如果驱动程序在处理错误或警告后停止操作,则返回SQL_ERROR。

如果驱动程序返回任何警告(例如 SQLSTATE 01004 (数据截断) ),则会在返回适用于特定行的错误信息之前返回适用于整个行集或行集中未知行的警告。 它返回特定行的警告以及有关这些行的任何其他错误信息。

如果 RowNumber 等于 0,并且 操作 SQL_UPDATE、SQL_REFRESH或SQL_DELETE,则 sqlSetPos 操作的行数由 SQL_ATTR_ROWS_FETCHED_PTR 语句属性指向。

如果 RowNumber 等于 0 且 操作 SQL_DELETE、SQL_REFRESH或SQL_UPDATE,则操作后的当前行与操作前的当前行相同。

在批量操作中忽略行

行操作数组可用于指示在使用 SQLSetPos 的批量操作期间应忽略当前行集中的行。 若要指示驱动程序在批量操作期间忽略一行或多行,应用程序应执行以下步骤:

  1. 调用 SQLSetStmtAttr 将 SQL_ATTR_ROW_OPERATION_PTR 语句属性设置为指向 SQLUSMALLINT 数组。 还可以通过调用 SQLSetDescField 来设置 ARD 的 SQL_DESC_ARRAY_STATUS_PTR 标头字段来设置此字段,这要求应用程序获取描述符句柄。

  2. 将行操作数组的每个元素设置为以下两个值之一:

    • SQL_ROW_IGNORE,以指示为大容量操作排除了该行。

    • SQL_ROW_PROCEED,以指示该行包含在批量操作中。 (这是默认值。)

  3. 调用 SQLSetPos 以执行批量操作。

以下规则适用于行操作数组:

  • SQL_ROW_IGNORE和SQL_ROW_PROCEED仅影响使用 SQLSetPos SQL_DELETE 或 SQL_UPDATE 的批量操作 。 它们不会影响对操作为 SQL_REFRESH 或 SQL_POSITION 的 SQLSetPos 的调用。

  • 默认情况下,指针设置为 null。

  • 如果指针为 null,则更新所有行,就像所有元素都设置为SQL_ROW_PROCEED一样。

  • 将 元素设置为 SQL_ROW_PROCEED 并不能保证操作将发生在该特定行上。 例如,如果行集中的某一行具有SQL_ROW_ERROR状态,则驱动程序可能无法更新该行,而不管应用程序是否SQL_ROW_PROCEED。 应用程序必须始终检查行状态数组,以查看操作是否成功。

  • SQL_ROW_PROCEED在头文件中定义为 0。 应用程序可以将行操作数组初始化为 0,以便处理所有行。

  • 如果行操作数组中的元素编号“n”设置为 SQL_ROW_IGNORE并且调用 SQLSetPos 来执行批量更新或删除操作,则行集中的第 n 行在调用 SQLSetPos 后保持不变。

  • 应用程序应自动将只读列设置为SQL_ROW_IGNORE。

在批量操作中忽略列

为了避免尝试更新一个或多个只读列时生成的不必要的处理诊断,应用程序可以将绑定长度/指示器缓冲区中的值设置为SQL_COLUMN_IGNORE。 有关详细信息,请参阅 SQLBindCol

代码示例

在以下示例中,应用程序允许用户浏览 ORDERS 表并更新订单状态。 游标由键集驱动,行集大小为 20,并使用比较行版本的乐观并发控制。 提取每个行集后,应用程序将打印它,并允许用户选择和更新订单的状态。 应用程序使用 SQLSetPos 将光标定位在所选行上,并执行行的定位更新。 为清楚起见,省略 (错误处理。)

#define ROWS 20  
#define STATUS_LEN 6  
  
SQLCHAR        szStatus[ROWS][STATUS_LEN], szReply[3];  
SQLINTEGER     cbStatus[ROWS], cbOrderID;  
SQLUSMALLINT   rgfRowStatus[ROWS];  
SQLUINTEGER    sOrderID, crow = ROWS, irow;  
SQLHSTMT       hstmtS, hstmtU;  
  
SQLSetStmtAttr(hstmtS, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0);  
SQLSetStmtAttr(hstmtS, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0);  
SQLSetStmtAttr(hstmtS, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0);  
SQLSetStmtAttr(hstmtS, SQL_ATTR_ROW_STATUS_PTR, (SQLPOINTER) rgfRowStatus, 0);  
SQLSetCursorName(hstmtS, "C1", SQL_NTS);  
SQLExecDirect(hstmtS, "SELECT ORDERID, STATUS FROM ORDERS ", SQL_NTS);  
  
SQLBindCol(hstmtS, 1, SQL_C_ULONG, &sOrderID, 0, &cbOrderID);  
SQLBindCol(hstmtS, 2, SQL_C_CHAR, szStatus, STATUS_LEN, &cbStatus);  
  
while ((retcode == SQLFetchScroll(hstmtS, SQL_FETCH_NEXT, 0)) != SQL_ERROR) {  
   if (retcode == SQL_NO_DATA_FOUND)  
      break;  
   for (irow = 0; irow < crow; irow++) {  
      if (rgfRowStatus[irow] != SQL_ROW_DELETED)  
         printf("%2d %5d %*s\n", irow+1, sOrderID, NAME_LEN-1, szStatus[irow]);  
   }  
   while (TRUE) {  
      printf("\nRow number to update?");  
      gets_s(szReply, 3);  
      irow = atoi(szReply);  
      if (irow > 0 && irow <= crow) {  
         printf("\nNew status?");  
         gets_s(szStatus[irow-1], (ROWS * STATUS_LEN));  
         SQLSetPos(hstmtS, irow, SQL_POSITION, SQL_LOCK_NO_CHANGE);  
         SQLPrepare(hstmtU,  
          "UPDATE ORDERS SET STATUS=? WHERE CURRENT OF C1", SQL_NTS);  
         SQLBindParameter(hstmtU, 1, SQL_PARAM_INPUT,  
            SQL_C_CHAR, SQL_CHAR,  
            STATUS_LEN, 0, szStatus[irow], 0, NULL);  
         SQLExecute(hstmtU);  
      } else if (irow == 0) {  
         break;  
      }  
   }  
}  

有关更多示例,请参阅 定位更新和删除语句 和使用 SQLSetPos 更新行集中的行

有关以下方面的信息 请参阅
将缓冲区绑定到结果集中的列 SQLBindCol 函数
执行与块光标位置无关的批量操作 SQLBulkOperations 函数
取消语句处理 SQLCancel 函数
提取数据块或滚动浏览结果集 SQLFetchScroll Function(SQLFetchScroll 函数)
获取描述符的单个字段 SQLGetDescField 函数
获取描述符的多个字段 SQLGetDescRec 函数
设置描述符的单个字段 SQLSetDescField 函数
设置描述符的多个字段 SQLSetDescRec 函数
设置语句属性 SQLSetStmtAttr 函数

另请参阅

ODBC API 参考
ODBC 头文件