文字変換処理での ODBC ドライバーの動作の変更
適用対象:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System (PDW)
重要
SQL Server Native Client (SNAC と略されることがよくあります) は、SQL Server 2022 (16.x) と SQL Server Management Studio 19 (SSMS) から削除されました。 SQL Server Native Client (SQLNCLI または SQLNCLI11) とレガシ Microsoft OLE DB Provider for SQL Server (SQLOLEDB) は、新しいアプリケーション開発には推奨されません。 今後、新しい Microsoft OLE DB Driver (MSOLEDBSQL) for SQL Server または最新の Microsoft ODBC Driver for SQL Server に切り替えてください。 SQL Server データベース エンジン (バージョン 2012 から 2019) のコンポーネントとして付属する SQLNCLI については、このサポート ライフサイクルの例外を参照してください。
SQL Server 2012 (11.x) Native Client ODBC Driver (SQLNCLI11.dll) は、SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR(MAX)) および SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)) 変換の処理方法を変更しました。 SQLGetData、SQLBindCol、SQLBindParameter などの ODBC 関数は、SQL Server 2012 Native Client ODBC ドライバーを使用する場合、長さ/インジケーター パラメーターとして (-4) SQL_NO_TOTALを返します。 SQL Server Native Client ODBC ドライバーの以前のバージョンでは、長さの値が返されました。これは正しくない可能性があります。
SQLGetData の動作
多くの Windows 関数ではバッファー サイズに 0 を指定できます。返される長さは、返されるデータのサイズです。 以下は、Windows プログラミングで一般的なパターンです。
int iSize = 0;
BYTE * pBuffer = NULL;
GetMyFavoriteAPI(pBuffer, &iSize); // Returns needed size in iSize
pBuffer = new BYTE[iSize]; // Allocate buffer
GetMyFavoriteAPI(pBuffer, &iSize); // Retrieve actual data
ただし、このシナリオでは SQLGetData を使用しないでください。 次のパターンは使用できません。
// bad
int iSize = 0;
WCHAR * pBuffer = NULL;
SQLGetData(hstmt, SQL_W_CHAR, ...., (SQLPOINTER*)0x1, 0, &iSize); // Get storage size needed
pBuffer = new WCHAR[(iSize/sizeof(WCHAR)) + 1]; // Allocate buffer
SQLGetData(hstmt, SQL_W_CHAR, ...., (SQLPOINTER*)pBuffer, iSize, &iSize); // Retrieve data
SQLGetData は、実際のデータのチャンクを取得するためにのみ呼び出すことができます。 SQLGetData を使用してデータのサイズを取得することはサポートされていません。
次に、不適切なパターンを使用した場合のドライバーの変更による影響を示します。 このアプリケーションは 、varchar 列とバインドを Unicode (SQL_UNICODE/SQL_WCHAR) として照会します。
クエリ: select convert(varchar(36), '123')
SQLGetData(hstmt, SQL_WCHAR, ....., (SQLPOINTER*) 0x1, 0 , &iSize); // Attempting to determine storage size needed
SQL SERVER NATIVE CLIENT ODBC ドライバーのバージョン | 長さまたはインジケーターの結果 | 説明 |
---|---|---|
SQL Server 2008 R2 (10.50.x) Native Client 以前 | 6 | ドライバーには、CHAR から WCHAR への変換が長さ * 2 として実行できるという誤った想定がありました。 |
SQL Server 2012 (11.x) Native Client (バージョン 11.0.2100.60) 以降 | -4 (SQL_NO_TOTAL) | ドライバーでは、CHAR から WCHAR または WCHAR から CHAR への変換が (乗算) *2 または (除算) /2 操作であると想定されることはなくなりました。 SQLGetData を呼び出しても、予想される変換の長さが返されなくなりました。 ドライバーでは CHAR と WCHAR との間の変換が検出され、誤りの可能性のある *2 または /2 の動作の代わりに (-4) SQL_NO_TOTAL が返されます。 |
SQLGetData を使用して、データのチャンクを取得します。 (擬似コードを示します)。
while( (SQL_SUCCESS or SQL_SUCCESS_WITH_INFO) == SQLFetch(...) ) {
SQLNumCols(...iTotalCols...)
for(int iCol = 1; iCol < iTotalCols; iCol++) {
WCHAR* pBufOrig, pBuffer = new WCHAR[100];
SQLGetData(.... iCol ... pBuffer, 100, &iSize); // Get original chunk
while(NOT ALL DATA RETREIVED (SQL_NO_TOTAL, ...) ) {
pBuffer += 50; // Advance buffer for data retrieved
// May need to realloc the buffer when you reach current size
SQLGetData(.... iCol ... pBuffer, 100, &iSize); // Get next chunk
}
}
}
SQLBindCol の動作
クエリ: select convert(varchar(36), '1234567890')
SQLBindCol(... SQL_W_CHAR, ...) // Only bound a buffer of WCHAR[4] - Expecting String Data Right Truncation behavior
SQL SERVER NATIVE CLIENT ODBC ドライバーのバージョン | 長さまたはインジケーターの結果 | 説明 |
---|---|---|
SQL Server 2008 R2 (10.50.x) Native Client 以前 | 20 | SQLFetch は、データの右側に切り捨てがあることを報告します。 長さは格納されたデータではなく、返されるデータの長さです (*2 による CHAR から WCHAR への変換が想定されていますが、グリフでは誤りである可能性があります)。 バッファーに格納されるデータは 123\0 です。 バッファーは NULL 終端であることが保証されます。 |
SQL Server 2012 (11.x) Native Client (バージョン 11.0.2100.60) 以降 | -4 (SQL_NO_TOTAL) | SQLFetch は、データの右側に切り捨てがあることを報告します。 残りのデータは変換されていないため、長さは -4 (SQL_NO_TOTAL) を示します。 バッファーに格納されているデータは 123\0 です。 - バッファーは NULL 終端であることが保証されます。 |
SQLBindParameter (出力パラメーターの動作)
クエリ: create procedure spTest @p1 varchar(max) OUTPUT
select @p1 = replicate('B', 1234)
SQLBindParameter(... SQL_W_CHAR, ...) // Only bind up to first 64 characters
SQL SERVER NATIVE CLIENT ODBC ドライバーのバージョン | 長さまたはインジケーターの結果 | 説明 |
---|---|---|
SQL Server 2008 R2 (10.50.x) Native Client 以前 | 2468 | SQLFetch は、これ以上使用できないデータを返します。 SQLMoreResults は、 使用できるデータを返しません。 長さはバッファーに格納されたデータではなく、サーバーから返されるデータのサイズを示します。 元のバッファーには 63 バイトと NULL ターミネータが含まれます。 バッファーは NULL 終端であることが保証されます。 |
SQL Server 2012 (11.x) Native Client (バージョン 11.0.2100.60) 以降 | -4 (SQL_NO_TOTAL) | SQLFetch は、これ以上使用できないデータを返します。 SQLMoreResults は、 使用できるデータを返しません。 残りのデータは変換されていないため、長さは (-4) SQL_NO_TOTAL を示します。 元のバッファーには 63 バイトと NULL ターミネータが含まれます。 バッファーは NULL 終端であることが保証されます。 |
CHAR と WCHAR の変換の実行
SQL Server 2012 (11.x) Native Client ODBC ドライバーには、CHAR 変換と WCHAR 変換を実行するいくつかの方法が用意されています。 ロジックは、BLOB (varchar(max)、nvarchar(max)、...) の操作に似ています。
SQLBindCol または SQLBindParameter を使用してバインドすると、データは指定されたバッファーに保存または切り捨てられます。
バインドしない場合は、 SQLGetData と SQLParamData を使用してチャンク単位でデータ を取得できます。
参照
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示