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);

最初の 3 つのパラメーターは問題なくバインドできますが、4 番目のパラメーターをバインドする方法がわかりません。コードは基本的に次のとおりです。

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 が生成されます。つまり、2 つのデフォルト 0 バイトとすべての入力 BLOBデータは 0 バイトに切り捨てられます。以下にリストされているすべてのクライアントドライバーでこれらすべての組み合わせを試しましたが、すべて役に立ちませんでした。私は何を間違っていますか?????

環境
クライアント OS: 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

OK、私の質問に対する答えは、実際には への呼び出しで失敗したということSQLBindParameterです。上記のコードを見ると、最後のパラメーターが NULL になっています。ドキュメントを注意深く読んでください - 信じてください。- 最後のパラメーターが NULL の場合、データはゼロ終了として扱われることを示します。(のドキュメントにSQLBindParameterは、「StrLen_or_IndPtr が null ポインターの場合、ドライバーは、すべての入力パラメーター値が NULL ではなく、文字およびバイナリ データが null で終了していると想定します。." - 私の強調) そして、残念なことに、私が提供していたデータの 2 番目または 3 番目のバイトがゼロだったので、実際に保存された BLOB は 1 バイトまたは 2 バイトしかありませんでした。 8000 - サイズが 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 は正しい道を歩んでいました。sproc を次のように変更してみてください...

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 に答える