Freigeben über


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

Der SQL Server 2012 Native Client ODBC-Treiber (SQLNCLI11.dll) hat die Funktionsweise von SQL_WCHAR*-Konvertierungen (NCHAR/NVARCHAR/NVARCHAR(MAX)) und SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)) geändert. ODBC-Funktionen, z. B. SQLGetData, SQLBindCol, SQLBindParameter, geben (-4 SQL_NO_TOTAL) als Längen-/Indikatorparameter zurück, wenn sie den ODBC-Treiber SQL Server 2012 Native Client verwenden. Frühere Versionen des SQL Server Native Client ODBC-Treibers haben einen 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 Blöcke der tatsächlichen Daten abzurufen. Die Verwendung von SQLGetData zum Abrufen der Datengröße wird nicht nicht unterstützt.

Im Folgenden wird veranschaulicht, wie sich der Treiberwechsel bei Verwendung des falschen Musters auswirkt. Von der Anwendung wird eine als Unicode definierte varchar-Spalte und -Bindung (SQL_UNICODE/SQL_WCHAR) abgefragt:

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 Native 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 Native Client (Version 11.0.2100.60) oder höher -4 (SQL_NO_TOTAL) Der Treiber geht nicht mehr davon aus, dass die Konvertierung von CHAR in WCHAR bzw. WCHAR in CHAR eine Multiplikations- (*2) oder Divisionsaktion (/2) ist.

Das Aufrufen von SQLGetData gibt nicht mehr die Länge der erwarteten Konvertierung 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 Blöcke der Daten 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 Native Client oder früher 20 - SQLFetch meldet, dass auf der rechten Seite der Daten ein Abschneiden vorliegt.
- Die Länge ist die Länge der zurückgegebenen Daten, nicht die gespeicherten Daten (vorausgesetzt, die Konvertierung von *2 CHAR in WCHAR kann für Glyphen falsch sein).
– Im Puffer gespeicherte Daten sind 123\0. Der Puffer ist garantiert NULL-terminiert.
SQL Server 2012 Native Client (Version 11.0.2100.60) oder höher -4 (SQL_NO_TOTAL) - SQLFetch meldet, dass auf der rechten Seite der Daten ein Abschneiden vorliegt.
– Die Länge gibt -4 (SQL_NO_TOTAL) an, da der Rest der Daten nicht konvertiert wurde.
– Im Puffer gespeicherte Daten sind 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 Native Client oder früher 2.468 - SQLFetch gibt keine weiteren verfügbaren Daten zurück.
- SQLMoreResults gibt keine weiteren verfügbaren Daten zurück.
– Länge gibt die Größe der vom Server zurückgegebenen Daten an, die nicht im Puffer gespeichert werden.
- Der ursprüngliche Puffer enthält 63 Bytes und einen NULL-Abschluss. Der Puffer ist garantiert NULL-terminiert.
SQL Server 2012 Native Client (Version 11.0.2100.60) oder höher -4 (SQL_NO_TOTAL) - SQLFetch gibt keine weiteren verfügbaren Daten zurück.
- SQLMoreResults gibt keine weiteren verfügbaren Daten zurück.
– Die Länge gibt (-4) SQL_NO_TOTAL an, da der Rest der Daten nicht konvertiert wurde.
- Der ursprüngliche Puffer enthält 63 Bytes und einen NULL-Abschluss. Der Puffer ist garantiert NULL-terminiert.

Ausführen von CHAR- und WCHAR-Konvertierungen

Der SQL Server 2012 Native Client ODBC-Treiber bietet mehrere Möglichkeiten, CHAR- und WCHAR-Konvertierungen durchzuführen. Die Logik ähnelt der Bearbeitung von Blobs (varchar(max), nvarchar(max), ...):

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

  • Wenn Sie keine Bindung durchführen, können Sie die Daten mit SQLGetData und SQLParamData in Blöcken abrufen.

Weitere Informationen

SQL Server Native Client-Funktionen