Share via


ODBC 驅動程式在處理字元轉換上的行為變更

適用於:SQL ServerAzure SQL DatabaseAzure SQL 受控執行個體Azure 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 資料庫引擎元件隨附的 SQLNCLI(版本 2012 到 2019),請參閱此 支援生命週期例外狀況

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 驅動程式時,ODBC 函式,例如 SQLGetData、SQLBindCol、SQLBindParameter、傳回 (-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 Driver 版本 長度或指標結果 描述
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 或 (divide)/2 巨集指令。

呼叫 SQLGetData 不再傳回預期的轉換長度。 驅動程式會偵測對 CHAR 和 WCHAR 的轉換,並傳回 (-4) SQL_NO_TOTAL,而不是可能不正確的 *2 或 /2 行為。

使用 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 Driver 版本 長度或指標結果 描述
SQL Server 2008 R2 (10.50.x) Native Client 或更早版本 20 SQLFetch 會報告資料右側有截斷。

Length 是傳回的資料長度,而不是儲存的資料長度(假設 *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 Driver 版本 長度或指標結果 描述
SQL Server 2008 R2 (10.50.x) Native Client 或更早版本 2468 SQLFetch 不會傳回更多可用的資料。

SQLMoreResults 不會傳回更多可用的資料。

Length 表示從伺服器傳回的資料大小,而不是儲存在緩衝區中。

原始緩衝區包含 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 功能