ODBC 表值参数的用法
适用于:SQL Server Azure SQL 数据库 Azure SQL 托管实例 Azure Synapse Analytics Analytics Platform System (PDW)
本主题介绍将表值参数用于 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 转换。
可以使用 SQLGetDescRec、SQLSetDescRec、SQLGetDescRec、SQLGetDescField 和 SQLSetDescField 单独和显式操作表值参数列的元数据。 但是,通常更方便重载 SQLBindParameter,在大多数情况下不需要显式描述符访问。 此方法与其他数据类型的 SQLBindParameter 定义一致,但对于表值参数,受影响的描述符字段略有不同。
有时,应用程序将表值参数用于动态 SQL,此时必须提供该表值参数的类型名称。 如果是这种情况,并且表值参数未在连接的当前默认架构中定义,则必须使用 SQLSetDescField 设置SQL_CA_SS_SCHEMA_NAME。 由于表类型定义和表值参数必须位于同一数据库中,因此如果应用程序使用表值参数,则不能设置SQL_CA_SS_CATALOG_NAME。 否则,SQLSetDescField 将报告错误。
此方案的示例代码位于“使用表值参数”(ODBC)过程中demo_fixed_TVP_binding
。
行流式处理情况下的表值参数(使用执行时数据将数据作为 TVP 发送)
在此情况下,应用程序在驱动程序请求行时向其提供行,并且这些行流向服务器。 这样就无需将所有行缓存在内存中。 这是大容量插入/更新时的典型情况。 表值参数提供了介于参数数组和大容量复制之间的某个性能点。 也就是说:表值参数可以像参数数组那样易于编程,但它们在服务器端提供更高的灵活性。
表值参数及其列按上一节“完全绑定多行缓冲区情况下的表值参数”所述进行绑定,但是表值参数本身的长度指示器设置为 SQL_DATA_AT_EXEC。 驱动程序通过返回SQL_NEED_DATA以执行时数据参数的常规方式响应 SQLExecute 或 SQLExecuteDirect。 当驱动程序准备好接受表值参数的数据时,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 架构集合稍有不同,未包括在此更改中。)
应用程序使用 SQLTable 来确定表类型的名称,与持久表、系统表和视图的名称相同。 引入了一个新的表类型 TABLE TYPE,该类型支持应用程序标识与表值参数关联的表类型。 表类型和常规表使用不同的命名空间。 这意味着可以对表类型和实际表使用相同的名称。 为处理同名情况,引入了一个新的语句属性 SQL_SOPT_SS_NAME_SCOPE。 此属性指定将表名用作参数的 SQLTable 和其他目录函数是否应将表名解释为实际表的名称或表类型的名称。
应用程序使用 SQLColumns 来确定表类型的列的方式与持久表的列相同,但必须首先设置SQL_SOPT_SS_NAME_SCOPE以指示它使用表类型而不是实际表。 SQLPrimaryKeys 还可用于表类型,再次使用SQL_SOPT_SS_NAME_SCOPE。
此方案的示例代码位于使用表值参数(ODBC)中的例程demo_metadata_from_catalog_APIs
中。
检索准备的语句的表值参数元数据
在此方案中,应用程序使用 SQLNumParameters 和 SQLDescribeParam 检索表值参数的元数据。
IPD 字段 SQL_CA_SS_TYPE_NAME 用于检索表值参数的类型名称。 IPD 字段SQL_CA_SS_SCHEMA_NAME和SQL_CA_SS_CATALOG_NAME分别用于检索其目录和架构。
表类型定义和表值参数必须位于同一数据库中。 如果应用程序在使用表值参数时设置SQL_CA_SS_CATALOG_NAME,SQLSetDescField 将报告错误。
SQL_CA_SS_CATALOG_NAME和SQL_CA_SS_SCHEMA_NAME还可用于检索与 CLR 用户定义的类型参数关联的目录和架构。 SQL_CA_SS_CATALOG_NAME和SQL_CA_SS_SCHEMA_NAME是 CLR UDT 类型的现有类型特定目录架构属性的替代方法。
应用程序在此方案中也使用 SQLColumns 检索表值参数的列元数据,因为 SQLDescribeParam 不返回表值参数列的元数据。
此用例的示例代码位于 Use Table-Valued Parameters (ODBC)中的例程demo_metadata_from_prepared_statement
中。