Abrufen von Ausgabeparametern mithilfe von SQLGetData
Vor ODBC 3.8 konnte eine Anwendung nur die Ausgabeparameter einer Abfrage mit einem gebundenen Ausgabepuffer abrufen. Es ist jedoch schwierig, einen sehr großen Puffer zuzuweisen, wenn die Größe des Parameterwerts sehr groß ist (z. B. ein großes Bild). ODBC 3.8 bietet eine neue Möglichkeit zum Abrufen von Ausgabeparametern in Teilen. Eine Anwendung kann jetzt SQLGetData mit einem kleinen Puffer mehrmals aufrufen, um einen großen Parameterwert abzurufen. Dies ähnelt dem Abrufen großer Spaltendaten.
Zum Binden eines Ausgabeparameters oder eines Eingabe-/Ausgabeparameters, der in Teilen abgerufen werden soll, rufen Sie SQLBindParameter auf, wobei das InputOutputType-Argument auf SQL_PARAM_OUTPUT_STREAM oder SQL_PARAM_INPUT_OUTPUT_STREAM festgelegt ist. Mit SQL_PARAM_INPUT_OUTPUT_STREAM kann eine Anwendung SQLPutData verwenden, um Daten in den Parameter einzugeben, und dann SQLGetData zum Abrufen des Ausgabeparameters verwenden. Die Eingabedaten müssen sich im DaE-Formular (Data-at-Execution) befinden, wobei SQLPutData verwendet wird, anstatt sie an einen vorallocatierten Puffer zu binden.
Dieses Feature kann von ODBC 3.8-Anwendungen verwendet oder odbc 3.x- und ODBC 2.x-Anwendungen neu kompiliert werden, und diese Anwendungen müssen über einen ODBC 3.8-Treiber verfügen, der das Abrufen von Ausgabeparametern mithilfe von SQLGetData und ODBC 3.8-Treiber-Manager unterstützt. Informationen zum Aktivieren einer älteren Anwendung für die Verwendung neuer ODBC-Features finden Sie in der Kompatibilitätsmatrix.
Beispiel für die Verwendung
Erwägen Sie beispielsweise das Ausführen einer gespeicherten Prozedur { CALL sp_f(?,?)}, wobei beide Parameter als SQL_PARAM_OUTPUT_STREAM gebunden sind und die gespeicherte Prozedur kein Resultset zurückgibt (später in diesem Thema finden Sie ein komplexeres Szenario):
Rufen Sie für jeden Parameter SQLBindParameter mit InputOutputType-Wert auf SQL_PARAM_OUTPUT_STREAM und ParameterValuePtr auf ein Token fest, z. B. eine Parameternummer, einen Zeiger auf Daten oder einen Zeiger auf eine Struktur, die von der Anwendung zum Binden von Eingabeparametern verwendet wird. In diesem Beispiel wird der Parameter als Token verwendet.
Führen Sie die Abfrage mit SQLExecDirect oder SQLExecute aus. SQL_PARAM_DATA_AVAILABLE wird zurückgegeben, was angibt, dass für den Abruf gestreamte Ausgabeparameter verfügbar sind.
Rufen Sie SQLParamData auf, um den Parameter abzurufen, der zum Abrufen verfügbar ist. SQLParamData gibt SQL_PARAM_DATA_AVAILABLE mit dem Token des ersten verfügbaren Parameters zurück, der in SQLBindParameter (Schritt 1) festgelegt ist. Das Token wird im Puffer zurückgegeben, auf den valuePtrPtr verweist.
Rufen Sie SQLGetData mit dem Argument "Col_or_Param_Num " auf den Parameter oder die Ordnungszahl fest, um die Daten des ersten verfügbaren Parameters abzurufen. Wenn SQLGetData SQL_SUCCESS_WITH_INFO und SQLState 01004 (Daten abgeschnitten) zurückgibt und der Typ sowohl auf dem Client als auch auf dem Server variable Länge aufweist, gibt es weitere Daten, die aus dem ersten verfügbaren Parameter abgerufen werden können. Sie können SQLGetData weiterhin aufrufen, bis sie SQL_SUCCESS oder SQL_SUCCESS_WITH_INFO mit einem anderen SQLState zurückgibt.
Wiederholen Sie Schritt 3 und Schritt 4, um den aktuellen Parameter abzurufen.
Rufen Sie SQLParamData erneut auf. Wenn etwas außer SQL_PARAM_DATA_AVAILABLE zurückgegeben wird, werden keine daten mit gestreamten Parametern abgerufen, und der Rückgabecode ist der Rückgabecode der nächsten ausgeführten Anweisung.
Rufen Sie SQLMoreResults auf, um den nächsten Satz von Parametern zu verarbeiten, bis sie SQL_NO_DATA zurückgibt. SQLMoreResults gibt in diesem Beispiel SQL_NO_DATA zurück, wenn das Anweisungsattribut SQL_ATTR_PARAMSET_SIZE auf 1 festgelegt wurde. Andernfalls gibt SQLMoreResults SQL_PARAM_DATA_AVAILABLE zurück, um anzugeben, dass streamte Ausgabeparameter für den nächsten abzurufenden Parametersatz verfügbar sind.
Ähnlich wie bei einem DAE-Eingabeparameter kann das token, das im Argument ParameterValuePtr in SQLBindParameter (Schritt 1) verwendet wird, ein Zeiger sein, der auf eine Anwendungsdatenstruktur verweist, die bei Bedarf die Ordnungszahl des Parameters und weitere anwendungsspezifische Informationen enthält.
Die Reihenfolge der zurückgegebenen gestreamten Ausgabe- oder Eingabe-/Ausgabeparameter ist treiberspezifisch und ist möglicherweise nicht immer mit der in der Abfrage angegebenen Reihenfolge identisch.
Wenn die Anwendung SQLGetData in Schritt 4 nicht aufruft, wird der Parameterwert nicht Karte ed. Wenn die Anwendung SQLParamData aufruft, bevor der gesamte Parameterwert von SQLGetData gelesen wurde, wird der re Standard der des Werts nicht Karte ed, und die Anwendung kann den nächsten Parameter verarbeiten.
Wenn die Anwendung SQLMoreResults aufruft, bevor alle gestreamten Ausgabeparameter verarbeitet werden (SQLParamData gibt weiterhin SQL_PARAM_DATA_AVAILABLE zurück), werden alle Erneut Standard ingparameter nicht Karte. Wenn die Anwendung SQLMoreResults aufruft, bevor der gesamte Parameterwert von SQLGetData gelesen wurde, werden der wertre Standard Derder des Werts und alle parameter erneut Standard werden dis Karte ed, und die Anwendung kann den nächsten Parametersatz weiter verarbeiten.
Beachten Sie, dass eine Anwendung den C-Datentyp sowohl in SQLBindParameter als auch in SQLGetData angeben kann. Der mit SQLGetData angegebene C-Datentyp überschreibt den in SQLBindParameter angegebenen C-Datentyp, es sei denn, der in SQLGetData angegebene C-Datentyp ist SQL_APD_TYPE.
Obwohl ein streamter Ausgabeparameter nützlicher ist, wenn der Datentyp des Ausgabeparameters vom Typ BLOB ist, kann diese Funktionalität auch mit jedem beliebigen Datentyp verwendet werden. Die datentypen, die von streamten Ausgabeparametern unterstützt werden, werden im Treiber angegeben.
Wenn SQL_PARAM_INPUT_OUTPUT_STREAM Parameter verarbeitet werden sollen, gibt SQLExecute oder SQLExecDirect zuerst SQL_NEED_DATA zurück. Eine Anwendung kann SQLParamData und SQLPutData aufrufen, um DAE-Parameterdaten zu senden. Wenn alle DAE-Eingabeparameter verarbeitet werden, gibt SQLParamData SQL_PARAM_DATA_AVAILABLE zurück, um anzugeben, dass gestreamte Ausgabeparameter verfügbar sind.
Wenn gestreamte Ausgabeparameter und gebundene Ausgabeparameter verarbeitet werden sollen, bestimmt der Treiber die Reihenfolge für die Verarbeitung von Ausgabeparametern. Wenn also ein Ausgabeparameter an einen Puffer gebunden ist (der SQLBindParameter-Parameter InputOutputType auf SQL_PARAM_INPUT_OUTPUT oder SQL_PARAM_OUTPUT festgelegt ist), wird der Puffer möglicherweise erst aufgefüllt, wenn SQLParamData SQL_SUCCESS oder SQL_SUCCESS_WITH_INFO zurückgibt. Eine Anwendung sollte einen gebundenen Puffer nur lesen, nachdem SQLParamData SQL_SUCCESS oder SQL_SUCCESS_WITH_INFO zurückgibt, der nach der Verarbeitung aller gestreamten Ausgabeparameter liegt.
Die Datenquelle kann zusätzlich zum streamten Ausgabeparameter eine Warnung und ein Resultset zurückgeben. Im Allgemeinen werden Warnungen und Resultsets getrennt von einem gestreamten Ausgabeparameter verarbeitet, indem SQLMoreResults aufgerufen wird. Prozesswarnungen und das Resultset vor der Verarbeitung des gestreamten Ausgabeparameters.
In der folgenden Tabelle werden verschiedene Szenarien eines einzelnen Befehls beschrieben, der an den Server gesendet wird und wie die Anwendung funktionieren soll.
Szenario | Rückgabewert von SQLExecute oder SQLExecDirect | Nächste Schritte |
---|---|---|
Daten enthalten nur gestreamte Ausgabeparameter | SQL_PARAM_DATA_AVAILABLE | Verwenden Sie SQLParamData und SQLGetData, um gestreamte Ausgabeparameter abzurufen. |
Daten umfassen ein Resultset und streamte Ausgabeparameter. | SQL_SUCCESS | Rufen Sie das Resultset mit SQLBindCol und SQLGetData ab. Rufen Sie SQLMoreResults auf, um mit der Verarbeitung von gestreamten Ausgabeparametern zu beginnen. Es sollte SQL_PARAM_DATA_AVAILABLE zurückgeben. Verwenden Sie SQLParamData und SQLGetData, um gestreamte Ausgabeparameter abzurufen. |
Daten enthalten eine Warnmeldung und streamte Ausgabeparameter. | SQL_SUCCESS_WITH_INFO | Verwenden Sie SQLGetDiagRec und SQLGetDiagField , um Warnmeldungen zu verarbeiten. Rufen Sie SQLMoreResults auf, um mit der Verarbeitung von gestreamten Ausgabeparametern zu beginnen. Es sollte SQL_PARAM_DATA_AVAILABLE zurückgeben. Verwenden Sie SQLParamData und SQLGetData, um gestreamte Ausgabeparameter abzurufen. |
Daten enthalten eine Warnmeldung, ein Resultset und eine gestreamte Ausgabeparameter. | SQL_SUCCESS_WITH_INFO | Verwenden Sie SQLGetDiagRec und SQLGetDiagField , um Warnmeldungen zu verarbeiten. Rufen Sie dann SQLMoreResults auf, um mit der Verarbeitung des Resultsets zu beginnen. Dient zum Abrufen eines Resultsets mit SQLBindCol und SQLGetData. Rufen Sie SQLMoreResults auf, um mit der Verarbeitung von gestreamten Ausgabeparametern zu beginnen. SQLMoreResults sollte SQL_PARAM_DATA_AVAILABLE zurückgeben. Verwenden Sie SQLParamData und SQLGetData, um gestreamte Ausgabeparameter abzurufen. |
Abfrage mit DAE-Eingabeparametern, z. B. einem DAE-Parameter (Streamed Input/Output) | SQL-NEED_DATA | Rufen Sie SQLParamData und SQLPutData auf, um DAE-Eingabeparameterdaten zu senden. Nachdem alle DAE-Eingabeparameter verarbeitet wurden, kann SQLParamData jeden Rückgabecode zurückgeben, den SQLExecute und SQLExecDirect zurückgeben können. Die Fälle in dieser Tabelle können dann angewendet werden. Wenn der Rückgabecode SQL_PARAM_DATA_AVAILABLE ist, sind streamte Ausgabeparameter verfügbar. Eine Anwendung muss SQLParamData erneut aufrufen, um das Token für den gestreamten Ausgabeparameter abzurufen, wie in der ersten Zeile dieser Tabelle beschrieben. Wenn der Rückgabecode SQL_SUCCESS ist, gibt es entweder ein Resultset, das verarbeitet werden soll, oder die Verarbeitung ist abgeschlossen. Wenn der Rückgabecode SQL_SUCCESS_WITH_INFO ist, werden Warnmeldungen verarbeitet. |
Nachdem SQLExecute, SQLExecDirect oder SQLMoreResults SQL_PARAM_DATA_AVAILABLE zurückgegeben hat, führt ein Funktionssequenzfehler dazu, wenn eine Anwendung eine Funktion aufruft, die sich nicht in der folgenden Liste befindet:
SQLAllocHandle / SQLAllocHandleStd
SQLDataSources / SQLDrivers
SQLGetInfo / SQLGetFunctions
SQLGet Verbinden Attr / SQLGetEnvAttr / SQLGetDescField / SQLGetDescRec
SQLNumParams
SQLDescribeParam
SQLNativeSql
SQLParamData
SQLMoreResults
SQLGetDiagField / SQLGetDiagRec
SQLCancel
SQLCancelHandle (mit Anweisungshandle )
SQLFreeStmt (mit Option = SQL_CLOSE, SQL_DROP oder SQL_UNBIND)
SQLCloseCursor
SQLDisconnect
SQLFreeHandle (mit HandleType = SQL_HANDLE_STMT)
SQLGetStmtAttr
Anwendungen können weiterhin SQLSetDescField oder SQLSetDescRec verwenden, um die Bindungsinformationen festzulegen. Die Feldzuordnung wird nicht geändert. Felder im Deskriptor geben jedoch möglicherweise neue Werte zurück. Beispielsweise kann SQL_DESC_PARAMETER_TYPE SQL_PARAM_INPUT_OUTPUT_STREAM oder SQL_PARAM_OUTPUT_STREAM zurückgeben.
Verwendungsszenario: Abrufen eines Bilds in Teilen aus einem Resultset
SQLGetData kann verwendet werden, um Daten in Teilen abzurufen, wenn eine gespeicherte Prozedur ein Resultset zurückgibt, das eine Zeile mit Metadaten zu einem Bild enthält und das Bild in einem großen Ausgabeparameter zurückgegeben wird.
// 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;
}
Verwendungsszenario: Senden und Empfangen eines großen Objekts als Streamed Input/Output-Parameter
SQLGetData kann verwendet werden, um Daten in Teilen abzurufen und zu senden, wenn eine gespeicherte Prozedur ein großes Objekt als Eingabe-/Ausgabeparameter übergibt, wobei der Wert in und aus der Datenbank gestreamt wird. Sie müssen nicht alle Daten im Arbeitsspeicher speichern.
// 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;
}