Compartir a través de


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

El controlador ODBC de SQL Server 2012 Native Client (SQLNCLI11.dll) cambió la forma de realizar las conversiones SQL_WCHAR* (NCHAR/NVARCHAR/NVARCHAR(MAX)) y SQL_CHAR* (CHAR/VARCHAR/NARCHAR(MAX)). Las funciones ODBC, como SQLGetData, SQLBindCol y SQLBindParameter, devuelven (-4) SQL_NO_TOTAL como el parámetro indicador de longitud al utilizar el controlador ODBC de SQL Server 2012 Native Client. Las versiones anteriores del controlador ODBC de SQL Server Native Client devolvían 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 se debe utilizar 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 realiza una consulta en una columna varchar y el enlace se especifica 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 Native Client o anterior

6

El controlador suponía incorrectamente que la conversión de CHAR en WCHAR se podía conseguir como longitud * 2.

SQL Server 2012 Native Client (versión 11.0.2100.60) o posterior

-4 (SQL_NO_TOTAL)

El controlador ya no da por supuesto que la conversión de CHAR en WCHAR o de WCHAR en CHAR es una acción de (multiplicar) *2 o de (dividir) /2.

La llamada 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.

Utilice SQLGetData para recuperar los fragmentos de 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 Native Client o anterior

20

  • SQLFetch indica 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 Native Client (versión 11.0.2100.60) o posterior

-4 (SQL_NO_TOTAL)

  • SQLFetch indica 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 Native Client o anterior

2468

  • SQLFetch devuelve que no hay más datos disponibles.

  • SQLMoreResults devuelve que no hay 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 Native Client (versión 11.0.2100.60) o posterior

-4 (SQL_NO_TOTAL)

  • SQLFetch devuelve que no hay más datos disponibles.

  • SQLMoreResults devuelve que no hay 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 Native Client ofrece varias maneras de realizar las conversiones CHAR y WCHAR. La lógica es similar a la manipulación de blobs (varchar(max), nvarchar(max), …):

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

  • Si no realiza el enlace, puede recuperar los datos en fragmentos mediante SQLGetData y SQLParamData.

Vea también

Otros recursos

Características de SQL Server Native Client