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操作映射到具有SQL_ADD操作的 SQLSetPos

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

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 of SQL_HANDLE_STMT 和 Handle of StatementHandle 调用 SQLGetDiagRec 来获取关联的 SQLSTATE 值。 下表列出了 SQLSetPos 通常返回的 SQLSTATE 值,并解释此函数上下文中的每个值;表示法“(DM)”位于驱动程序管理器返回的 SQLSTATE 的说明之前。 除非另有说明,否则与每个 SQLSTATE 值关联的返回代码SQL_ERROR。

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

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

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。

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

(函数返回SQL_SUCCESS_WITH_INFO。)
07006 受限数据类型属性冲突 无法将结果集中列的数据值转换为对 SQLBindCol 的调用中 TargetType 指定的数据类型。
07009 描述符索引无效 参数 操作 SQL_REFRESH或SQL_UPDATE,列与列数大于结果集中的列数绑定。
21S02 派生表的程度与列列表不匹配 参数 操作 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,并且结果集中要发送到列的数据的日期/时间算术的性能导致结果的日期/时间字段(年、月、日、小时、分钟或秒字段)超出字段的允许值范围,或者根据公历日期时间的自然规则无效。

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

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

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

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

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

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

游标在 StatementHandle 上打开,并且已调用 SQLFetch 或 SQLFetchScroll,但游标位于结果集的开头或结果集末尾之后。

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

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

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

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

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

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

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

Operation 参数SQL_UPDATE;数据值不是空指针;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或特定于数据源的长数据类型;SQLGetInfoSQL_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 关联的游标被定义为仅向前,因此游标不能放置在行集中。 请参阅 SQLSetStmtAttrSQL_ATTR_CURSOR_TYPE属性的说明。

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

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

在调用 SQLBulkOperations 和调用 SQLFetchScrollSQLFetch 之前调用 SQLSetPos
HY117 连接因未知事务状态而挂起。 仅允许断开连接和只读函数。 (DM) 有关挂起状态的详细信息,请参阅 SQLEndTran 函数
HYC00 未实现可选功能 驱动程序或数据源不支持 Operation 参数或 LockType 参数中请求的操作。
HYT00 已超时 在数据源返回结果集之前,查询超时期限已过期。 超时期限是通过具有SQL_ATTR_QUERY_TIMEOUT属性的 SQLSetStmtAttr 设置的。
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 指定的行上。 以下操作需要游标位置:

  • 定位更新和删除语句。

  • 对 SQLGetData调用。

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

例如,如果 RowNumber 为 2,则调用具有SQL_DELETE操作的 SQLSetPos 时,游标将放置在行集的第二行上并删除该行。 第二行的实现行状态数组中的条目(由 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

操作

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

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

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

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

执行 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(如果行状态数组存在)。

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

SQL_ATTR_ROW_OPERATION_PTR语句属性指向的行操作数组可用于指示在批量更新期间应忽略当前行集中的行。 有关详细信息,请参阅此函数参考后面的“状态和操作数组”。
SQL_DELETE 驱动程序将光标置于 RowNumber 指定的行上,并删除基础数据行。 它将行状态数组的相应元素更改为SQL_ROW_DELETED。 删除行后,以下内容对行无效:定位的更新和删除语句、对 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 选项为语句或 SQLFreeStmt 调用 SQLFreeHandle。 对于支持事务的驱动程序,当应用程序调用 SQLEndTran 提交或回滚连接上的事务(如果提交或回滚事务时关闭游标,如 sqlGetInfo 返回的SQL_CURSOR_COMMIT_BEHAVIOR和SQL_CURSOR_ROLLBACK_BEHAVIOR信息类型所指示)时,通过 SQLSetPos 锁定的行将解锁。

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 选项为语句或 SQLFreeStmt 调用 SQLFreeHandle。 如果驱动程序支持事务并在提交或回滚事务时关闭游标,应用程序将调用 SQLEndTran

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

  • 为了保证行在检索后不会更改,应用程序调用 SQLSetPos操作设置为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 设置为要删除的行数的 SQLSetPos,并将操作设置为SQL_DELETE。

删除数据后,驱动程序会将相应行的实现行状态数组中的值更改为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(length) 宏的结果置于 *StrLen_or_IndPtr 缓冲区中。 如果列的 SQL 数据类型是SQL_LONGVARBINARY、SQL_LONGVARCHAR或特定于数据源的长数据类型,并且驱动程序为 SQLGetInfoSQL_NEED_LONG_DATA_LEN信息类型返回“Y”,则长度为要为参数发送的数据字节数;否则,它必须是非负值并被忽略。

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

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

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

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

    注意

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

    注意

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

    注意

    执行时的数据列是行集中的列,在使用 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。

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

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

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

执行批量操作

如果 RowNumber 参数为 0,则驱动程序对行集中的每一行执行 Operation 参数中指定的操作,该行集中的行操作数组中其字段中的值为 SQL_ROW_PROCEED,该行的字段由 SQL_ATTR_ROW_OPERATION_PTR 语句属性指向。 这是 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 并且 Operation 为 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仅影响使用具有SQL_DELETE或SQL_UPDATE操作的 SQLSetPos 的批量操作。 它们不会影响对具有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 在行集中定位的 Update 和 Delete 语句和更新行。

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

另请参阅

ODBC API 参考
ODBC 头文件