Compartir a través de


Cambio de comportamiento del controlador ODBC al administrar las conversiones de caracteres

Se aplica a: SQL Server Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW)

Importante

SQL Server Native Client (SNAC) no se incluye con:

  • SQL Server 2022 (16.x) y versiones posteriores
  • SQL Server Management Studio 19 y versiones posteriores

Sql Server Native Client (SQLNCLI o SQLNCLI11) y el proveedor MICROSOFT OLE DB heredado para SQL Server (SQLOLEDB) no se recomiendan para el desarrollo de aplicaciones nuevas.

En el caso de los proyectos nuevos, use uno de los siguientes controladores:

Para SQLNCLI que se incluye como componente de motor de base de datos de SQL Server (versiones 2012 a 2019), consulte esta excepción de ciclo de vida de soporte técnico.

El controlador ODBC de SQL Server 2012 (11.x) Native Client (SQLNCLI11.dll) cambió cómo funciona SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR/NVARCHAR(MAX)) y SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)). Las funciones ODBC, como SQLGetData, SQLBindCol, SQLBindParameter, devuelven (-4) SQL_NO_TOTAL como parámetro length/indicador al usar el controlador ODBC de SQL Server 2012 Native Client. Las versiones anteriores del controlador ODBC de SQL Server Native Client devolvieron un valor de longitud, que puede ser incorrecto.

Comportamiento de SQLGetData

Muchas funciones de Windows permiten especificar un tamaño de búfer de 0, siendo la longitud devuelta el tamaño de los datos devueltos. El patrón siguiente es frecuente para los programadores de 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  

Sin embargo, SQLGetData no debe usarse en este escenario. No se debe utilizar el patrón siguiente:

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

Solo se puede llamar a SQLGetData para recuperar fragmentos de datos reales. No se admite el uso de SQLGetData para obtener el tamaño de los datos.

A continuación se muestra el impacto del cambio de controlador cuando se utiliza el patrón incorrecto. Esta aplicación consulta una columna varchar y un enlace como Unicode (SQL_UNICODE/SQL_WCHAR):

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

SQLGetData(hstmt, SQL_WCHAR, ....., (SQLPOINTER*) 0x1, 0 , &iSize);   // Attempting to determine storage size needed  
Versión del controlador ODBC de SQL Server Native Client Resultado de indicador o de longitud Descripción
SQL Server 2008 R2 (10.50.x) Native Client o versiones anteriores 6 El controlador suponía incorrectamente que la conversión de CHAR en WCHAR se podía conseguir como longitud * 2.
SQL Server 2012 (11.x) Native Client (versión 11.0.2100.60) o posterior -4 (SQL_NO_TOTAL) El controlador ya no supone que la conversión de CHAR a WCHAR o WCHAR a CHAR es una acción (multiplicar) *2 o (dividir)/2.

Llamar a SQLGetData ya no devuelve la longitud de la conversión esperada. El controlador detecta la conversión a o desde CHAR y WCHAR y devuelve (-4) SQL_NO_TOTAL en lugar del comportamiento *2 o /2, que podría ser incorrecto.

Use SQLGetData para recuperar los fragmentos de los datos. (Se muestra el pseudocódigo:)

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

Comportamiento de SQLBindCol

Consulta: select convert(varchar(36), '1234567890')

SQLBindCol(... SQL_W_CHAR, ...)   // Only bound a buffer of WCHAR[4] - Expecting String Data Right Truncation behavior  
Versión del controlador ODBC de SQL Server Native Client Resultado de indicador o de longitud Descripción
SQL Server 2008 R2 (10.50.x) Native Client o versiones anteriores 20 SQLFetch informa de que hay un truncamiento en el lado derecho de los datos.

La longitud es la longitud de los datos devueltos, no lo que se almacenó (se supone una conversión *2 de CHAR en WCHAR, lo que puede ser incorrecto para los glifos).

Los datos almacenados en el búfer son 123\0. Se garantiza que el búfer está terminado en NULL.
SQL Server 2012 (11.x) Native Client (versión 11.0.2100.60) o posterior -4 (SQL_NO_TOTAL) SQLFetch informa de que hay un truncamiento en el lado derecho de los datos.

La longitud indica -4 (SQL_NO_TOTAL) debido a que el resto de los datos no se convirtió.

Los datos almacenados en el búfer son 123\0. - Se garantiza que el búfer está terminado en NULL.

SQLBindParameter (comportamiento del parámetro OUTPUT)

Consulta: create procedure spTest @p1 varchar(max) OUTPUT

select @p1 = replicate('B', 1234)

SQLBindParameter(... SQL_W_CHAR, ...)   // Only bind up to first 64 characters  
Versión del controlador ODBC de SQL Server Native Client Resultado de indicador o de longitud Descripción
SQL Server 2008 R2 (10.50.x) Native Client o versiones anteriores 2468 SQLFetch no devuelve más datos disponibles.

SQLMoreResults no devuelve más datos disponibles.

La longitud indica el tamaño de los datos devueltos desde el servidor, no el de los datos almacenados en el búfer.

El búfer original contiene 63 bytes y un terminador NULL. Se garantiza que el búfer está terminado en NULL.
SQL Server 2012 (11.x) Native Client (versión 11.0.2100.60) o posterior -4 (SQL_NO_TOTAL) SQLFetch no devuelve más datos disponibles.

SQLMoreResults no devuelve más datos disponibles.

La longitud indica (-4) SQL_NO_TOTAL debido a que el resto de los datos no se convirtió.

El búfer original contiene 63 bytes y un terminador NULL. Se garantiza que el búfer está terminado en NULL.

Realizar conversiones CHAR y WCHAR

El controlador ODBC de SQL Server 2012 (11.x) Native Client ofrece varias maneras de realizar conversiones CHAR y WCHAR. La lógica es similar a manipular blobs (varchar(max), nvarchar(max), ...):

  • Los datos se guardan o truncan en el búfer especificado al enlazar con SQLBindCol o SQLBindParameter.

  • Si no se enlaza, puede recuperar los datos en fragmentos mediante SQLGetData y SQLParamData.

Consulte también

Características de SQL Server Native Client