Udostępnij przez


Pobieranie parametrów wyjściowych przy użyciu polecenia SQLGetData

Przed ODBC 3.8 aplikacja mogła pobrać tylko parametry wyjściowe zapytania z powiązanym buforem wyjściowym. Trudno jednak przydzielić bardzo duży bufor, gdy rozmiar wartości parametru jest bardzo duży (na przykład duży obraz). ODBC 3.8 wprowadza nowy sposób pobierania parametrów wyjściowych w segmentach. Aplikacja może teraz wywołać funkcję SQLGetData z małym buforem wielokrotnie, aby pobrać dużą wartość parametru. Jest to podobne do pobierania danych z dużych kolumn.

Aby powiązać parametr wyjściowy lub parametr wejściowy/wyjściowy do pobierania w częściach, wywołaj SQLBindParameter z argumentem InputOutputType ustawionym na SQL_PARAM_OUTPUT_STREAM lub SQL_PARAM_INPUT_OUTPUT_STREAM. W przypadku SQL_PARAM_INPUT_OUTPUT_STREAM aplikacja może używać sqlPutData do wprowadzania danych do parametru, a następnie pobierać parametr wyjściowy za pomocą funkcji SQLGetData . Dane wejściowe muszą znajdować się w formacie data-at-execution (DAE) przy użyciu SQLPutData zamiast wiązania ich ze wstępnie alokowanym buforem.

Ta funkcja może być używana przez aplikacje ODBC 3.8 lub ponownie skompilowane aplikacje ODBC 3.x i ODBC 2.x, a te aplikacje muszą mieć sterownik ODBC 3.8, który obsługuje pobieranie parametrów wyjściowych przy użyciu sqlGetData i ODBC 3.8 Driver Manager. Aby uzyskać informacje na temat włączania starszej aplikacji do korzystania z nowych funkcji ODBC, zobacz Macierz zgodności.

Przykład użycia

Rozważ na przykład wykonanie procedury składowanej {CALL sp_f(?,?)}, gdzie oba parametry są powiązane jako SQL_PARAM_OUTPUT_STREAM, a procedura składowana nie zwraca żadnego zestawu wyników (w dalszej części tego tematu znajdziesz bardziej złożony scenariusz):

  1. Dla każdego parametru wywołaj parametr SQLBindParameter z parametrem InputOutputType ustawionym na SQL_PARAM_OUTPUT_STREAM i ParametrValuePtr ustawionym na token, taki jak numer parametru, wskaźnik do danych lub wskaźnik do struktury używanej przez aplikację do powiązania parametrów wejściowych. W tym przykładzie użyto parametru ordinalnego jako tokenu.

  2. Wykonaj zapytanie za pomocą polecenia SQLExecDirect lub SQLExecute. SQL_PARAM_DATA_AVAILABLE zostaną zwrócone, co wskazuje, że do pobierania są dostępne parametry wyjściowe przesyłane strumieniowo.

  3. Wywołaj metodę SQLParamData , aby uzyskać parametr dostępny do pobrania. Funkcja SQLParamData zwróci SQL_PARAM_DATA_AVAILABLE z tokenem pierwszego dostępnego parametru, który jest ustawiony w parametrze SQLBindParameter (krok 1). Token jest zwracany w buforze, na który wskazuje ValuePtrPtr.

  4. Wywołaj metodę SQLGetData za pomocą argumentu Col_or_Param_Num ustawionego na porządkowy parametr, aby pobrać dane pierwszego dostępnego parametru. Jeśli SQLGetData zwraca SQL_SUCCESS_WITH_INFO i SQLState 01004 (dane obcięte), i jeśli typ ma zmienną długość zarówno po stronie klienta, jak i serwera, do pobrania jest więcej danych z pierwszego dostępnego parametru. Możesz nadal wywoływać funkcję SQLGetData , dopóki nie zwróci SQL_SUCCESS lub SQL_SUCCESS_WITH_INFO z innym stanem SQLState.

  5. Powtórz krok 3 i krok 4, aby pobrać bieżący parametr.

  6. Ponownie wywołaj metodę SQLParamData . Jeśli zwraca wszystkie elementy z wyjątkiem SQL_PARAM_DATA_AVAILABLE, nie ma więcej przesyłanych strumieniowo danych parametrów do pobrania, a kod zwracany będzie kodem zwracanym kolejnej instrukcji, która jest wykonywana.

  7. Wywołaj metodę SQLMoreResults , aby przetworzyć następny zestaw parametrów, dopóki nie zwróci SQL_NO_DATA. Funkcja SQLMoreResults zwróci SQL_NO_DATA w tym przykładzie, jeśli atrybut instrukcji SQL_ATTR_PARAMSET_SIZE został ustawiony na 1. W przeciwnym razie funkcja SQLMoreResults zwróci SQL_PARAM_DATA_AVAILABLE, aby wskazać, że są dostępne parametry wyjściowe przesyłane strumieniowo dla następnego zestawu parametrów do pobrania.

Podobnie jak w przypadku parametru wejściowego DAE, token używany w argumencie ParameterValuePtr w funkcji SQLBindParameter (krok 1) może być wskaźnikiem na strukturę danych aplikacji, która zawiera numerację parametru i, w razie potrzeby, bardziej specyficzne dla aplikacji informacje.

Kolejność zwracanych strumieniowych parametrów wyjściowych lub wejściowych/wyjściowych jest specyficzna dla sterownika i może nie zawsze być taka sama jak kolejność określona w zapytaniu.

Jeśli aplikacja nie wywołuje metody SQLGetData w kroku 4, wartość parametru zostanie odrzucona. Podobnie, jeśli aplikacja wywołuje metodę SQLParamData , zanim wszystkie wartości parametru zostały odczytane przez funkcję SQLGetData, pozostała część wartości zostanie odrzucona, a aplikacja może przetworzyć następny parametr.

Jeśli aplikacja wywołuje metodę SQLMoreResults przed przetworzeniem wszystkich przesyłanych strumieniowo parametrów wyjściowych (funkcja SQLParamData nadal zwraca SQL_PARAM_DATA_AVAILABLE), wszystkie pozostałe parametry zostaną odrzucone. Podobnie, jeśli aplikacja wywołuje element SQLMoreResults przed odczytaniem przez sqlGetData wszystkich wartości parametrów, pozostała część wartości i wszystkie pozostałe parametry zostaną odrzucone, a aplikacja będzie nadal przetwarzać następny zestaw parametrów.

Należy pamiętać, że aplikacja może określić typ danych języka C zarówno w parametrach SQLBindParameter , jak i SQLGetData. Typ danych języka C określony za pomocą parametru SQLGetData zastępuje typ danych C określony w parametrze SQLBindParameter, chyba że typ danych języka C określony w danych SQLGetData jest SQL_APD_TYPE.

Chociaż przesyłany strumieniowo parametr wyjściowy jest bardziej przydatny, gdy typ danych parametru wyjściowego jest typu BLOB, ta funkcja może być również używana z dowolnym typem danych. Typy danych obsługiwane przez parametry przesyłane strumieniowo danych wyjściowych są określone w sterowniku.

Jeśli istnieją parametry SQL_PARAM_INPUT_OUTPUT_STREAM do przetworzenia, procedury SQLExecute lub SQLExecDirect zwrócą najpierw SQL_NEED_DATA. Aplikacja może wywoływać metody SQLParamData i SQLPutData w celu wysyłania danych parametrów języka DAE. Po przetworzeniu wszystkich parametrów wejściowych DAE funkcja SQLParamData zwraca SQL_PARAM_DATA_AVAILABLE, aby wskazać, że dostępne są strumieniowane parametry wyjściowe.

Gdy są przesyłane strumieniowo parametry wyjściowe i powiązane parametry wyjściowe do przetworzenia, sterownik określa kolejność przetwarzania parametrów wyjściowych. Dlatego jeśli parametr wyjściowy jest powiązany z buforem (parametr SQLBindParameterInputOutputType jest ustawiony na wartość SQL_PARAM_INPUT_OUTPUT lub SQL_PARAM_OUTPUT), bufor może nie zostać wypełniony, dopóki funkcja SQLParamData nie zwróci SQL_SUCCESS lub SQL_SUCCESS_WITH_INFO. Aplikacja powinna odczytywać powiązany bufor tylko wtedy, gdy funkcja SQLParamData zwróci SQL_SUCCESS lub SQL_SUCCESS_WITH_INFO, co ma miejsce po przetworzeniu wszystkich przesyłanych strumieniowo parametrów wyjściowych.

Źródło danych może zwrócić ostrzeżenie i zestaw wyników oprócz strumieniowego parametru wyjściowego. Ogólnie rzecz biorąc, ostrzeżenia i zestawy wyników są przetwarzane oddzielnie od przesyłanego strumieniowo parametru wyjściowego przez wywołanie metody SQLMoreResults. Ostrzeżenia dotyczące przetwarzania i zestaw wyników przed przetworzeniem przesyłanego strumieniowo parametru wyjściowego.

W poniższej tabeli opisano różne scenariusze pojedynczego polecenia wysyłanego na serwer oraz sposób działania aplikacji.

Scenario Zwracana wartość z sqlExecute lub SQLExecDirect Co zrobić dalej
Dane wyjściowe obejmują tylko parametry przesyłane strumieniowo SQL_PARAM_DATA_AVAILABLE Użyj SQLParamData i SQLGetData, aby pobrać strumieniowane parametry wyjściowe.
Dane zawierają zestaw wyników i przesyłane strumieniowo parametry wyjściowe SQL_SUCCESS Pobierz zestaw wyników przy użyciu elementów SQLBindCol i SQLGetData.

Wywołaj metodę SQLMoreResults , aby rozpocząć przetwarzanie strumieniowych parametrów wyjściowych. Powinien zwrócić SQL_PARAM_DATA_AVAILABLE.

Użyj SQLParamData i SQLGetData, aby pobrać przesyłane strumieniowo parametry wyjściowe.
Dane zawierają komunikat ostrzegawczy i przesyłane strumieniowo parametry wyjściowe SQL_SUCCESS_WITH_INFO Użyj funkcji SQLGetDiagRec i SQLGetDiagField do przetwarzania komunikatów ostrzegawczych.

Wywołaj metodę SQLMoreResults , aby rozpocząć przetwarzanie strumieniowych parametrów wyjściowych. Powinien zwrócić SQL_PARAM_DATA_AVAILABLE.

Użyj funkcji SQLParamData i SQLGetData, aby pobrać przesyłane strumieniowo parametry wyjściowe.
Dane zawierają komunikat ostrzegawczy, zestaw wyników i parametry wyjściowe przesyłane strumieniowo SQL_SUCCESS_WITH_INFO Użyj SQLGetDiagRec i SQLGetDiagField do przetwarzania komunikatów ostrzegawczych. Następnie wywołaj metodę SQLMoreResults , aby rozpocząć przetwarzanie zestawu wyników.

Pobieranie zestawu wyników przy użyciu elementów SQLBindCol i SQLGetData.

Wywołaj metodę SQLMoreResults , aby rozpocząć przetwarzanie strumieniowych parametrów wyjściowych. SqlMoreResults powinien zwrócić SQL_PARAM_DATA_AVAILABLE.

Użyj SQLParamData i SQLGetData, aby pobrać przesyłane strumieniowo parametry wyjściowe.
Zapytanie z parametrami wejściowymi DAE, na przykład parametrem strumieniowym wejściowym/wyjściowym (DAE) SQL NEED_DATA Wywołaj metody SQLParamData i SQLPutData , aby wysłać dane parametrów wejściowych języka DAE.

Po przetworzeniu wszystkich parametrów wejściowych DAE funkcja SQLParamData może zwrócić dowolny kod zwracany przez SQLExecute i SQLExecDirect. Przypadki w tej tabeli można następnie zastosować.

Jeśli kod zwracany jest SQL_PARAM_DATA_AVAILABLE, dostępne są przesyłane strumieniowo parametry wyjściowe. Aplikacja musi ponownie wywołać metodę SQLParamData , aby pobrać token dla przesyłanego strumieniowo parametru wyjściowego, zgodnie z opisem w pierwszym wierszu tej tabeli.

Jeśli kod zwracany jest SQL_SUCCESS, istnieje zestaw wyników do przetworzenia lub przetwarzanie zostało zakończone.

Jeśli kod powrotny jest SQL_SUCCESS_WITH_INFO, istnieją komunikaty ostrzegawcze do przetworzenia.

Gdy funkcja SQLExecute, SQLExecDirect lub SQLMoreResults zwróci SQL_PARAM_DATA_AVAILABLE, błąd sekwencji funkcji spowoduje, że aplikacja wywołuje funkcję, która nie znajduje się na poniższej liście:

  • SQLAllocHandle / SQLAllocHandleStd

  • SQLDataSources / SQLDrivers

  • Sqlgetinfo / Sqlgetfunctions

  • SQLGetConnectAttr / SQLGetEnvAttr / SQLGetDescField / SQLGetDescRec

  • SQLNumParams

  • Sqldescribeparam

  • SQLNativeSql

  • Sqlparamdata

  • Sqlmoreresults

  • Sqlgetdiagfield / Sqlgetdiagrec

  • Sqlcancel

  • SQLCancelHandle (z obsługą instrukcji)

  • SQLFreeStmt (z opcją = SQL_CLOSE, SQL_DROP lub SQL_UNBIND)

  • SQLCloseCursor

  • SQLDisconnect

  • SQLFreeHandle (with HandleType = SQL_HANDLE_STMT)

  • SQLGetStmtAttr

Aplikacje nadal mogą używać sqlSetDescField lub SQLSetDescRec , aby ustawić informacje o powiązaniu. Mapowanie pól nie zostanie zmienione. Jednak pola wewnątrz deskryptora mogą zwracać nowe wartości. Na przykład SQL_DESC_PARAMETER_TYPE może zwrócić SQL_PARAM_INPUT_OUTPUT_STREAM lub SQL_PARAM_OUTPUT_STREAM.

Scenariusz użycia: pobieranie obrazu w częściach z zestawu wyników

Funkcja SQLGetData może służyć do pobierania danych w częściach, gdy procedura składowana zwraca zestaw wyników zawierający jeden wiersz metadanych obrazu, a obraz jest zwracany w dużym parametrze wyjściowym.

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

Scenariusz użycia: wysyłanie i odbieranie dużego obiektu jako strumieniowego parametru wejściowego/wyjściowego

Funkcja SQLGetData może służyć do pobierania i wysyłania danych w częściach, gdy procedura składowana przekazuje duży obiekt jako parametr wejściowy/wyjściowy, przesyłając strumieniowo wartość do i z bazy danych. Nie trzeba przechowywać wszystkich danych w pamięci.

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

Zobacz też

Parametry wyrażenia