문자 변환을 처리할 때 ODBC 드라이버 동작 변경
적용 대상: SQL Server Azure SQL 데이터베이스 Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System(PDW)
Important
SNAC(SQL Server Native Client)는 다음과 함께 제공되지 않습니다.
- SQL Server 2022(16.x) 이상 버전
- SQL Server Management Studio 19 이상 버전
SQL Server Native Client(SQLNCLI 또는 SQLNCLI11)와 레거시 Microsoft OLE DB Provider for SQL Server(SQLOLEDB)는 새로운 응용 프로그램 개발에 권장되지 않습니다.
새 프로젝트의 경우 다음 드라이버 중 하나를 사용합니다.
SQL Server 데이터베이스 엔진(버전 2012부터 2019까지)의 구성 요소로 제공되는 SQLNCLI의 경우 이 수명 주기 예외 지원을 참조하세요.
SQL Server 2012(11.x) 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 열 및 바인딩을 유니코드(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를 사용하여 청크로 데이터를 검색할 수 있습니다.