문자 변환을 처리할 때 ODBC 드라이버 동작 변경

적용 대상:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse Analytics AnalyticsPlatform System(PDW)

Important

SQL Server Native Client(약칭 SNAC)는 SQL Server 2022(16.x) 및 SSMS(SQL Server Management Studio) 19에서 제거되었습니다. SQL Server Native Client(SQLNCLI 또는 SQLNCLI11) 및 레거시 Microsoft OLE DB Provider for SQL Server(SQLOLEDB)는 새 애플리케이션 개발에 권장되지 않습니다. 앞으로 새 SQL Server용 Microsoft OLE DB 드라이버(MSOLEDBSQL) 또는 최신 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)) 변환 방식을 변경했습니다. 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 열 및 바인딩을 유니코드(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로 변환하는 것이 (곱하기) *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(OUTPUT 매개 변수 동작)

쿼리: 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를 사용하여 청크로 데이터를 검색할 수 있습니다.

참고 항목

SQL Server Native Client 기능