Récupération des paramètres de sortie à l’aide de SQLGetData

Avant ODBC 3.8, une application ne peut récupérer que les paramètres de sortie d’une requête avec une mémoire tampon de sortie liée. Toutefois, il est difficile d’allouer une mémoire tampon très importante lorsque la taille de la valeur du paramètre est très grande (par exemple, une image volumineuse). ODBC 3.8 introduit une nouvelle façon de récupérer les paramètres de sortie en parties. Une application peut désormais appeler SQLGetData avec une petite mémoire tampon plusieurs fois pour récupérer une valeur de paramètre volumineuse. Cela est similaire à la récupération de données de colonnes volumineuses.

Pour lier un paramètre de sortie ou un paramètre d’entrée/sortie à récupérer en parties, appelez SQLBindParameter avec l’argument InputOutputType défini sur SQL_PARAM_OUTPUT_STREAM ou SQL_PARAM_INPUT_OUTPUT_STREAM. Avec SQL_PARAM_INPUT_OUTPUT_STREAM, une application peut utiliser SQLPutData pour entrer des données dans le paramètre, puis utiliser SQLGetData pour récupérer le paramètre de sortie. Les données d’entrée doivent se trouver dans le formulaire data-at-execution (DAE), à l’aide de SQLPutData au lieu de la lier à une mémoire tampon prélocalisée.

Cette fonctionnalité peut être utilisée par des applications ODBC 3.8 ou des applications ODBC 3.x et ODBC 2.x recompilées, et ces applications doivent avoir un pilote ODBC 3.8 qui prend en charge la récupération des paramètres de sortie à l’aide de SQLGetData et ODBC 3.8 Driver Manager. Pour plus d’informations sur l’activation d’une application plus ancienne pour utiliser de nouvelles fonctionnalités ODBC, consultez La matrice de compatibilité.

Exemple d’utilisation

Par exemple, envisagez d’exécuter une procédure stockée, {CALL sp_f(?,?)}, où les deux paramètres sont liés en tant que SQL_PARAM_OUTPUT_STREAM, et la procédure stockée ne retourne aucun jeu de résultats (plus loin dans cette rubrique, vous trouverez un scénario plus complexe) :

  1. Pour chaque paramètre, appelez SQLBindParameter avec InputOutputType défini sur SQL_PARAM_OUTPUT_STREAM et ParameterValuePtr défini sur un jeton, tel qu’un numéro de paramètre, un pointeur vers des données ou un pointeur vers une structure utilisée par l’application pour lier des paramètres d’entrée. Cet exemple utilise l’ordinal de paramètre comme jeton.

  2. Exécutez la requête avec SQLExecDirect ou SQLExecute. SQL_PARAM_DATA_AVAILABLE est retourné, indiquant qu’il existe des paramètres de sortie en continu disponibles pour la récupération.

  3. Appelez SQLParamData pour obtenir le paramètre disponible pour la récupération. SQLParamData retourne SQL_PARAM_DATA_AVAILABLE avec le jeton du premier paramètre disponible, qui est défini dans SQLBindParameter (étape 1). Le jeton est retourné dans la mémoire tampon vers laquelle pointe ValuePtrPtr .

  4. Appelez SQLGetData avec l’argument Col_or_Param_Num défini sur l’ordinal du paramètre pour récupérer les données du premier paramètre disponible. Si SQLGetData retourne SQL_SUCCESS_WITH_INFO et SQLState 01004 (données tronquées) et que le type est de longueur variable sur le client et le serveur, il existe plus de données à récupérer à partir du premier paramètre disponible. Vous pouvez continuer à appeler SQLGetData jusqu’à ce qu’il retourne SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO avec un autre SQLState.

  5. Répétez l’étape 3 et l’étape 4 pour récupérer le paramètre actuel.

  6. Appelez à nouveau SQLParamData . S’il retourne quelque chose sauf SQL_PARAM_DATA_AVAILABLE, il n’y a plus de données de paramètre diffusées en continu à récupérer, et le code de retour sera le code de retour de l’instruction suivante qui est exécutée.

  7. Appelez SQLMoreResults pour traiter le jeu de paramètres suivant jusqu’à ce qu’il retourne SQL_NO_DATA. SQLMoreResults retourne SQL_NO_DATA dans cet exemple si l’attribut d’instruction SQL_ATTR_PARAMSET_SIZE a été défini sur 1. Sinon, SQLMoreResults retourne SQL_PARAM_DATA_AVAILABLE pour indiquer qu’il existe des paramètres de sortie en flux disponibles pour le prochain ensemble de paramètres à récupérer.

Comme pour un paramètre d’entrée DAE, le jeton utilisé dans l’argument ParameterValuePtr dans SQLBindParameter (étape 1) peut être un pointeur qui pointe vers une structure de données d’application, qui contient l’ordinal du paramètre et d’autres informations spécifiques à l’application, si nécessaire.

L’ordre des paramètres de sortie ou d’entrée/sortie renvoyés est spécifique au pilote et peut ne pas toujours être identique à l’ordre spécifié dans la requête.

Si l’application n’appelle pas SQLGetData à l’étape 4, la valeur du paramètre est dis carte ed. De même, si l’application appelle SQLParamData avant que l’ensemble d’une valeur de paramètre ait été lue par SQLGetData, le reste de la valeur est dis carte ed et l’application peut traiter le paramètre suivant.

Si l’application appelle SQLMoreResults avant que tous les paramètres de sortie diffusés soient traités (SQLParamData retourne toujours SQL_PARAM_DATA_AVAILABLE), tous les paramètres restants sont dis carte ed. De même, si l’application appelle SQLMoreResults avant que l’ensemble d’une valeur de paramètre ait été lue par SQLGetData, le reste de la valeur et tous les paramètres restants sont dis carte ed, et l’application peut continuer à traiter le jeu de paramètres suivant.

Notez qu’une application peut spécifier le type de données C dans SQLBindParameter et SQLGetData. Le type de données C spécifié avec SQLGetData remplace le type de données C spécifié dans SQLBindParameter, sauf si le type de données C spécifié dans SQLGetData est SQL_APD_TYPE.

Bien qu’un paramètre de sortie diffusé en continu soit plus utile lorsque le type de données du paramètre de sortie est de type BLOB, cette fonctionnalité peut également être utilisée avec n’importe quel type de données. Les types de données pris en charge par les paramètres de sortie en flux sont spécifiés dans le pilote.

S’il existe SQL_PARAM_INPUT_OUTPUT_STREAM paramètres à traiter, SQLExecute ou SQLExecDirect retourne d’abord SQL_NEED_DATA. Une application peut appeler SQLParamData et SQLPutData pour envoyer des données de paramètre DAE. Lorsque tous les paramètres d’entrée DAE sont traités, SQLParamData retourne SQL_PARAM_DATA_AVAILABLE pour indiquer que les paramètres de sortie diffusés sont disponibles.

Lorsqu’il existe des paramètres de sortie en continu et des paramètres de sortie liés à traiter, le pilote détermine l’ordre de traitement des paramètres de sortie. Par conséquent, si un paramètre de sortie est lié à une mémoire tampon (le paramètre SQLBindParameter InputOutputType est défini sur SQL_PARAM_INPUT_OUTPUT ou SQL_PARAM_OUTPUT), la mémoire tampon peut ne pas être remplie tant que SQLParamData ne retourne SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO. Une application doit lire une mémoire tampon liée uniquement une fois que SQLParamData retourne SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO qui se trouve après le traitement de tous les paramètres de sortie diffusés en continu.

La source de données peut retourner un jeu d’avertissements et de résultats, en plus du paramètre de sortie diffusé en continu. En général, les avertissements et les jeux de résultats sont traités séparément d’un paramètre de sortie en continu en appelant SQLMoreResults. Traiter les avertissements et le jeu de résultats avant de traiter le paramètre de sortie diffusé en continu.

Le tableau suivant décrit différents scénarios d’une seule commande envoyée au serveur et la façon dont l’application doit fonctionner.

Scénario Valeur renvoyée par SQLExecute ou SQLExecDirect Que faire maintenant ?
Les données incluent uniquement les paramètres de sortie diffusés en continu SQL_PARAM_DATA_AVAILABLE Utilisez SQLParamData et SQLGetData pour récupérer les paramètres de sortie diffusés en continu.
Les données incluent un jeu de résultats et des paramètres de sortie diffusés en continu SQL_SUCCESS Récupérez le jeu de résultats avec SQLBindCol et SQLGetData.

Appelez SQLMoreResults pour démarrer le traitement des paramètres de sortie diffusés en continu. Elle doit retourner SQL_PARAM_DATA_AVAILABLE.

Utilisez SQLParamData et SQLGetData pour récupérer les paramètres de sortie diffusés en continu.
Les données incluent un message d’avertissement et des paramètres de sortie diffusés en continu SQL_SUCCESS_WITH_INFO Utilisez SQLGetDiagRec et SQLGetDiagField pour traiter les messages d’avertissement.

Appelez SQLMoreResults pour démarrer le traitement des paramètres de sortie diffusés en continu. Elle doit retourner SQL_PARAM_DATA_AVAILABLE.

Utilisez SQLParamData et SQLGetData pour récupérer les paramètres de sortie diffusés en continu.
Les données incluent un message d’avertissement, un jeu de résultats et des paramètres de sortie diffusés en continu SQL_SUCCESS_WITH_INFO Utilisez SQLGetDiagRec et SQLGetDiagField pour traiter les messages d’avertissement. Appelez ensuite SQLMoreResults pour commencer à traiter le jeu de résultats.

Récupérez un jeu de résultats avec SQLBindCol et SQLGetData.

Appelez SQLMoreResults pour démarrer le traitement des paramètres de sortie diffusés en continu. SQLMoreResults doit retourner SQL_PARAM_DATA_AVAILABLE.

Utilisez SQLParamData et SQLGetData pour récupérer les paramètres de sortie diffusés en continu.
Interroger avec des paramètres d’entrée DAE, par exemple, un paramètre d’entrée/sortie en continu (DAE) SQL NEED_DATA Appelez SQLParamData et SQLPutData pour envoyer des données de paramètre d’entrée DAE.

Une fois tous les paramètres d’entrée DAE traités, SQLParamData peut retourner n’importe quel code de retour que SQLExecute et SQLExecDirect peuvent retourner. Les cas de ce tableau peuvent ensuite être appliqués.

Si le code de retour est SQL_PARAM_DATA_AVAILABLE, les paramètres de sortie diffusés en continu sont disponibles. Une application doit appeler à nouveau SQLParamData pour récupérer le jeton du paramètre de sortie en continu, comme décrit dans la première ligne de cette table.

Si le code de retour est SQL_SUCCESS, il existe un jeu de résultats à traiter ou le traitement est terminé.

Si le code de retour est SQL_SUCCESS_WITH_INFO, il existe des messages d’avertissement à traiter.

Une fois SQLExecute, SQLExecDirect ou SQLMoreResults retourné SQL_PARAM_DATA_AVAILABLE, une erreur de séquence de fonctions se produit si une application appelle une fonction qui n’est pas dans la liste suivante :

  • SQLAllocHandle / SQLAllocHandleStd

  • SQLDataSources / SQLDrivers

  • SQLGetInfo / SQLGetFunctions

  • SQLGet Connecter Attr / SQLGetEnvAttr / SQLGetDescField / SQLGetDescRec

  • SQLNumParams

  • SQLDescribeParam

  • SQLNativeSql

  • SQLParamData

  • SQLMoreResults

  • SQLGetDiagField / SQLGetDiagRec

  • SQLCancel

  • SQLCancelHandle (with statement handle)

  • SQLFreeStmt (avec Option = SQL_CLOSE, SQL_DROP ou SQL_UNBIND)

  • SQLCloseCursor

  • SQLDisconnect

  • SQLFreeHandle (avec HandleType = SQL_HANDLE_STMT)

  • SQLGetStmtAttr

Les applications peuvent toujours utiliser SQLSetDescField ou SQLSetDescRec pour définir les informations de liaison. Le mappage de champs n’est pas modifié. Toutefois, les champs à l’intérieur du descripteur peuvent retourner de nouvelles valeurs. Par exemple, SQL_DESC_PARAMETER_TYPE peut retourner SQL_PARAM_INPUT_OUTPUT_STREAM ou SQL_PARAM_OUTPUT_STREAM.

Scénario d’utilisation : Récupérer une image dans des parties à partir d’un jeu de résultats

SQLGetData peut être utilisé pour obtenir des données en parties lorsqu’une procédure stockée retourne un jeu de résultats qui contient une ligne de métadonnées sur une image et que l’image est retournée dans un paramètre de sortie volumineux.

// CREATE PROCEDURE SP_TestOutputPara  
//      @ID_of_picture   as int,  
//      @Picture         as varbinary(max) out  
// AS  
//     output the image data through streamed output parameter  
// GO  
BOOL displayPicture(SQLUINTEGER idOfPicture, SQLHSTMT hstmt) {  
   SQLLEN      lengthOfPicture;    // The actual length of the picture.  
   BYTE        smallBuffer[100];   // A very small buffer.  
   SQLRETURN   retcode, retcode2;  
  
   // Bind the first parameter (input parameter)  
   SQLBindParameter(  
         hstmt,  
         1,                         // The first parameter.   
         SQL_PARAM_INPUT,           // Input parameter: The ID_of_picture.  
         SQL_C_ULONG,               // The C Data Type.  
         SQL_INTEGER,               // The SQL Data Type.  
         0,                         // ColumnSize is ignored for integer.  
         0,                         // DecimalDigits is ignored for integer.  
         &idOfPicture,              // The Address of the buffer for the input parameter.  
         0,                         // BufferLength is ignored for integer.  
         NULL);                     // This is ignored for integer.  
  
   // Bind the streamed output parameter.  
   SQLBindParameter(  
         hstmt,   
         2,                         // The second parameter.  
         SQL_PARAM_OUTPUT_STREAM,   // A streamed output parameter.   
         SQL_C_BINARY,              // The C Data Type.    
         SQL_VARBINARY,             // The SQL Data Type.  
         0,                         // ColumnSize: The maximum size of varbinary(max).  
         0,                         // DecimalDigits is ignored for binary type.  
         (SQLPOINTER)2,             // ParameterValuePtr: An application-defined  
                                    // token (this will be returned from SQLParamData).  
                                    // In this example, we used the ordinal   
                                    // of the parameter.  
         0,                         // BufferLength is ignored for streamed output parameters.  
         &lengthOfPicture);         // StrLen_or_IndPtr: The status variable returned.   
  
   retcode = SQLPrepare(hstmt, L"{call SP_TestOutputPara(?, ?)}", SQL_NTS);  
   if ( retcode == SQL_ERROR )  
      return FALSE;  
  
   retcode = SQLExecute(hstmt);  
   if ( retcode == SQL_ERROR )  
      return FALSE;  
  
   // Assume that the retrieved picture exists.  Use SQLBindCol or SQLGetData to retrieve the result-set.  
  
   // Process the result set and move to the streamed output parameters.  
   retcode = SQLMoreResults( hstmt );  
  
   // SQLGetData retrieves and displays the picture in parts.  
   // The streamed output parameter is available.  
   while (retcode == SQL_PARAM_DATA_AVAILABLE) {  
      SQLPOINTER token;   // Output by SQLParamData.  
      SQLLEN cbLeft;      // #bytes remained  
      retcode = SQLParamData(hstmt, &token);   // returned token is 2 (according to the binding)  
      if ( retcode == SQL_PARAM_DATA_AVAILABLE ) {  
         // A do-while loop retrieves the picture in parts.  
         do {  
            retcode2 = SQLGetData(   
               hstmt,   
               (UWORD) token,          // the value of the token is the ordinal.   
               SQL_C_BINARY,           // The C-type.  
               smallBuffer,            // A small buffer.   
               sizeof(smallBuffer),    // The size of the buffer.  
               &cbLeft);               // How much data we can get.  
         }  
         while ( retcode2 == SQL_SUCCESS_WITH_INFO );  
      }  
   }  
  
   return TRUE;  
}  

Scénario d’utilisation : Envoyer et recevoir un objet volumineux en tant que paramètre d’entrée/sortie en continu

SQLGetData peut être utilisé pour obtenir et envoyer des données en parties lorsqu’une procédure stockée transmet un objet volumineux en tant que paramètre d’entrée/sortie, en continuant la valeur vers et à partir de la base de données. Vous n’avez pas besoin de stocker toutes les données en mémoire.

// CREATE PROCEDURE SP_TestInOut  
//       @picture as varbinary(max) out  
// AS  
//    output the image data through output parameter   
// go  
  
BOOL displaySimilarPicture(BYTE* image, ULONG lengthOfImage, SQLHSTMT hstmt) {  
   BYTE smallBuffer[100];   // A very small buffer.  
   SQLRETURN retcode, retcode2;  
   SQLLEN statusOfPicture;  
  
   // First bind the parameters, before preparing the statement that binds the output streamed parameter.  
   SQLBindParameter(  
      hstmt,   
      1,                                 // The first parameter.  
      SQL_PARAM_INPUT_OUTPUT_STREAM,     // I/O-streamed parameter: The Picture.  
      SQL_C_BINARY,                      // The C Data Type.  
      SQL_VARBINARY,                     // The SQL Data Type.  
      0,                                 // ColumnSize: The maximum size of varbinary(max).  
      0,                                 // DecimalDigits is ignored.   
      (SQLPOINTER)1,                     // An application defined token.   
      0,                                 // BufferLength is ignored for streamed I/O parameters.  
      &statusOfPicture);                 // The status variable.  
  
   statusOfPicture = SQL_DATA_AT_EXEC;   // Input data in parts (DAE parameter at input).  
  
   retcode = SQLPrepare(hstmt, L"{call SP_TestInOut(?) }", SQL_NTS);  
   if ( retcode == SQL_ERROR )  
      return FALSE;  
  
   // Execute the statement.  
   retcode = SQLExecute(hstmt);  
   if ( retcode == SQL_ERROR )  
      return FALSE;  
  
   if ( retcode == SQL_NEED_DATA ) {  
      // Use SQLParamData to loop through DAE input parameters.  For  
      // each, use SQLPutData to send the data to database in parts.  
  
      // This example uses an I/O parameter with streamed output.  
      // Therefore, the last call to SQLParamData should return  
      // SQL_PARAM_DATA_AVAILABLE to indicate the end of the input phrase   
      // and report that a streamed output parameter is available.  
  
      // Assume retcode is set to the return value of the last call to  
      // SQLParamData, which is equal to SQL_PARAM_DATA_AVAILABLE.  
   }  
  
   // Start processing the streamed output parameters.  
   while ( retcode == SQL_PARAM_DATA_AVAILABLE ) {  
      SQLPOINTER token;   // Output by SQLParamData.  
      SQLLEN cbLeft;     // #bytes remained  
      retcode = SQLParamData(hstmt, &token);  
      if ( retcode == SQL_PARAM_DATA_AVAILABLE ) {  
         do {  
            retcode2 = SQLGetData(   
               hstmt,   
               (UWORD) token,          // the value of the token is the ordinal.   
               SQL_C_BINARY,           // The C-type.  
               smallBuffer,            // A small buffer.   
               sizeof(smallBuffer),    // The size of the buffer.  
               &cbLeft);               // How much data we can get.  
         }  
         while ( retcode2 == SQL_SUCCESS_WITH_INFO );  
      }  
   }   
  
   return TRUE;  
}  

Voir aussi

Paramètres des instructions