長い形式のデータの取得
DBMS では、長いデータは、255 文字など、特定のサイズの任意の文字またはバイナリ データとして定義されます。 このデータは、数千文字の部品説明のように、1 つのバッファに格納できるほど小さいかもしれません。 ただし、長いテキスト ドキュメントやビットマップなど、メモリに格納するには長すぎる場合があります。 このようなデータは 1 つのバッファーに格納できないため、行内の他のデータがフェッチされた後、SQLGetData の部分でドライバーから取得されます。
Note
アプリケーションは、長いデータだけでなく、SQLGetData を使用して任意の種類のデータを実際に取得できますが、一部で取得できるのは文字データとバイナリ データだけです。 しかし、データが1つのバッファに収まるほど小さければ、一般的にSQLGetDataを使用する理由はありません。 バッファーを列にバインドし、ドライバーがバッファー内のデータを返す方がはるかに簡単です。
列から長いデータを取得するために、アプリケーションは最初に SQLFetchScrollまたは SQLFetch を呼び出して行に移動し、バインドされた列のデータをフェッチします。 その後、アプリケーションは SQLGetData を呼び出します。 SQLGetData には SQLBindCol と同じ引数があります:ステートメント ハンドル、列番号、アプリケーション変数の C データ型、アドレス、バイト長、長さ/インジケーター バッファーのアドレスです。 どちらの関数も本質的に同じタスクを実行するため、同じ引数を持ちます:どちらもアプリケーション変数をドライバーに記述し、特定の列のデータをその変数で返すように指定します。 主な違いは、行がフェッチされた後に SQLGetData が呼び出され (この理由から遅延バインドと呼ばれることもあります)、SQLGetData で指定されたバインドが呼び出しの期間中のみ続く点です。
1 つの列に関しては、SQLGetData は SQLFetch のように動作します:列のデータを取得し、それをアプリケーション変数の型に変換して、その変数で返します。 また、長さ/インジケーター バッファー内のデータのバイト長も返します。 SQLFetch がデータを返す方法の詳細については、「データ行のフェッチ」を参照してください。
SQLGetData は、1 つの重要な点で 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 に対して呼び出すとエラーになります。
バインドすることはできません。
最後にバインドされた列より大きい列番号を指定する必要があります。 たとえば、最後にバインドされた列が列 3 の場合、列 2 に対して SQLGetData を呼び出すとエラーになります。 このため、アプリケーションでは、選択リストの末尾に長いデータ列を配置する必要があります。
複数の行を取得するために SQLFetch または SQLFetchScroll が呼び出された場合は使用できません。 詳しくは、「ブロック カーソルを使う」を参照してください。
一部のドライバーでは、これらの制限が適用されません。 相互運用可能なアプリケーションは、存在することを前提とするか、SQL_GETDATA_EXTENSIONS オプションを使用して SQLGetInfo を呼び出すことによって、適用されない制限を決定する必要があります。
アプリケーションが文字またはバイナリ データ列のすべてのデータを必要としない場合は、ステートメントを実行する前に SQL_ATTR_MAX_LENGTH ステートメント属性を設定することで、DBMS ベースのドライバーのネットワーク トラフィックを減らすことができます。 これにより、任意の文字またはバイナリ列に対して返されるデータのバイト数が制限されます。 たとえば、列に長いテキスト ドキュメントが含まれているとします。 この列を含むテーブルを参照するアプリケーションでは、各ドキュメントの最初のページのみを表示する必要がある場合があります。 このステートメント属性はドライバーでシミュレートできますが、これを行う理由はありません。 特に、アプリケーションが文字またはバイナリ データを切り捨てる場合は、SQLBindCol を使用して小さなバッファーを列にバインドし、ドライバーがデータを切り捨てできるようにする必要があります。