3

使用 C++ 代码,我正在尝试使用存储过程将大型二进制 blob 插入 MS SQL 服务器。我要插入的表有 5 列,类型:

int
varchar
datetime
varbinary(max)
datetime

存储过程有 4 个参数:

PROCEDURE [dbo].[spr_fff] 
     @act           AS INT
    ,@id            AS VARCHAR(255)
    ,@timestamp     AS DATETIME
    ,@blob          AS VARBINARY(MAX)

我设置了我的声明(检查我没有显示的返回值):

const std::string queryString("{Call [spr_fff](?,?,?,?)}");
SQLHSTMT handle = NULL;
SQLAllocHandle(SQL_HANDLE_STMT, m_hConn, &handle);
SQLPrepare(handle, (SQLCHAR *)queryString.c_str(), SQL_NTS);

我绑定前三个参数没有问题,但我似乎无法弄清楚如何绑定第四个参数。代码本质上是:

std::string sData; getData(sData);  //fills sData with the binary data
SQLLEN len1 = ???;
SQLBindParameter( handle, (SQLUSMALLINT)4, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, len1, 0, (SQLCHAR*)&sData.c_str(), (SQLLEN)sData.size(), NULL);

诀窍似乎是弄清楚 len1 应该是什么。如果sData.size() < 8000, 则len1 = sData.size()工作正常。但是,如果sData.size() > 8000,似乎没有任何效果。如果我设置len1 = sData.size(), 或len1 = 2147483647调用SQLBindParameter导致错误代码“无效的精度值”。如果我设置len1 = 0为一些(可怕的)文档似乎建议,调用SQLBindParameter工作(对于 2008 本机驱动程序),但执行语句会导致大小为 2 的 blob,即所有输入 blob 的两个默认 0 字节数据被截断为 0 字节。我已经尝试了所有这些组合以及下面列出的所有客户端驱动程序,但都无济于事。我究竟做错了什么?????

环境
客户端操作系统:Windows XP sp3

SQL Server 是
Microsoft SQL Server 09.00.3042

尝试使用的 SQL 客户端:
Microsoft SQL Server Native Client 版本 10.00.5500 (sqlncli10.dll, 2007.100.5500.00)
Microsoft SQL Native Client 版本 09.00.5000 (sqlncli.dll, 2005.90.5000.00)
Microsoft SQL Server ODBC 驱动程序版本 03.85.1132 (sqlsrv32 .dll 2000.85.1132.0)

4

2 回答 2

4

好的,我的问题的答案实际上是我在调用SQLBindParameter. 如果您查看我上面的代码,我将最终参数设置为 NULL。仔细阅读文档 - 相信我,它需要仔细阅读!- 表明如果最终参数为 NULL,则数据被视为以零结尾。(文档SQLBindParameter说“如果 StrLen_or_IndPtr 是空指针,则驱动程序假定所有输入参数值都是非空的,并且字符和二进制数据以空终止.” - 强调我的)而且,不幸的是,我提供的数据的第二个或第三个字节为零,因此实际存储的 blob 只有 1 或 2 个字节。不知道为什么它的大小小于8000 - size<8000 和各种驱动程序版本可能存在一些相互作用,但我没有花时间梳理一下。

此外,在上面的代码中,我声明“如果我设置len1 = 0为某些(可怕的)文档似乎建议”。这实际上是正确的做法。

因此正确的代码是

SQLLEN len1 = 0;
SQLLEN nThisLen = (SQLLEN)sData.size();
SQLBindParameter( handle, (SQLUSMALLINT)4, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, len1, 0, (SQLCHAR*)&sData.c_str(), nThisLen, &nThisLen );
于 2013-02-26T05:26:53.257 回答
0

Jeff O 走在了正确的轨道上。尝试将存储过程更改为...

PROCEDURE [dbo].[spr_fff] 
    @act           AS INT
    ,@id           AS VARCHAR(255)
    ,@timestamp    AS DATETIME
    ,@preblob      AS nvarchar(MAX)

    DECLARE @blob varbinary(MAX) = CAST(@preblob as varbinary(MAX))
    /* Continue using varbinary blob as before */

请注意 sproc 的参数数据类型的更改以及随后转换为 varbinary。

干杯。

于 2013-02-13T22:24:23.597 回答