Verhaltensänderungen des ODBC-Treibers bei der Behandlung von Zeichenkonvertierungen
Die Konvertierung der Datentypen SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR(MAX)) und SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)) hat sich beim SQL Server 2012 Native Client-ODBC-Treiber (SQLNCLI11.dll) geändert. ODBC-Funktionen wie SQLGetData, SQLBindCol und SQLBindParameter geben bei Verwendung des SQL Server 2012 Native Client-ODBC-Treibers (-4) SQL_NO_TOTAL als Längen-/Indikatorparameter zurück. Von früheren Versionen des SQL Server Native Client-ODBC-Treibers wurde ein Längenwert zurückgegeben, was möglicherweise falsch ist.
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 Segmente tatsächlicher Daten 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. 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. Durch Aufrufen von SQLGetData wird nicht mehr die Länge der erwarteten Konvertierung zurückgegeben. 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 Datensegmente 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 |
|
SQL Server 2012 Native Client (Version 11.0.2100.60) oder höher |
-4 (SQL_NO_TOTAL) |
|
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 |
2468 |
|
SQL Server 2012 Native Client (Version 11.0.2100.60) oder höher |
-4 (SQL_NO_TOTAL) |
|
Ausführen von CHAR- und WCHAR-Konvertierungen
Der SQL Server 2012 Native Client-ODBC-Treiber bietet verschiedene Möglichkeiten zum Durchführen von CHAR- und WCHAR-Konvertierungen. Die Logik ist vergleichbar mit dem Bearbeiten von BLOBs (varchar(max), nvarchar(max), …):
Die Daten werden bei der Bindung mit SQLBindCol oder SQLBindParameter im angegebenen Puffer gespeichert oder gekürzt.
Wenn Sie keine Bindung durchführen, können Sie die Daten durch Verwendung von SQLGetData und SQLParamData in Segmenten abrufen.