Verhaltensänderungen des ODBC-Treibers bei der Behandlung von Zeichenkonvertierungen

Gilt für: SQL Server Azure SQL-Datenbank Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW)

Wichtig

SQL Server Native Client (SNAC) wird nicht ausgeliefert mit:

  • SQL Server 2022 (16.x) und höhere Versionen
  • SQL Server Management Studio 19 und höhere Versionen

Der SQL Server Native Client (SQLNCLI oder SQLNCLI11) und der ältere Microsoft OLE DB-Anbieter für SQL Server (SQLOLEDB) werden für die entwicklung neuer Anwendungen nicht empfohlen.

Für neue Projekte verwenden Sie einen der folgenden Treiber:

Informationen zu SQLNCLI, das als Komponente der SQL Server Datenbank-Engine (Versionen 2012 bis 2019) ausgeliefert wird, finden Sie in dieser Ausnahme für den Supportlebenszyklus.

Der SQL Server 2012 (11.x) Native Client ODBC-Treiber (SQLNCLI11.dll) hat die Funktionsweise der Konvertierungen SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR(MAX)) und SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)) geändert. ODBC-Funktionen wie SQLGetData, SQLBindCol, SQLBindParameter, return (-4) SQL_NO_TOTAL als Längen-/Indikatorparameter bei Verwendung des SQL Server 2012 Native Client ODBC-Treibers. In früheren Versionen des SQL Server Native Client ODBC-Treibers wurde ein Längenwert zurückgegeben, der falsch sein kann.

SQLGetData-Verhalten

Bei vielen Windows-Funktionen können Sie die Puffergröße 0 angeben, wobei die zurückgegebene Länge der Größe der zurückgegebenen Daten entspricht. Windows-Programmierer verwenden häufig das folgende Muster:

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 sollte in diesem Szenario jedoch nicht verwendet werden. Das folgende Muster sollte nicht verwendet werden:

// 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 kann nur aufgerufen werden, um Datenblöcke abzurufen. Die Verwendung von SQLGetData zum Abrufen der Datengröße wird nicht unterstützt.

Im Folgenden wird veranschaulicht, wie sich der Treiberwechsel bei Verwendung des falschen Musters auswirkt. Diese Anwendung fragt eine Varchar-Spalte und Bindung als Unicode ab (SQL_UNICODE/SQL_WCHAR):

Abfrage: select convert(varchar(36), '123')

SQLGetData(hstmt, SQL_WCHAR, ....., (SQLPOINTER*) 0x1, 0 , &iSize);   // Attempting to determine storage size needed  
SQL Server Native Client ODBC-Treiberversion Längen- oder Indikatorergebnis Beschreibung
SQL Server 2008 R2 (10.50.x) Nativer Client oder früher 6 Der Treiber geht fälschlicherweise davon aus, dass die Konvertierung von CHAR in WCHAR als "Länge * 2" durchgeführt wird.
SQL Server 2012 (11.x) Native Client (Version 11.0.2100.60) oder höher -4 (SQL_NO_TOTAL) Der Treiber geht nicht mehr davon aus, dass das Konvertieren von CHAR in WCHAR oder WCHAR in CHAR eine (multiplizierte) *2- oder (Dividieren)/2-Aktion ist.

Das Aufrufen von SQLGetData gibt die Länge der erwarteten Konvertierung nicht mehr zurück. Der Treiber erkennt die Konvertierung in bzw. aus CHAR und WCHAR und gibt anstelle von "*2" oder "/2" das Ergebnis (-4) SQL_NO_TOTAL zurück; dieses Verhalten kann falsch sein.

Verwenden Sie SQLGetData , um die Datenblöcke abzurufen. (Dargestellter Pseudocode:)

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-Verhalten

Abfrage: 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-Treiberversion Längen- oder Indikatorergebnis Beschreibung
SQL Server 2008 R2 (10.50.x) Nativer Client oder früher 20 SQLFetch meldet, dass auf der rechten Seite der Daten eine Abkürzung vorhanden ist.

Die Länge entspricht der Länge der zurückgegebenen Daten und nicht der Größe der gespeicherten Daten (dabei wird die Konvertierung von CHAR in WCHAR mit Multiplikation (*2) vorausgesetzt, was für Symbole u. U. falsch ist).

Die im Puffer gespeicherten Daten sind 123\0. Der Puffer ist garantiert NULL-terminiert.
SQL Server 2012 (11.x) Native Client (Version 11.0.2100.60) oder höher -4 (SQL_NO_TOTAL) SQLFetch meldet, dass auf der rechten Seite der Daten eine Abkürzung vorhanden ist.

Die Länge entspricht -4 (SQL_NO_TOTAL), weil die übrigen Daten nicht konvertiert wurden.

Die im Puffer gespeicherten Daten haben eine Größe von 123\0. - Der Puffer ist garantiert NULL-terminiert.

SQLBindParameter (Verhalten des OUTPUT-Parameters)

Abfrage: 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-Treiberversion Längen- oder Indikatorergebnis Beschreibung
SQL Server 2008 R2 (10.50.x) Nativer Client oder früher 2468 SQLFetch gibt keine weiteren Daten zur Verfügung.

SQLMoreResults gibt keine weiteren Daten zurück.

Die Länge gibt die Größe der vom Server zurückgegebenen, nicht jedoch die Größe der im Puffer gespeicherten Daten an.

Der ursprüngliche Puffer enthält 63 Bytes und einen NULL-Terminator. Der Puffer ist garantiert NULL-terminiert.
SQL Server 2012 (11.x) Native Client (Version 11.0.2100.60) oder höher -4 (SQL_NO_TOTAL) SQLFetch gibt keine weiteren Daten zur Verfügung.

SQLMoreResults gibt keine weiteren Daten zurück.

Die Länge entspricht (-4) SQL_NO_TOTAL, weil die übrigen Daten nicht konvertiert wurden.

Der ursprüngliche Puffer enthält 63 Bytes und einen NULL-Terminator. Der Puffer ist garantiert NULL-terminiert.

Ausführen von CHAR- und WCHAR-Konvertierungen

Der SQL Server 2012 (11.x) Native Client ODBC-Treiber bietet verschiedene Möglichkeiten zum Ausführen von CHAR- und WCHAR-Konvertierungen. Die Logik ähnelt dem Bearbeiten von Blobs (varchar(max), nvarchar(max), ...):

  • Daten werden beim Binden mit SQLBindCol oder SQLBindParameter in den angegebenen Puffer gespeichert oder abgeschnitten.

  • Wenn Sie keine Bindung vornehmen, können Sie die Daten in Datenblöcken mithilfe von SQLGetData und SQLParamData abrufen.

Weitere Informationen

SQL Server Native Client-Funktionen