Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy:sql Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Ważne
Klient natywny SQL Servera (SNAC) nie jest dostarczany z:
- SQL Server 2022 (16.x) i nowsze wersje
- SQL Server Management Studio 19 i nowsze wersje
Program SQL Server Native Client (SQLNCLI lub SQLNCLI11) oraz starszy dostawca microsoft OLE DB dla programu SQL Server (SQLOLEDB) nie są zalecane w przypadku tworzenia nowych aplikacji.
W przypadku nowych projektów użyj jednego z następujących sterowników:
- Sterownik ODBC firmy Microsoft dla programu SQL Server
- Sterownik OLE DB firmy Microsoft dla programu SQL Server
W przypadku programu SQLNCLI dostarczanego jako składnik aparatu bazy danych programu SQL Server (wersje 2012–2019), proszę sprawdzić wyjątek cyklu wsparcia .
Sterownik ODBC z natywnego klienta z SQL Server 2012 (11.x) (SQLNCLI11.dll) zmienił sposób realizacji konwersji SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR(MAX)) i SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)). Funkcje ODBC, takie jak SQLGetData, SQLBindCol, SQLBindParameter, return (-4) SQL_NO_TOTAL jako parametr długości/wskaźnika podczas korzystania z sterownika ODBC Native Client SQL Server 2012. Poprzednie wersje sterownika ODBC dla natywnego klienta SQL Server zwracały wartość długości, która może być nieprawidłowa.
Zachowanie SQLGetData
Wiele funkcji Windows pozwala określić rozmiar bufora 0, a zwrócona długość to rozmiar zwróconych danych. Następujący wzorzec jest powszechny wśród programistów 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
Jednak SQLGetData nie powinno być używane w tym scenariuszu. Nie powinno się stosować następującego wzoru:
// 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 można wywołać tylko w celu pobrania fragmentów rzeczywistych danych. Używanie SQLGetData do określania rozmiaru danych nie jest nieobsługiwane.
Poniżej przedstawiono wpływ zmiany sterownika przy użyciu nieprawidłowego wzoru. Ta aplikacja zapytuje kolumnę varchar i powiązanie jako Unicode (SQL_UNICODE/SQL_WCHAR):
Zapytanie: 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 version | Długość lub wskaźnik wynik | Description |
|---|---|---|
| SQL Server 2008 R2 (10.50.x) Natywny klient lub wcześniejszy | 6 | Maszynista błędnie założył, że konwersja CHAR na WCHAR może być wykonana jako długość * 2. |
| SQL Server 2012 (11.x) Natywny klient (wersja 11.0.2100.60) lub nowszy | -4 (SQL_NO_TOTAL) | Kierowca nie zakłada już, że konwersja z CHAR na WCHAR lub WCHAR na CHAR to akcja (mnoż) *2 lub (dziel)/2. Wywołanie SQLGetData nie zwraca już długości oczekiwanej konwersji. Sterownik wykrywa konwersję do lub z CHAR i WCHAR i zwraca (-4) SQL_NO_TOTAL zamiast *2 lub /2, które może być nieprawidłowe. |
Użyj SQLGetData do pobrania fragmentów danych. (Pokazano pseudokod:)
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 RETRIEVED (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
}
}
}
Zachowanie SQLBindCol
Zapytanie: 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 version | Długość lub wskaźnik wynik | Description |
|---|---|---|
| SQL Server 2008 R2 (10.50.x) Natywny klient lub wcześniejszy | 20 |
SQLFetch informuje, że po prawej stronie danych jest obcięcie. Długość to długość zwróconych danych, a nie to, co zostało zapisane (zakłada konwersję *2 CHAR na WCHAR, co może być błędne dla glifów). Dane przechowywane w buforze mają 123\0. Bufor jest gwarantowany zakończeniem NULL. |
| SQL Server 2012 (11.x) Natywny klient (wersja 11.0.2100.60) lub nowszy | -4 (SQL_NO_TOTAL) |
SQLFetch informuje, że po prawej stronie danych jest obcięcie. Długość wskazuje na -4 (SQL_NO_TOTAL), ponieważ pozostałe dane nie zostały przekonwertowane. Dane przechowywane w buforze to 123\0. - Bufor jest gwarantowany zakończenie NULL. |
SQLBindParameter (Zachowanie parametrów wyjściowych)
Zapytanie: 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 version | Długość lub wskaźnik wynik | Description |
|---|---|---|
| SQL Server 2008 R2 (10.50.x) Natywny klient lub wcześniejszy | 2468 |
SQLFetch nie zwraca już dostępnych danych. SQLMoreResults nie zwraca już dostępnych danych. Długość wskazuje rozmiar danych zwracanych z serwera, które nie są przechowywane w buforze. Oryginalny bufor zawiera 63 bajty oraz terminator NULL. Bufor jest gwarantowany zakończeniem NULL. |
| SQL Server 2012 (11.x) Natywny klient (wersja 11.0.2100.60) lub nowszy | -4 (SQL_NO_TOTAL) |
SQLFetch nie zwraca już dostępnych danych. SQLMoreResults nie zwraca już dostępnych danych. Długość wskazuje (-4) SQL_NO_TOTAL, ponieważ pozostałe dane nie zostały przekonwertowane. Oryginalny bufor zawiera 63 bajty oraz terminator NULL. Bufor jest gwarantowany zakończeniem NULL. |
Przeprowadzanie konwersji CHAR i WCHAR
Natywny sterownik ODBC klienta SQL Server 2012 (11.x) oferuje kilka sposobów wykonywania konwersji CHAR i WCHAR. Logika jest podobna do manipulowania plamami (varchar(max), nvarchar(max), ...):
Dane są zapisywane lub obcinane do określonego bufora podczas wiązania z SQLBindCol lub SQLBindParametrem.
Jeśli nie masz bindu, możesz pobierać dane w kawałkach, używając SQLGetData i SQLParamData.