Long 数据和 SQLSetPos 及 SQLBulkOperations

与 SQL 语句中的参数一样,使用 SQLBulkOperationsSQLSetPos 更新行或者使用 SQLBulkOperations 插入行时,可以发送长数据。 通过多次调用 SQLPutData 分部分发送数据。 在执行时发送其数据的列称为执行时数据列

注意

应用程序实际上可以使用 SQLPutData 在执行时发送任何类型的数据,尽管只能分部分发送字符和二进制数据。 但是,如果数据足够小,无法容纳在单个缓冲区中,则通常没有理由使用 SQLPutData。 绑定缓冲区并让驱动程序从缓冲区中检索数据要容易得多。

由于长数据列通常未绑定,因此应用程序必须在调用 SQLBulkOperationsSQLSetPos 之前绑定列,并在调用 SQLBulkOperationsSQLSetPos 后将其取消绑定。 该列必须绑定,因为 SQLBulkOperationsSQLSetPos 仅在绑定列上运行,并且必须解除绑定,以便 SQLGetData 可用于从列检索数据。

要在执行时发送数据,应用程序将执行以下操作:

  1. 将 32 位值放在行集缓冲区而不是数据值中。 此值稍后将返回到应用程序中,因此应用程序应将其设置为有意义的值,例如列数或包含数据的文件的句柄。

  2. 将长度/指示器缓冲区中的值设置为 SQL_LEN_DATA_AT_EXEC(length) 宏的结果。 此值向驱动程序指示将使用 SQLPutData 发送参数的数据。 向数据源发送长数据时,将使用长度值,该数据源需要知道将发送多少字节的长数据,以便它可以预先分配空间。 若要确定数据源是否需要此值,应用程序使用 SQL_NEED_LONG_DATA_LEN 选项调用 SQLGetInfo。 所有驱动程序都必须支持此宏;如果数据源不需要字节长度,驱动程序可以忽略它。

  3. 调用 SQLBulkOperationsSQLSetPos。 驱动程序发现长度/指示器缓冲区包含 SQL_LEN_DATA_AT_EXEC(length) 宏的结果,并将 SQL_NEED_DATA 作为函数的返回值返回。

  4. 调用 SQLParamData 以响应 SQL_NEED_DATA 返回值。 如果需要发送长数据,SQLParamData 将返回 SQL_NEED_DATA。 在 ValuePtrPtr 参数指向的缓冲区中,驱动程序返回应用程序放置在行集缓冲区中的唯一值。 如果有多个执行时数据列,则应用程序使用此值来确定要向其发送数据的列;驱动程序不需要以任何特定顺序请求执行时数据列的数据。

  5. 调用 SQLPutData 将列数据发送到驱动程序。 如果列数据不适合单个缓冲区,与长数据的情况一样,应用程序会反复调用 SQLPutData 以分部分发送数据;重组数据由驱动程序和数据源决定。 如果应用程序传递以 null 结尾的字符串数据,驱动程序或数据源必须在重组过程中删除 null 终止字符。

  6. 再次调用 SQLParamData 以指示它已发送列的所有数据。 如果存在尚未发送数据的任何执行时数据列,驱动程序将返回 SQL_NEED_DATA 和下一个执行时数据列的唯一值;应用程序返回到步骤 5。 如果已为所有的执行时数据列发送数据,则行的数据将发送到数据源。 然后,SQLParamData 将返回 SQL_SUCCESS 或 SQL_SUCCESS_WITH_INFO,并且可以返回 SQLBulkOperationsSQLSetPos 可以返回的任何 SQLSTATE。

SQLBulkOperationsSQLSetPos 返回 SQL_NEED_DATA 之后,为最后一个执行时数据列完全发送数据之前,该语句处于“需要数据”状态。 在此状态下,应用程序只能调用 SQLPutDataSQLParamDataSQLCancelSQLGetDiagFieldSQLGetDiagRec;所有其他函数返回 SQLSTATE HY010(函数序列错误)。 调用 SQLCancel 会取消语句的执行,并将其返回到其以前的状态。 有关详细信息,请参阅附录 B:ODBC 状态转换表