ODBC 表值参数的用法

本主题介绍将表值参数用于 ODBC 时的主要用户情况:

  • 完全绑定多行缓冲区情况下的表值参数(在所有值都位于内存中时将数据作为 TVP 发送)

  • 行流式处理情况下的表值参数(使用执行时数据将数据作为 TVP 发送)

  • 从系统目录中检索表值参数元数据

  • 检索准备的语句的表值参数元数据

完全绑定多行缓冲区情况下的表值参数(在所有值都位于内存中时将数据作为 TVP 发送)

用于完全绑定多行缓冲区时,所有参数值都位于内存中。 这是 OLTP 事务(举例来说)的典型情况,在这种情况下,可以将表值参数封装到单个存储过程中。 如果不使用表值参数,这通常需要动态生成复杂的多语句批处理,或者执行多个针对服务器的调用。

通过将 SQLBindParameter 与其他参数配合使用,可以对表值参数本身进行绑定。 绑定所有参数后,应用程序将对每个表值参数设置参数焦点属性 SQL_SOPT_SS_PARAM_FOCUS,并且为表值参数各列调用 SQLBindParameter

表值参数的服务器类型是特定于 SQL Server 的新增类型 SQL_SS_TABLE。 SQL_SS_TABLE 的绑定 C 类型必须始终为 SQL_C_DEFAULT。 不为表值参数绑定参数传输任何数据;该参数用于传递表元数据,并且控制如何传递表值参数各构成列中的数据。

表值参数的长度设置为要发送到服务器的行数。 表值参数的 SQLBindParameter 的 ColumnSize 参数指定可以发送的最大行数;这是列缓冲区的数组大小。 ParameterValuePtr 是 SQLBindParameter 中的表值参数的参数缓冲区。 ParameterValuePtr 及其关联 BufferLength 用于按需传递表值参数的类型名称。 类型名称不是存储过程调用必需的,但却是 SQL 语句所必需的。

在对 SQLBindParameter 的调用指定表值参数类型名称时,必须始终将该名称指定为 Unicode 值,即便在作为 ANSI 应用程序生成的应用程序中也是如此。 使用 SQLSetDescField 指定表值参数类型名称时,可以使用与应用程序生成方式相符的文字。 ODBC 驱动程序管理器将执行任何所需的 Unicode 转换。

通过使用 SQLGetDescRecSQLSetDescRecSQLGetDescFieldSQLSetDescField,可以分别且显式操作表值参数和表值参数列的元数据。 不过,重载 SQLBindParameter 通常更为方便,并且在多数情况下不要求显式描述符访问权限。 此方法与其他数据类型的 SQLBindParameter 的定义是一致的,只不过对于表值参数,受影响的描述符字段稍有不同。

有时,应用程序将表值参数用于动态 SQL,此时必须提供该表值参数的类型名称。 如果是这样,但是没有在连接的当前默认架构中定义表值参数,则必须使用 SQLSetDescField 设置 SQL_CA_SS_TYPE_CATALOG_NAME 和 SQL_CA_SS_TYPE_SCHEMA_NAME。 由于表类型定义和表值参数必须位于同一数据库中,在应用程序使用表值参数时不能设置 SQL_CA_SS_TYPE_CATALOG_NAME。 否则,SQLSetDescField 将报告错误。

此情况的示例代码位于使用表值参数 (ODBC)中的过程 demo_fixed_TVP_binding 内。

行流式处理情况下的表值参数(使用执行时数据将数据作为 TVP 发送)

在此情况下,应用程序在驱动程序请求行时向其提供行,并且这些行流向服务器。 这样就无需将所有行缓存在内存中。 这是大容量插入/更新时的典型情况。 表值参数提供了介于参数数组和大容量复制之间的某个性能点。 也就是说:表值参数可以像参数数组那样易于编程,但它们在服务器端提供更高的灵活性。

表值参数及其列按上一节“完全绑定多行缓冲区情况下的表值参数”所述进行绑定,但是表值参数本身的长度指示器设置为 SQL_DATA_AT_EXEC。 驱动程序按照通常响应执行时数据参数的方式(即通过返回 SQL_NEED_DATA)响应 SQLExecuteSQLExecuteDirect。 当驱动程序准备好接收表值参数的数据时,SQLParamData 将返回 SQLBindParameter 中的 ParameterValuePtr 的值。

应用程序使用表值参数的 SQLPutData 来指示表值参数构成列的数据的可用性。 为表值参数调用 SQLPutData 时,DataPtr 必须始终为 Null,并且 StrLen_or_Ind 必须为 0 或小于等于为表值参数缓冲区指定的数组大小(SQLBindParameter 的 ColumnSize 参数)的数字。 0 表示表值参数没有更多的行,驱动程序将继续处理下一个实际过程参数。 如果 StrLen_or_Ind 不为 0,驱动程序将按照处理非表值参数绑定参数的方式处理表值参数构成列:每个表值参数列可以指定其实际数据长度、SQL_NULL_DATA,或者通过其长度/指示器缓冲区指定执行时数据。 如果要分块传递某个字符或二进制值,则可以按通常方式通过重复调用 SQLPutData 来传递表值参数列值。

处理完所有表值参数列后,驱动程序将返回到表值参数以处理更多的表值参数数据行。 因此,对于执行时数据表值参数,驱动程序不遵循通常的顺序扫描绑定参数的方式。 将对绑定的表值参数进行轮询,直到调用 SQLPutData(同时 StrLen_Or_IndPtr 等于 0),此时应用程序将跳过表值参数列值,移至下一个实际存储过程参数。 当 SQLPutData 传递大于等于 1 的指示器值时,驱动程序顺序处理表值参数列和行,直到获取所有绑定行和列的值。 然后驱动程序返回到表值参数。 在从 SQLParamData 接收表值参数的标记与为 SQLPutData(hstmt, NULL, n) 调用表值参数之间,应用程序必须设置表值参数构成列数据和指示器缓冲区内容,以便向服务器传递之后的一个或多个行。

此情况的示例代码位于使用表值参数 (ODBC)中的例程 demo_variable_TVP_binding 内。

从系统目录中检索表值参数元数据

当应用程序为具有表值参数的过程调用 SQLProcedureColumns 时,DATA_TYPE 将返回为 SQL_SS_TABLE,并且 TYPE_NAME 是表值参数的表类型的名称。 SQLProcedureColumns 返回的结果集中还添加了两个附加列:SS_TYPE_CATALOG_NAME 返回定义表值参数的表类型的目录名称,SS_TYPE_SCHEMA_NAME 返回定义表值参数的表类型的架构名称。 为了符合 ODBC 规范,SS_TYPE_CATALOG_NAME 和 SS_TYPE_SCHEMA_NAME 的显示位置位于 SQL Server 早期版本中添加的所有驱动程序特定列之前,ODBC 自身托管的所有列之后。

不仅将为表值参数填充这些新列,还将为 CLR 用户定义类型参数填充这些新列。 仍将填充 UDT 参数的现有架构和目录列,但是为数据类型提供所需的常见架构和目录列将简化未来的应用程序开发。 (请注意,XML 架构集合稍有不同,未包括在此更改中。)

应用程序使用 SQLTables 确定表类型的名称,这与确定持久性表、系统表和视图的名称时的方式相同。 引入了一个新的表类型 TABLE TYPE,该类型支持应用程序标识与表值参数关联的表类型。 表类型和常规表使用不同的命名空间。 这意味着可以对表类型和实际表使用相同的名称。 为处理同名情况,引入了一个新的语句属性 SQL_SOPT_SS_NAME_SCOPE。 此属性指定采用表名作为参数的 SQLTables 和其他目录函数应将该表名解释为实际表的名称还是表类型的名称。

应用程序使用 SQLColumns 确定某个表类型的列(这与确定永久性表的列的方式相同),但是必须首先设置 SQL_SOPT_SS_NAME_SCOPE 以指示该属性适用于表类型而不是实际表。 SQLPrimaryKeys 也可用于表类型,同时也需要使用 SQL_SOPT_SS_NAME_SCOPE。

此情况的示例代码位于使用表值参数 (ODBC)中的例程 demo_metadata_from_catalog_APIs 内。

检索准备的语句的表值参数元数据

在此情况下,应用程序使用 SQLNumParametersSQLDescribeParam 检索表值参数的元数据。

IPD 字段 SQL_CA_SS_TYPE_NAME 用于检索表值参数的类型名称。 IPD 字段 SQL_CA_SS_TYPE_SCHEMA_NAME 和 SQL_CA_SS_TYPE_CATALOG_NAME 分别用于检索表值参数的目录和架构。

表类型定义和表值参数必须位于同一数据库中。 如果应用程序在使用表值参数时设置了 SQL_CA_SS_TYPE_CATALOG_NAME,SQLSetDescField 将报告错误。

SQL_CA_SS_TYPE_CATALOG_NAME 和 SQL_CA_SS_TYPE_SCHEMA_NAME 还可以用于检索与 CLR 用户定义类型参数关联的目录和架构。 SQL_CA_SS_TYPE_CATALOG_NAME 和 SQL_CA_SS_TYPE_SCHEMA_NAME 是 CLR UDT 类型的现有类型特定目录架构属性的替代属性。

在此情况下,应用程序也使用 SQLColumns 检索表值参数的列元数据,因为 SQLDescribeParam 不返回表值参数列的元数据。

此用例的示例代码位于使用表值参数 (ODBC)中的例程 demo_metadata_from_prepared_statement 内。

请参阅

概念

表值参数 (ODBC)