Dela via


Hämtar utdataparametrar med SQLGetData

Före ODBC 3.8 kunde ett program bara hämta utdataparametrarna för en fråga med en bunden utdatabuffert. Det är dock svårt att allokera en mycket stor buffert när storleken på parametervärdet är mycket stort (till exempel en stor bild). ODBC 3.8 introducerar ett nytt sätt att hämta utdataparametrar i delar. Ett program kan nu anropa SQLGetData med en liten buffert flera gånger för att hämta ett stort parametervärde. Detta liknar hämtning av stora kolumndata.

Om du vill binda en utdataparameter eller indata-/utdataparameter som ska hämtas i delar anropar du SQLBindParameter med argumentet InputOutputType inställt på SQL_PARAM_OUTPUT_STREAM eller SQL_PARAM_INPUT_OUTPUT_STREAM. Med SQL_PARAM_INPUT_OUTPUT_STREAM kan ett program använda SQLPutData för att mata in data i parametern och sedan använda SQLGetData för att hämta utdataparametern. Indata måste vara i dae-formatet (data-at-execution) med hjälp av SQLPutData i stället för att binda dem till en förallokerad buffert.

Den här funktionen kan användas av ODBC 3.8-program eller omkompilerade ODBC 3.x- och ODBC 2.x-program, och dessa program måste ha en ODBC 3.8-drivrutin som stöder hämtning av utdataparametrar med SQLGetData och ODBC 3.8 Driver Manager. Information om hur du aktiverar ett äldre program för att använda nya ODBC-funktioner finns i Kompatibilitetsmatris.

Användningsexempel

Överväg till exempel att köra en lagrad procedur, {CALL sp_f(?,?)}, där båda parametrarna är bundna som SQL_PARAM_OUTPUT_STREAM, och den lagrade proceduren returnerar ingen resultatuppsättning (senare i det här avsnittet hittar du ett mer komplext scenario):

  1. För varje parameter anropar du SQLBindParameter med InputOutputType inställt på SQL_PARAM_OUTPUT_STREAM och ParameterValuePtr inställt på en token, till exempel ett parameternummer, en pekare till data eller en pekare till en struktur som programmet använder för att binda indataparametrar. I det här exemplet används parameterordinalen som token.

  2. Kör frågan med SQLExecDirect eller SQLExecute. SQL_PARAM_DATA_AVAILABLE returneras, vilket anger att det finns strömmade utdataparametrar tillgängliga för hämtning.

  3. Anropa SQLParamData för att hämta parametern som är tillgänglig för hämtning. SQLParamData returnerar SQL_PARAM_DATA_AVAILABLE med token för den första tillgängliga parametern, som anges i SQLBindParameter (steg 1). Token returneras i bufferten som ValuePtrPtr pekar på.

  4. Anropa SQLGetData med argumentet Col_or_Param_Num inställt på parameterns ordningstal för att hämta data för den första tillgängliga parametern. Om SQLGetData returnerar SQL_SUCCESS_WITH_INFO och SQLState 01004 (trunkerade data) och typen är variabel längd på både klienten och servern finns det mer data att hämta från den första tillgängliga parametern. Du kan fortsätta att anropa SQLGetData tills det returnerar SQL_SUCCESS eller SQL_SUCCESS_WITH_INFO med en annan SQLState.

  5. Upprepa steg 3 och steg 4 för att hämta den aktuella parametern.

  6. Anropa SQLParamData igen. Om det returnerar något annat än SQL_PARAM_DATA_AVAILABLE finns det inga fler strömmade parameterdata att hämta, och returkoden blir returkoden för nästa instruktion som körs.

  7. Anropa SQLMoreResults för att bearbeta nästa uppsättning parametrar tills den returnerar SQL_NO_DATA. SQLMoreResults returnerar SQL_NO_DATA i det här exemplet om instruktionsattributet SQL_ATTR_PARAMSET_SIZE har angetts till 1. Annars returnerar SQLMoreResults SQL_PARAM_DATA_AVAILABLE för att indikera att det finns strömmade utdataparametrar tillgängliga för nästa uppsättning parametrar som ska hämtas.

Precis som en DAE-indataparameter kan token som används i argumentet ParameterValuePtr i SQLBindParameter (steg 1) vara en pekare som pekar på en programdatastruktur som innehåller parameterns ordningstal och mer programspecifik information om det behövs.

Ordningen på de returnerade strömmade utdata- eller indata-/utdataparametrarna är drivrutinsspecifika och kanske inte alltid samma som den ordning som anges i frågan.

Om programmet inte anropar SQLGetData i steg 4 ignoreras parametervärdet. Om programmet anropar SQLParamData innan alla parametervärden har lästs av SQLGetData ignoreras resten av värdet och programmet kan bearbeta nästa parameter.

Om programmet anropar SQLMoreResults innan alla strömmade utdataparametrar bearbetas (SQLParamData returnerar fortfarande SQL_PARAM_DATA_AVAILABLE) ignoreras alla återstående parametrar. Om programmet anropar SQLMoreResults innan alla parametervärden har lästs av SQLGetData ignoreras resten av värdet och alla återstående parametrar och programmet kan fortsätta att bearbeta nästa parameteruppsättning.

Observera att ett program kan ange C-datatypen i både SQLBindParameter och SQLGetData. C-datatypen som anges med SQLGetData åsidosätter den C-datatyp som anges i SQLBindParameter, såvida inte den C-datatyp som anges i SQLGetData SQL_APD_TYPE.

Även om en strömmad utdataparameter är mer användbar när datatypen för utdataparametern är av typen BLOB, kan den här funktionen också användas med valfri datatyp. De datatyper som stöds av strömmade utdataparametrar anges i drivrutinen.

Om det finns SQL_PARAM_INPUT_OUTPUT_STREAM parametrar som ska bearbetas returnerar SQLExecute eller SQLExecDirect SQL_NEED_DATA först. Ett program kan anropa SQLParamData och SQLPutData för att skicka DAE-parameterdata. När alla DAE-indataparametrar bearbetas returnerar SQLParamData SQL_PARAM_DATA_AVAILABLE för att indikera att strömmade utdataparametrar är tillgängliga.

När det finns strömmade utdataparametrar och bundna utdataparametrar som ska bearbetas avgör drivrutinen ordningen för bearbetning av utdataparametrar. Om en utdataparameter är bunden till en buffert ( SQLBindParameter-parameternInputOutputType är inställd på SQL_PARAM_INPUT_OUTPUT eller SQL_PARAM_OUTPUT) kanske bufferten inte fylls i förrän SQLParamData returnerar SQL_SUCCESS eller SQL_SUCCESS_WITH_INFO. Ett program bör bara läsa en bunden buffert när SQLParamData returnerar SQL_SUCCESS eller SQL_SUCCESS_WITH_INFO som när alla strömmade utdataparametrar har bearbetats.

Datakällan kan returnera en varning och resultatuppsättning utöver den strömmade utdataparametern. I allmänhet bearbetas varningar och resultatuppsättningar separat från en strömmad utdataparameter genom att anropa SQLMoreResults. Bearbeta varningar och resultatuppsättningen innan du bearbetar den strömmade utdataparametern.

I följande tabell beskrivs olika scenarier för ett enda kommando som skickas till servern och hur programmet ska fungera.

Scenario Returnera värde från SQLExecute eller SQLExecDirect Vad du ska göra härnäst
Data innehåller endast strömmade utdataparametrar SQL_PARAM_DATA_AVAILABLE Använd SQLParamData och SQLGetData för att hämta strömmade utdataparametrar.
Data innehåller en resultatuppsättning och strömmade utdataparametrar SQL_SUCCESS Hämta resultatuppsättningen med SQLBindCol och SQLGetData.

Anropa SQLMoreResults för att börja bearbeta strömmade utdataparametrar. Den bör returnera SQL_PARAM_DATA_AVAILABLE.

Använd SQLParamData och SQLGetData för att hämta strömmade utdataparametrar.
Data innehåller ett varningsmeddelande och strömmade utdataparametrar SQL_SUCCESS_WITH_INFO Använd SQLGetDiagRec och SQLGetDiagField för att bearbeta varningsmeddelanden.

Anropa SQLMoreResults för att börja bearbeta strömmade utdataparametrar. Den bör returnera SQL_PARAM_DATA_AVAILABLE.

Använd SQLParamData och SQLGetData för att hämta strömmade utdataparametrar.
Data innehåller ett varningsmeddelande, resultatuppsättning och strömmade utdataparametrar SQL_SUCCESS_WITH_INFO Använd SQLGetDiagRec och SQLGetDiagField för att bearbeta varningsmeddelanden. Anropa sedan SQLMoreResults för att börja bearbeta resultatuppsättningen.

Hämta en resultatuppsättning med SQLBindCol och SQLGetData.

Anropa SQLMoreResults för att börja bearbeta strömmade utdataparametrar. SQLMoreResults bör returnera SQL_PARAM_DATA_AVAILABLE.

Använd SQLParamData och SQLGetData för att hämta strömmade utdataparametrar.
Fråga med inparametrar för DAE, till exempel en parameter för strömmat in- och utdata (DAE) SQL BEHÖVER_DATA Anropa SQLParamData och SQLPutData för att skicka DAE-indataparameterdata.

När alla DAE-indataparametrar har bearbetats kan SQLParamData returnera valfri returkod som SQLExecute och SQLExecDirect kan returnera. Fallen i den här tabellen kan sedan tillämpas.

Om returkoden är SQL_PARAM_DATA_AVAILABLE är strömmade utdataparametrar tillgängliga. Ett program måste anropa SQLParamData igen för att hämta token för den strömmade utdataparametern, enligt beskrivningen i den första raden i den här tabellen.

Om returkoden är SQL_SUCCESS finns det antingen en resultatuppsättning att bearbeta eller så är bearbetningen klar.

Om returkoden är SQL_SUCCESS_WITH_INFO finns det varningsmeddelanden att bearbeta.

När SQLExecute, SQLExecDirect eller SQLMoreResults returnerar SQL_PARAM_DATA_AVAILABLE resulterar ett funktionssekvensfel om ett program anropar en funktion som inte finns i följande lista:

  • SQLAllocHandle / SQLAllocHandleStd

  • SQLDataSources / SQLDrivers

  • SQLGetInfo / SQLGetFunctions

  • SQLGetConnectAttr / SQLGetEnvAttr / SQLGetDescField / SQLGetDescRec

  • SQLNumParams

  • SQLDescribeParam

  • SQLNativeSql

  • SQLParamData

  • SQLMoreResults

  • SQLGetDiagField / SQLGetDiagRec

  • SQLCancel

  • SQLCancelHandle (med uttryckshanterare)

  • SQLFreeStmt (med Alternativet = SQL_CLOSE, SQL_DROP eller SQL_UNBIND)

  • SQLCloseCursor

  • SQLDisconnect

  • SQLFreeHandle (med HandleType = SQL_HANDLE_STMT)

  • SQLGetStmtAttr

Program kan fortfarande använda SQLSetDescField eller SQLSetDescRec för att ange bindningsinformationen. Fältmappning ändras inte. Fält i beskrivningen kan dock returnera nya värden. SQL_DESC_PARAMETER_TYPE kan till exempel returnera SQL_PARAM_INPUT_OUTPUT_STREAM eller SQL_PARAM_OUTPUT_STREAM.

Användningsscenario: Hämta en bild i delar från en resultatuppsättning

SQLGetData kan användas för att hämta data i delar när en lagrad procedur returnerar en resultatuppsättning som innehåller en rad metadata om en bild och bilden returneras i en stor utdataparameter.

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

Användningsscenario: Skicka och ta emot ett stort objekt som en strömmad indata-/utdataparameter

SQLGetData kan användas för att hämta och skicka data i delar när en lagrad procedur skickar ett stort objekt som en indata-/utdataparameter och strömmar värdet till och från databasen. Du behöver inte lagra alla data i minnet.

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

Se även

Uttalandeparametrar