Obtention de données de type Long

Les SGBD définissent les données longues comme n’importe quel caractère ou données binaires sur une certaine taille, par exemple 255 caractères. Ces données peuvent être suffisamment petites pour être stockées dans une mémoire tampon unique, par exemple une description de plusieurs milliers de caractères. Toutefois, il peut être trop long de stocker en mémoire, comme les documents texte longs ou les bitmaps. Étant donné que ces données ne peuvent pas être stockées dans une mémoire tampon unique, elles sont récupérées à partir du pilote dans des parties avec SQLGetData une fois que les autres données de la ligne ont été extraites.

Remarque

Une application peut en fait récupérer n’importe quel type de données avec SQLGetData, pas seulement les données longues, bien que seules les données caractères et binaires puissent être récupérées en parties. Toutefois, si les données sont suffisamment petites pour s’adapter à une seule mémoire tampon, il n’existe généralement aucune raison d’utiliser SQLGetData. Il est beaucoup plus facile de lier une mémoire tampon à la colonne et de laisser le pilote retourner les données dans la mémoire tampon.

Pour récupérer des données longues à partir d’une colonne, une application appelle d’abord SQLFetchScroll ou SQLFetch pour passer à une ligne et extraire les données des colonnes liées. L’application appelle ensuite SQLGetData. SQLGetData a les mêmes arguments que SQLBindCol : un handle d’instruction ; un numéro de colonne ; le type de données C, l’adresse et la longueur d’octet d’une variable d’application ; et l’adresse d’une mémoire tampon de longueur/indicateur. Les deux fonctions ont les mêmes arguments, car elles effectuent essentiellement la même tâche : elles décrivent toutes les deux une variable d’application au pilote et spécifient que les données d’une colonne particulière doivent être retournées dans cette variable. Les principales différences sont que SQLGetData est appelé après la récupération d’une ligne (et est parfois appelé liaison tardive pour cette raison) et que la liaison spécifiée par SQLGetData dure uniquement pendant la durée de l’appel.

En ce qui concerne une seule colonne, SQLGetData se comporte comme SQLFetch : il récupère les données de la colonne, la convertit en type de variable d’application et la retourne dans cette variable. Elle retourne également la longueur d’octet des données dans la mémoire tampon longueur/indicateur. Pour plus d’informations sur la façon dont SQLFetch retourne des données, consultez Extraction d’une ligne de données.

SQLGetData diffère de SQLFetch d’un point de vue important. S’il est appelé plusieurs fois par succession pour la même colonne, chaque appel retourne une partie successive des données. Chaque appel à l’exception du dernier appel retourne SQL_SUCCESS_WITH_INFO et SQLSTATE 01004 (données de chaîne, tronquées à droite) ; le dernier appel retourne SQL_SUCCESS. Il s’agit de la façon dont SQLGetData est utilisé pour récupérer des données longues en parties. Lorsqu’il n’y a plus de données à retourner, SQLGetData retourne SQL_NO_DATA. L’application est chargée de regrouper les données longues, ce qui peut signifier concaténer les parties des données. Chaque partie est terminée par null ; l’application doit supprimer le caractère d’arrêt null s’il concatène les parties. La récupération de données en parties peut être effectuée pour les signets de longueur variable, ainsi que pour d’autres données longues. La valeur retournée dans la mémoire tampon de longueur/indicateur diminue dans chaque appel par le nombre d’octets retournés dans l’appel précédent, bien qu’il soit courant que le pilote ne puisse pas découvrir la quantité de données disponibles et retourner une longueur d’octet de SQL_NO_TOTAL. Par exemple :

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

Il existe plusieurs restrictions sur l’utilisation de SQLGetData. En règle générale, les colonnes accessibles avec SQLGetData :

  • Doit être accessible dans l’ordre d’augmentation du nombre de colonnes (en raison de la façon dont les colonnes d’un jeu de résultats sont lues à partir de la source de données). Par exemple, il s’agit d’une erreur d’appel de SQLGetData pour la colonne 5, puis de l’appeler pour la colonne 4.

  • Impossible d’être lié.

  • Doit avoir un numéro de colonne supérieur à la dernière colonne liée. Par exemple, si la dernière colonne liée est la colonne 3, il s’agit d’une erreur d’appel de SQLGetData pour la colonne 2. Pour cette raison, les applications doivent s’assurer de placer de longues colonnes de données à la fin de la liste de sélection.

  • Impossible d’utiliser si SQLFetch ou SQLFetchScroll a été appelé pour récupérer plusieurs lignes. Pour plus d’informations, consultez Utilisation des curseurs de bloc.

Certains pilotes n’appliquent pas ces restrictions. Les applications interopérables doivent supposer qu’elles existent ou déterminer quelles restrictions ne sont pas appliquées en appelant SQLGetInfo avec l’option SQL_GETDATA_EXTENSIONS.

Si l’application n’a pas besoin de toutes les données d’une colonne de données caractère ou binaire, elle peut réduire le trafic réseau dans les pilotes SGBD en définissant l’attribut d’instruction SQL_ATTR_MAX_LENGTH avant d’exécuter l’instruction. Cela limite le nombre d’octets de données qui seront retournés pour n’importe quel caractère ou colonne binaire. Par exemple, supposons qu’une colonne contient des documents texte longs. Une application qui parcoure la table contenant cette colonne peut avoir à afficher uniquement la première page de chaque document. Bien que cet attribut d’instruction puisse être simulé dans le pilote, il n’y a aucune raison de le faire. En particulier, si une application souhaite tronquer des données binaires ou caractère, elle doit lier une petite mémoire tampon à la colonne avec SQLBindCol et laisser le pilote tronquer les données.