Obtener datos de tipo Long

DbMS define los datos largos como cualquier carácter o datos binarios en un tamaño determinado, como 255 caracteres. Estos datos pueden ser lo suficientemente pequeños como para almacenarse en un único búfer, como una descripción de parte de varios miles de caracteres. Sin embargo, pueden ser demasiado largos para almacenarse en memoria, como documentos de texto largos o mapas de bits. Dado que estos datos no se pueden almacenar en un único búfer, se recupera del controlador en partes con SQLGetData después de capturar los demás datos de la fila.

Nota:

Una aplicación puede recuperar realmente cualquier tipo de datos con SQLGetData, no solo datos largos, aunque solo se pueden recuperar datos binarios y de caracteres en partes. Sin embargo, si los datos son lo suficientemente pequeños como para caber en un solo búfer, por lo general no hay ninguna razón para usar SQLGetData. Es mucho más fácil enlazar un búfer a la columna y permitir que el controlador devuelva los datos en el búfer.

Para recuperar datos largos de una columna, una aplicación llama primero a SQLFetchScroll o SQLFetch para pasar a una fila y capturar los datos de las columnas enlazadas. A continuación, la aplicación llama a SQLGetData. SQLGetData tiene los mismos argumentos que SQLBindCol: un identificador de instrucción; un número de columna; el tipo de datos C, la dirección y la longitud de bytes de una variable de aplicación; y la dirección de un búfer de longitud o indicador. Ambas funciones tienen los mismos argumentos porque realizan básicamente la misma tarea: ambos describen una variable de aplicación al controlador y especifican que los datos de una columna determinada deben devolverse en esa variable. Las principales diferencias son que se llama a SQLGetData después de capturar una fila (y a veces se conoce como enlace en tiempo de ejecución por este motivo) y que el enlace especificado por SQLGetData solo dura la duración de la llamada.

Con respecto a una sola columna, SQLGetData se comporta como SQLFetch: recupera los datos de la columna, los convierte en el tipo de la variable de aplicación y los devuelve en esa variable. También devuelve la longitud de bytes de los datos en el búfer de longitud o indicador. Para obtener más información sobre cómo SQLFetch devuelve datos, vea Captura de una fila de datos.

SQLGetData difiere de SQLFetch en un aspecto importante. Si se llama más de una vez sucesivamente para la misma columna, cada llamada devuelve una parte sucesiva de los datos. Cada llamada, excepto la última, devuelve SQL_SUCCESS_WITH_INFO y SQLSTATE 01004 (datos de cadena, truncado derecho). La última llamada devuelve SQL_SUCCESS. Así es como se usa SQLGetData para recuperar datos largos en partes. Cuando no hay más datos que devolver, SQLGetData devuelve SQL_NO_DATA. La aplicación es responsable de reunir los datos largos, lo que podría significar concatenar las partes de los datos. Cada parte está terminada en NULL. La aplicación debe quitar el carácter de terminación NULL si concatena las partes. La recuperación de datos en partes se puede realizar para marcadores de longitud variable, así como para otros datos largos. El valor devuelto en el búfer de longitud o indicador disminuye en cada llamada por el número de bytes devueltos en la llamada anterior, aunque es habitual que el controlador no pueda detectar la cantidad de datos disponibles y devolver una longitud de bytes de SQL_NO_TOTAL. Por ejemplo:

// Declare a binary buffer to retrieve 5000 bytes of data at a time.  
SQLCHAR       BinaryPtr[5000];  
SQLUINTEGER   PartID;  
SQLINTEGER    PartIDInd, BinaryLenOrInd, NumBytes;  
SQLRETURN     rc;   
SQLHSTMT      hstmt;  
  
// Create a result set containing the ID and picture of each part.  
SQLExecDirect(hstmt, "SELECT PartID, Picture FROM Pictures", SQL_NTS);  
  
// Bind PartID to the PartID column.  
SQLBindCol(hstmt, 1, SQL_C_ULONG, &PartID, 0, &PartIDInd);  
  
// Retrieve and display each row of data.  
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {  
   // Display the part ID and initialize the picture.  
   DisplayID(PartID, PartIDInd);  
   InitPicture();  
  
   // Retrieve the picture data in parts. Send each part and the number   
   // of bytes in each part to a function that displays it. The number   
   // of bytes is always 5000 if there were more than 5000 bytes   
   // available to return (cbBinaryBuffer > 5000). Code to check if   
   // rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.  
   while ((rc = SQLGetData(hstmt, 2, SQL_C_BINARY, BinaryPtr, sizeof(BinaryPtr),  
                           &BinaryLenOrInd)) != SQL_NO_DATA) {  
      NumBytes = (BinaryLenOrInd > 5000) || (BinaryLenOrInd == SQL_NO_TOTAL) ?  
                  5000 : BinaryLenOrInd;  
      DisplayNextPictPart(BinaryPtr, NumBytes);  
   }  
}  
  
// Close the cursor.  
SQLCloseCursor(hstmt);  

Hay varias restricciones en el uso de SQLGetData. Por lo general, las columnas a las que se accede con SQLGetData:

  • Se debe tener acceso a ellas según un orden de número de columna ascendente (debido a la forma en que se leen las columnas de un conjunto de resultados del origen de datos). Por ejemplo, es un error llamar a SQLGetData para la columna 5 y, a continuación, llamarlo para la columna 4.

  • No se pueden enlazar.

  • Deben tener un número de columna mayor que la última columna enlazada. Por ejemplo, si la última columna enlazada es la columna 3, es un error llamar a SQLGetData para la columna 2. Por este motivo, las aplicaciones deben asegurarse de colocar columnas de datos largos al final de la lista de selección.

  • No se pueden usar si se llamó a SQLFetch o SQLFetchScroll para recuperar más de una fila. Para obtener más información, consulte Uso de cursores de bloque.

Algunos controladores no aplican estas restricciones. Las aplicaciones interoperables deben suponer que existen o determinar qué restricciones no se aplican mediante una llamada a SQLGetInfo con la opción SQL_GETDATA_EXTENSIONS.

Si la aplicación no necesita todos los datos de una columna de datos binarios o de caracteres, puede reducir el tráfico de red en controladores basados en DBMS estableciendo el atributo de instrucción SQL_ATTR_MAX_LENGTH antes de ejecutar la instrucción. Esto restringe el número de bytes de datos que se devolverán para cualquier carácter o columna binaria. Por ejemplo, supongamos que una columna contiene documentos de texto largos. Es posible que una aplicación que examine la tabla que contiene esta columna solo tenga que mostrar la primera página de cada documento. Aunque este atributo de instrucción se puede simular en el controlador, no hay ninguna razón para hacerlo. En concreto, si una aplicación quiere truncar datos binarios o de caracteres, debe enlazar un búfer pequeño a la columna con SQLBindCol y permitir que el controlador trunque los datos.