次の方法で共有


文字変換処理での ODBC ドライバーの動作の変更

SQL Server 2012 Native Client ODBC ドライバー (SQLNCLI11.dll) での SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR(MAX)) と SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)) の変換方法が変更されました。 SQL Server 2012 Native Client ODBC ドライバーを使用する場合、SQLGetData、SQLBindCol、SQLBindParameter などの 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 Native Client 以前

6

ドライバーには、CHAR から WCHAR への変換が長さ * 2 として実行できるという誤った想定がありました。

SQL Server 2012 Native Client (Version 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 Native Client 以前

20

  • SQLFetch により、データの右側に切り捨てがあることが報告されます。

  • 長さは格納されたデータではなく、返されるデータの長さです (*2 による CHAR から WCHAR への変換が想定されていますが、グリフでは誤りである可能性があります)。

  • バッファーに格納されているデータは 123\0 です。 バッファーは NULL 終端であることが保証されます。

SQL Server 2012 Native Client (Version 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 Native Client 以前

2468

  • SQLFetch で返されるデータはこれ以上ありません。

  • SQLMoreResults で返されるデータはこれ以上ありません。

  • 長さはバッファーに格納されたデータではなく、サーバーから返されるデータのサイズを示します。

  • 元のバッファーには 63 バイトと NULL ターミネータが含まれます。 バッファーは NULL 終端であることが保証されます。

SQL Server 2012 Native Client (Version 11.0.2100.60) 以降

-4 (SQL_NO_TOTAL)

  • SQLFetch で返されるデータはこれ以上ありません。

  • SQLMoreResults で返されるデータはこれ以上ありません。

  • 残りのデータは変換されていないため、長さは (-4) SQL_NO_TOTAL を示します。

  • 元のバッファーには 63 バイトと NULL ターミネータが含まれます。 バッファーは NULL 終端であることが保証されます。

CHAR と WCHAR の変換の実行

SQL Server 2012 Native Client ODBC ドライバーには、CHAR と WCHAR の変換を実行する方法が複数用意されています。 論理は BLOB (varchar(max)、nvarchar(max) など) の操作に似ています。

  • SQLBindCol または SQLBindParameter でバインドする場合、データは指定されたバッファーに保存されるか、切り捨てられます。

  • バインドしない場合は、SQLGetDataSQLParamData を使用してデータ チャンクを取得できます。

関連項目

その他の技術情報

SQL Server Native Client の機能