Freigeben über


Abrufen von Long-Daten

DBMSs definieren lange Daten als beliebige Zeichen oder Binärdaten über eine bestimmte Größe, z. B. 255 Zeichen. Diese Daten können klein genug sein, um in einem einzelnen Puffer gespeichert zu werden, z. B. eine Teilbeschreibung von mehreren tausend Zeichen. Es kann jedoch zu lang sein, den Speicher zu speichern, z. B. lange Textdokumente oder Bitmaps. Da solche Daten nicht in einem einzigen Puffer gespeichert werden können, wird sie aus dem Treiber in Teilen mit SQLGetData abgerufen, nachdem die anderen Daten in der Zeile abgerufen wurden.

Hinweis

Eine Anwendung kann tatsächlich jeden Datentyp mit SQLGetData abrufen, nicht nur lange Daten, obwohl nur Zeichen- und Binärdaten in Teilen abgerufen werden können. Wenn die Daten jedoch klein genug sind, um in einen einzelnen Puffer zu passen, gibt es in der Regel keinen Grund, SQLGetData zu verwenden. Es ist viel einfacher, einen Puffer an die Spalte zu binden und den Treiber die Daten im Puffer zurückzugeben.

Um lange Daten aus einer Spalte abzurufen, ruft eine Anwendung zuerst SQLFetchScroll oder SQLFetch auf, um zu einer Zeile zu wechseln und die Daten für gebundene Spalten abzurufen. Die Anwendung ruft dann SQLGetData auf. SQLGetData weist dieselben Argumente wie SQLBindCol auf: ein Anweisungshandle; eine Spaltennummer; den Datentyp C, die Adresse und die Bytelänge einer Anwendungsvariablen sowie die Adresse eines Längen-/Indikatorpuffers. Beide Funktionen weisen dieselben Argumente auf, da sie im Wesentlichen dieselbe Aufgabe ausführen: Beide beschreiben eine Anwendungsvariable für den Treiber und geben an, dass die Daten für eine bestimmte Spalte in dieser Variablen zurückgegeben werden sollen. Die wichtigsten Unterschiede sind, dass SQLGetData aufgerufen wird, nachdem eine Zeile abgerufen wurde (und manchmal als späte Bindung aus diesem Grund bezeichnet wird) und dass die durch SQLGetData angegebene Bindung nur für die Dauer des Aufrufs dauert.

In Bezug auf eine einzelne Spalte verhält sich SQLGetData wie SQLFetch: Sie ruft die Daten für die Spalte ab, konvertiert sie in den Typ der Anwendungsvariable und gibt sie in dieser Variablen zurück. Außerdem wird die Bytelänge der Daten im Längen-/Indikatorpuffer zurückgegeben. Weitere Informationen dazu, wie SQLFetch Daten zurückgibt, finden Sie unter Abrufen einer Datenzeile.

SQLGetData unterscheidet sich von SQLFetch in einer wichtigen Hinsicht. Wenn sie für dieselbe Spalte mehrmals nacheinander aufgerufen wird, gibt jeder Aufruf einen aufeinander folgenden Teil der Daten zurück. Jeder Aufruf mit Ausnahme des letzten Aufrufs gibt SQL_SUCCESS_WITH_INFO und SQLSTATE 01004 zurück (Zeichenfolgendaten, rechts abgeschnitten); der letzte Aufruf gibt SQL_SUCCESS zurück. Dies ist, wie SQLGetData verwendet wird, um lange Daten in Teilen abzurufen. Wenn keine weiteren Daten zurückgegeben werden sollen, gibt SQLGetData SQL_NO_DATA zurück. Die Anwendung ist dafür verantwortlich, die langen Daten zusammenzustellen, was dazu führen kann, dass die Teile der Daten verkettet werden. Jeder Teil ist null-beendet; die Anwendung muss das Nullendpunktzeichen entfernen, wenn die Teile verkettet werden. Das Abrufen von Daten in Teilen kann sowohl für Textmarken mit variabler Länge als auch für andere lange Daten erfolgen. Der im Längen-/Indikatorpuffer zurückgegebene Wert nimmt in jedem Aufruf um die Anzahl der im vorherigen Aufruf zurückgegebenen Bytes ab, obwohl es üblich ist, dass der Treiber die Menge der verfügbaren Daten nicht ermitteln und eine Bytelänge von SQL_NO_TOTAL zurückgeben kann. Beispiel:

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

Es gibt mehrere Einschränkungen bei der Verwendung von SQLGetData. Im Allgemeinen werden spalten, auf die mit SQLGetData zugegriffen wird:

  • Der Zugriff muss in Der Reihenfolge der Erhöhung der Spaltenzahl erfolgen (aufgrund der Art und Weise, wie die Spalten eines Resultsets aus der Datenquelle gelesen werden). Beispielsweise ist es ein Fehler, SQLGetData für Spalte 5 aufzurufen und dann für Spalte 4 aufzurufen.

  • Kann nicht gebunden werden.

  • Muss eine höhere Spaltennummer als die letzte gebundene Spalte aufweisen. Wenn die letzte gebundene Spalte beispielsweise Spalte 3 ist, ist es ein Fehler, SQLGetData für Spalte 2 aufzurufen. Aus diesem Grund sollten Anwendungen sicherstellen, dass lange Datenspalten am Ende der Auswahlliste platziert werden.

  • Kann nicht verwendet werden, wenn SQLFetch oder SQLFetchScroll aufgerufen wurde, um mehrere Zeilen abzurufen. Weitere Informationen finden Sie unter Verwenden von Blockcursorn.

Einige Treiber erzwingen diese Einschränkungen nicht. Interoperable Anwendungen sollten entweder davon ausgehen, dass sie vorhanden sind, oder bestimmen, welche Einschränkungen nicht durch Aufrufen von SQLGetInfo mit der option SQL_GETDATA_EXTENSIONS erzwungen werden.

Wenn die Anwendung nicht alle Daten in einer Zeichen- oder Binärdatenspalte benötigt, kann sie den Netzwerkdatenverkehr in DBMS-basierten Treibern reduzieren, indem sie das attribut SQL_ATTR_MAX_LENGTH-Anweisung festlegen, bevor die Anweisung ausgeführt wird. Dadurch wird die Anzahl der Bytes von Daten eingeschränkt, die für ein beliebiges Zeichen oder eine binäre Spalte zurückgegeben werden. Angenommen, eine Spalte enthält lange Textdokumente. Eine Anwendung, die die Tabelle mit dieser Spalte durchsucht, muss möglicherweise nur die erste Seite jedes Dokuments anzeigen. Obwohl dieses Anweisungsattribut im Treiber simuliert werden kann, gibt es keinen Grund, dies zu tun. Wenn eine Anwendung Zeichen- oder Binärdaten abschneiden möchte, sollte sie einen kleinen Puffer an die Spalte mit SQLBindCol binden und den Treiber die Daten abschneiden lassen.