表值参数和列值的绑定及数据传输
与其他参数类似,表值参数在传递到服务器之前必须进行绑定。应用程序绑定表值参数的方式与绑定其他参数的方式是一样的:使用 SQLBindParameter 或等效地调用 SQLSetDescField 或 SQLSetDescRec。表值参数的服务器数据类型为 SQL_SS_TABLE。C 类型可以指定为 SQL_C_DEFAULT 或 SQL_C_BINARY。
在 SQL Server 2008 或更高版本中,只支持输入表值参数。因此,任何将 SQL_DESC_PARAMETER_TYPE 设置为 SQL_PARAM_INPUT 之外的值的尝试,都将返回具有 SQLSTATE = HY105 和消息“参数类型无效”的 SQL_ERROR。
可使用属性 SQL_CA_SS_COL_HAS_DEFAULT_VALUE 为整个表值参数列分配默认值。但是,不能通过在具有 SQLBindParameter 的 StrLen_or_IndPtr 中使用 SQL_DEFAULT_PARAM 来为单个的表值参数列值赋予默认值。不能通过在 SQLBindParameter 的 StrLen_or_IndPtr 中使用 SQL_DEFAULT_PARAM 来将表值参数整体设置为默认值。如果不遵从以上规则,SQLExecute 或 SQLExecDirect 将返回 SQL_ERROR。将生成具有 SQLSTATE=07S01 和消息“参数 <p> 不允许使用默认参数”的诊断记录,其中 <p> 为 TVP 在查询语句中的序号。
绑定表值参数之后,应用程序随后必须绑定每个表值参数列。为此,应用程序首先调用 SQLSetStmtAttr 将 SQL_SOPT_SS_PARAM_FOCUS 设置为表值参数的序号。然后,应用程序调用以下例程来绑定表值参数的列:SQLBindParameter、SQLSetDescRec 和 SQLSetDescField。将 SQL_SOPT_SS_PARAM_FOCUS 设置为 0 可还原 SQLBindParameter、SQLSetDescRec 和 SQLSetDescField 在对常规顶级参数进行操作时的常见效果。
对于表值参数本身而言,并未发送或接收实际数据,但对于表值参数的每个构成列而言,发送和接收了数据。由于表值参数是伪列,因此使用 SQLBindParameter 的参数来指代与其他数据类型不同的属性,如下所示:
参数 |
非表值参数类型的相关属性,包括列 |
表值参数的相关属性 |
---|---|---|
InputOutputType |
IPD 中的 SQL_DESC_PARAMETER_TYPE。 对于表值参数列,此属性设置必须与表值参数自身的设置相同。 |
IPD 中的 SQL_DESC_PARAMETER_TYPE。 此属性必须为 SQL_PARAM_INPUT。 |
ValueType |
APD 中的 SQL_DESC_TYPE、SQL_DESC_CONCISE_TYPE。 |
APD 中的 SQL_DESC_TYPE、SQL_DESC_CONCISE_TYPE。 此属性必须为 SQL_C_DEFAULT 或 SQL_C_BINARY。 |
ParameterType |
IPD 中的 SQL_DESC_TYPE、SQL_DESC_CONCISE_TYPE。 |
IPD 中的 SQL_DESC_TYPE、SQL_DESC_CONCISE_TYPE。 此属性必须为 SQL_SS_TABLE。 |
ColumnSize |
IPD 中的 SQL_DESC_LENGTH 或 SQL_DESC_PRECISION。 此属性取决于 ParameterType 的值。 |
SQL_DESC_ARRAY_SIZE 当参数焦点设置为表值参数时,也可以使用 SQL_ATTR_PARAM_SET_SIZE 进行设置。 对于表值参数,此属性为表值参数列缓冲区内的行数。 |
DecimalDigits |
IPD 中的 SQL_DESC_PRECISION 或 SQL_DESC_SCALE。 |
未使用。此属性必须为 0。 如果此参数不为 0,则 SQLBindParameter 将返回 SQL_ERROR,且生成具有 SQLSTATE= HY104 和消息“精度或小数位数值无效”的诊断记录。 |
ParameterValuePtr |
APD 中的 SQL_DESC_DATA_PTR。 |
SQL_CA_SS_TYPE_NAME。 此属性对于存储过程调用为可选的,并且如果不需要可以指定为 NULL。对于非过程调用的 SQL 语句,必须指定此属性。 在使用可变行绑定时,此参数还可作为应用程序用于标识该表值参数的唯一值。有关详细信息,请参阅本主题后面的“可变表值参数行绑定”部分。 在对 SQLBindParameter 调用指定表值参数类型名称时,必须将其指定为 Unicode 值,即使应用程序是作为 ANSI 应用程序生成的也应如此。用于参数 StrLen_or_IndPtr 的值应当为 SQL_NTS 或与 sizeof(WCHAR) 相乘的名称的字符串长度。 |
BufferLength |
APD 中的 SQL_DESC_OCTET_LENGTH。 |
表值参数类型名称的长度(以字节为单位)。 如果类型名称为以 NULL 值结束,则它可以是 SQL_NTS;如果不需要表值参数类型名称,则为 0。 |
StrLen_or_IndPtr |
APD 中的 SQL_DESC_OCTET_LENGTH_PTR。 |
APD 中的 SQL_DESC_OCTET_LENGTH_PTR。 对于表值参数,此属性为行计数,而非数据长度。 |
表值参数支持两种数据传输模式:固定行绑定和可变行绑定。
固定表值参数行绑定
在固定行绑定模式中,应用程序会分配足以容纳所有可能的输入列值的缓冲区(或缓冲区数组)。应用程序执行以下操作:
使用 SQLBindParameter、SQLSetDescRec 或 SQLSetDescField 调用绑定所有参数。
- 将 SQL_DESC_ARRAY_SIZE 设置为每个表值参数所能传输的最大行数。此操作可以在 SQLBindParameter 调用中完成。
调用 SQLSetStmtAttr 将 SQL_SOPT_SS_PARAM_FOCUS 设置为每个表值参数的序号。
对于每个表值参数,使用 SQLBindParameter、SQLSetDescRec 或 SQLSetDescField 调用绑定表值参数列。
对于具有默认值的每个表值参数列,调用 SQLSetDescField 将 SQL_CA_SS_COL_HAS_DEFAULT_VALUE 设置为 1。
调用 SQLSetStmtAttr 以便将 SQL_SOPT_SS_PARAM_FOCUS 设置为 0。必须在调用 SQLExecute 或 SQLExecDirect 之前完成此操作。否则,将返回 SQL_ERROR,且生成具有 SQLSTATE=HY024 和消息“属性值 SQL_SOPT_SS_PARAM_FOCUS 无效(执行时必须为零)”的诊断记录。
对于不包含行的表值参数,将 StrLen_or_IndPtr 或 SQL_DESC_OCTET_LENGTH_PTR 设置为 SQL_DEFAULT_PARAM,如果表值参数具有行,则设置为下次调用 SQLExecute 或 SQLExecDirect 时传输的行数。由于表值参数不可为 Null(尽管表值参数构成列可以为 Null),因此对于表值参数而言,StrLen_or_IndPtr 或 SQL_DESC_OCTET_LENGTH_PTR 不能设置为 SQL_NULL_DATA。如果设置为无效值,SQLExecute 或 SQLExecDirect 将返回 SQL_ERROR,且生成具有 SQLSTATE=HY090 和消息“参数 <p> 的字符串或缓冲区长度无效”(其中 p 为参数编号)的诊断记录。
调用 SQLExecute 或 SQLExecDirect。
如果列的 StrLen_or_IndPtr 设置为 SQL_LEN_DATA_AT_EXEC(length) 或 SQL_DATA_AT_EXEC,那么输入表值参数列值可以分块传递。这类似于使用参数数组时的分块传递值。与所有执行时数据参数一样,SQLParamData 不指出驱动程序请求的是哪一个数组行的数据,这一点必须由应用程序考虑。应用程序不能对驱动程序将请求值的顺序做出任何假设。
可变表值参数行绑定
在可变行绑定模式中,行在执行时进行批量传输,且应用程序根据需要将行传递给驱动程序。这类似于单个参数值的执行时数据。对于可变行绑定,应用程序执行以下操作:
按照上一部分“固定表值参数行绑定”中的步骤 1 到 3 所述,绑定参数和表值参数列。
将要在执行时传递的任意表值参数的 StrLen_or_IndPtr 或 SQL_DESC_OCTET_LENGTH_PTR 设置为 SQL_DATA_AT_EXEC。如果未设置这两个参数,则将按照上一部分中所述步骤处理参数。
调用 SQLExecute 或 SQLExecDirect。如果有任何 SQL_PARAM_INPUT 或 SQL_PARAM_INPUT_OUTPUT 参数处理为执行时数据参数,则调用将返回 SQL_NEED_DATA。在这种情况下,应用程序执行以下操作:
- 调用 SQLParamData。返回执行时数据参数的 ParameterValuePtr 值,返回代码为 SQL_NEED_DATA。如果已将所有参数传递给驱动程序,则 SQLParamData 返回 SQL_SUCCESS、SQL_SUCCESS_WITH_INFO 或 SQL_ERROR。对于执行时数据参数,可以将 ParameterValuePtr(与描述符字段 SQL_DESC_DATA_PTR 相同)视为唯一标识需要其值的参数的标记。此“标记”在绑定时从应用程序传递给驱动程序,在执行时传递回应用程序。
若要发送 Null 表值参数(假设表值参数没有行)的表值参数行数据,应用程序可调用 SQLPutData,其 StrLen_or_Ind 设置为 SQL_DEFAULT_PARAM。
对于非 Null TVP,应用程序会:
将所有表值参数列的 Str_Len_or_Ind 设置为适当的值,并填充非执行时数据参数的表值参数列的数据缓冲区。可以采用类似于将普通参数分块传递给驱动程序的方式,使用表值参数列的执行时数据。
调用 SQLPutData,其 Str_Len_or_Ind 设置为要发送给服务器的行数。范围 0 到 SQL_DESC_ARRAY_SIZE 或 SQL_DEFAULT_PARAM 以外的任何值都将生成错误,并将返回 SQLSTATE HY090 和消息“字符串或缓冲区长度无效”。0 表示已发送所有行,已不存在任何表值参数数据(如本列表的第二个项目符号项中所述)。只有在驱动程序第一次请求表值参数数据时,才能使用 SQL_DEFAULT_PARAM(如本列表的第二个项目符号项中所述)。
发送完所有行之后,为表值参数调用 SQLPutData,其 Str_Len_or_Ind 值为 0,然后继续执行上述步骤 3a。
再次调用 SQLParamData。如果表值参数列中存在任何执行时数据参数,则这些参数将由 SQLParamData 返回的值 ValuePtrPtr 标识。如果所有列值均可用,则 SQLParamData 将再次返回表值参数的 ParameterValuePtr 值,然后应用程序再次开始。