取得長資料
DBMS 會將「長資料」定義為超過特定大小的任何字元或二進位資料,例如超出 255 個字元。 這種資料的大小範圍可能小到可儲存在單一緩衝區中,例如屬於數千字元的描述的一部分。 不過資料也可能會長到無法儲存在記憶體中,例如長篇的文字文件或點陣圖。 由於這類資料無法儲存在單一緩衝區中,因此在擷取資料列中的其他資料之後,會使用 SQLGetData 從驅動程式分段擷取。
注意
雖然只有字元和二進位資料可以分段擷取,但是應用程式實際上還是可以使用 SQLGetData 擷取任何類型的資料,不限於長資料。 不過,如果資料夠小而足以容納在單一緩衝區中,通常就沒有理由使用 SQLGetData。 將緩衝區繫結至資料行,並讓驅動程式傳回緩衝區中的資料會更容易。
若要從資料行擷取長資料,應用程式會先呼叫 SQLFetchScroll 或 SQLFetch 來移至資料列,並擷取繫結資料行的資料。 應用程式接著會呼叫 SQLGetData。 SQLGetData 的引數與 SQLBindCol 相同:陳述式控制代碼;資料行編號;應用程式變數的 C 資料類型、位址和位元組長度;長度/指標緩衝區的位址。 這兩個函式都有相同的引數,因為基本上執行的工作相同:都會向驅動程式描述應用程式變數,並指定該變數中應該傳回的特定資料行資料。 主要差異在於,會在擷取資料列之後呼叫 SQLGetData (因此有時也稱為「晚期繫結」),而且 SQLGetData 指定的繫結只會持續到呼叫期間結束為止。
關於單一資料行,SQLGetData 行為類似於 SQLFetch:其會擷取資料行的資料、將之轉換成應用程式變數的類型,並在該變數中傳回。 也會傳回長度/指標緩衝區中資料的位元組長度。 如需 SQLFetch 如何傳回資料的詳細資訊,請參閱擷取一列資料。
SQLGetData 有一個重要的層面與 SQLFetch 不同。 如果相同資料行連續呼叫一次以上,則每次呼叫都會傳回該資料的一個連續部分。 最後一次呼叫除外,其他每次呼叫都會傳回 SQL_SUCCESS_WITH_INFO 和 SQLSTATE 01004 (字串資料,右截斷);最後一次呼叫則會傳回 SQL_SUCCESS。 這是 SQLGetData 用來分段擷取長資料的方式。 當沒有其他資料可傳回時,SQLGetData 會傳回SQL_NO_DATA。 應用程式負責將長資料組合在一起,這可能代表會將資料各部分串連起來。 每個部分都是以 Null 終止;如果要串連各部分,則應用程式必須移除 null 終止字元。 對可變長度書籤和其他長資料,可分段擷取資料。 每一次呼叫中,長度/指標緩衝區中傳回的值會依照上一次呼叫中傳回的位元組數目減少,不過驅動程式通常無法探索可用的資料量,並傳回 SQL_NO_TOTAL 的位元組長度。 例如:
// 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);
使用 SQLGetData 有數個限制。 一般而言,使用 SQLGetData 存取的資料行:
存取順序必須依照遞增的資料行編號 (原因在於從資料來源讀取結果集資料行的方式)。 舉例來說,呼叫資料行 5 的 SQLGetData 後再呼叫資料行 4 的 SQLGetData 時,便會發生錯誤。
無法繫結。
資料行編號必須大於最後一個繫結資料行。 假如最後一個繫結資料行是資料行 3,則呼叫資料行 2 的 SQLGetData 會發生錯誤。 基於這個理由,應用程式一定要將長資料行放在選取清單的結尾。
如果呼叫 SQLFetch 或 SQLFetchScroll 來擷取多個資料列,則無法使用。 如需詳細資訊,請參閱使用區塊資料指標。
某些驅動程式不會強制執行這些限制。 可互通的應用程式應會假設存在這些限制,或者使用 SQL_GETDATA_EXTENSIONS 選項呼叫 SQLGetInfo 來判斷哪些限制不會強制執行。
如果應用程式不需要字元或二進位資料行中的所有資料,則可以先設定 SQL_ATTR_MAX_LENGTH 陳述式屬性,再執行陳述式,以減少 DBMS 型驅動程式中的流量。 這樣一來,對任何字元或二進位資料行傳回的資料位元組數目會受到限制。 例如,假設某個資料行包含長篇的文字文件。 若應用程式瀏覽包含此資料行的資料表,可能只需要顯示每份文件的第一頁。 雖然可在驅動程式中模擬此陳述式屬性,但沒有需要這麼做的理由。 尤其若是應用程式想要截斷字元或二進位資料,則應會使用 SQLBindCol 將小型緩衝區繫結至資料行,並讓驅動程式截斷資料。