SQLBulkOperations 関数

準拠
導入されたバージョン: ODBC 3.0 Standards Compliance: ODBC

まとめ
SQLBulkOperations は 、ブックマークによる更新、削除、フェッチなど、一括挿入と一括ブックマーク操作を実行します。

構文

  
SQLRETURN SQLBulkOperations(  
     SQLHSTMT       StatementHandle,  
     SQLUSMALLINT   Operation);  

引数

StatementHandle
[入力]ステートメント ハンドル。

操作
[入力]実行する操作:

SQL_ADD SQL_UPDATE_BY_BOOKMARK SQL_DELETE_BY_BOOKMARK SQL_FETCH_BY_BOOKMARK

詳細については、「コメント」を参照してください。

戻り値

SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、SQL_NEED_DATA、SQL_STILL_EXECUTING、SQL_ERROR、またはSQL_INVALID_HANDLE。

診断

SQLBulkOperations がSQL_ERRORまたはSQL_SUCCESS_WITH_INFOを返す場合、関連付けられた SQLSTATE 値を取得するには、HandleType が SQL_HANDLE_STMT で、Handle of StatementHandle を指定して SQLGetDiagRec呼び出します。 次の表に、 SQLBulkOperations によって通常返される SQLSTATE 値の一覧を示し、この関数のコンテキストでそれぞれについて説明します。"(DM)" という表記は、ドライバー マネージャーによって返される SQLSTATEs の説明の前にあります。 特に明記されていない限り、各 SQLSTATE 値に関連付けられた戻りコードはSQL_ERRORされます。

SQL_SUCCESS_WITH_INFOまたはSQL_ERRORを返すことができるすべての SQLSTATEs (01xxx SQLSTATEs を除く) に対して、複数行操作の 1 つ以上の行でエラーが発生した場合はSQL_SUCCESS_WITH_INFOが返され、単一行操作でエラーが発生した場合はSQL_ERRORが返されます。

SQLSTATE エラー 説明
01000 一般的な警告 ドライバー固有の情報メッセージ。 (関数はSQL_SUCCESS_WITH_INFOを返します。
01004 文字列データの右切り捨て Operation 引数がSQL_FETCH_BY_BOOKMARKされ、データ型がSQL_C_CHARまたはSQL_C_BINARYの列または列に対して文字列またはバイナリ データが返され、非空白文字または NULL 以外のバイナリ データが切り捨てられました。
01S01 行のエラー Operation 引数がSQL_ADDされ、操作の実行中に 1 つ以上の行でエラーが発生しましたが、少なくとも 1 つの行が正常に追加されました。 (関数はSQL_SUCCESS_WITH_INFOを返します。

(このエラーは、アプリケーションが ODBC 2 を使用している場合にのみ発生します。x ドライバー。)
01S07 小数部の切り捨て 引数 Operation がSQL_FETCH_BY_BOOKMARKされ、アプリケーション バッファーのデータ型がSQL_C_CHARまたはSQL_C_BINARYされず、1 つ以上の列のアプリケーション バッファーに返されたデータが切り捨てられました。 (数値 C データ型の場合、数値の小数部が切り捨てられました。時刻、タイムスタンプ、および間隔 C のデータ型に時間コンポーネントが含まれている場合は、時刻の小数部が切り捨てられました)。

(関数はSQL_SUCCESS_WITH_INFOを返します。
07006 制限付きデータ型属性違反 Operation 引数がSQL_FETCH_BY_BOOKMARKされ、結果セット内の列のデータ値を、SQLBindCol の呼び出しで TargetType 引数で指定されたデータ型に変換できませんでした。

Operation 引数がSQL_UPDATE_BY_BOOKMARKまたはSQL_ADDであり、アプリケーション バッファー内のデータ値を結果セット内の列のデータ型に変換できませんでした。
07009 記述子インデックスが無効です 引数 Operation がSQL_ADDされ、結果セット内の列数より大きい列番号で列がバインドされました。
21S02 派生テーブルの次数が列リストと一致しない 引数 Operation がSQL_UPDATE_BY_BOOKMARKされました。すべての列が非連結または読み取り専用であったか、バインドされた長さ/インジケーター バッファーの値がSQL_COLUMN_IGNOREされたため、更新可能な列はありませんでした。
22001 文字列データの右切り捨て 結果セット内の列に文字またはバイナリ値を割り当てると、非空白文字 (文字の場合) または null 以外 (バイナリの場合) 文字またはバイトが切り捨てられました。
22003 範囲外の数値 Operation 引数はSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKであり、結果セット内の列に数値を割り当てると、数値の全体 (小数部ではなく) 部分が切り捨てられました。

引数 Operation がSQL_FETCH_BY_BOOKMARKされ、1 つ以上の連結列の数値を返すと、有効桁数が失われる可能性があります。
22007 datetime 形式が無効です 引数 Operation がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKされ、結果セット内の列に日付またはタイムスタンプ値を割り当て、年、月、または日のフィールドが範囲外になりました。

引数 Operation がSQL_FETCH_BY_BOOKMARKされ、1 つ以上の連結列の日付またはタイムスタンプ値を返すと、年、月、または日のフィールドが範囲外になります。
22008 日付/時刻フィールドオーバーフロー Operation 引数はSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKであり、結果セット内の列に送信されるデータに対する datetime 算術のパフォーマンスにより、結果の datetime フィールド (年、月、日、時間、分、または 2 番目のフィールド) がフィールドの許容範囲外に落ちたり、グレゴリオ暦の日付時刻カレンダーの自然なルールに基づいて無効になったりしました。

Operation 引数がSQL_FETCH_BY_BOOKMARKされ、結果セットから取得されたデータに対する datetime 算術のパフォーマンスにより、結果の datetime フィールド (年、月、日、時間、分、または 2 番目のフィールド) がフィールドの許容範囲外に落ちたり、グレゴリオ暦の datetime の自然なルールに基づいて無効になったりしました。
22015 間隔フィールドのオーバーフロー Operation 引数がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKであり、正確な数値型または間隔 C 型を間隔 SQL データ型に割り当て、有効桁数が失われました。

Operation 引数がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKされました。間隔 SQL 型に割り当てるときに、間隔 SQL 型に C 型の値が表現されませんでした。

引数 Operation がSQL_FETCH_BY_BOOKMARKされ、正確な数値または間隔の SQL 型から間隔 C 型に割り当てると、先頭フィールドに有効桁数が失われました。

Operation 引数がSQL_FETCH_BY_BOOKMARKされました。間隔 C 型に割り当てるときに、間隔 C 型の SQL 型の値の表現はありませんでした。
22018 キャスト指定の文字値が無効です Operation 引数がSQL_FETCH_BY_BOOKMARKされました。C 型は、正確または近似数値、datetime、または間隔データ型でした。列の SQL 型は文字データ型でした。列の値が、バインドされた C 型の有効なリテラルではありません。

引数 Operation がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKされました。SQL 型は、正確または近似数値、datetime、または間隔データ型でした。C 型はSQL_C_CHARされました。列の値が、バインドされた SQL 型の有効なリテラルではありません。
23000 整合性制約違反 Operation 引数がSQL_ADD、SQL_DELETE_BY_BOOKMARK、またはSQL_UPDATE_BY_BOOKMARKであり、整合性制約に違反しました。

Operation 引数がSQL_ADDされ、バインドされていない列は NOT NULL として定義され、既定値はありません。

Operation 引数がSQL_ADDされました。バインドされたStrLen_or_IndPtrバッファーで指定された長さがSQL_COLUMN_IGNOREされ、列に既定値が設定されていませんでした。
24000 カーソル状態が無効 StatementHandle は実行された状態でしたが、結果セットが StatementHandle に関連付けられなかった。
40001 シリアル化エラー 別のトランザクションでリソースのデッドロックが発生したため、トランザクションがロールバックされました。
40003 ステートメントの完了が不明です この関数の実行中に関連付けられた接続が失敗し、トランザクションの状態を特定できません。
42000 構文エラーまたはアクセス違反 ドライバーは、 Operation 引数で要求された操作を実行するために、必要に応じて行をロックできませんでした。
44000 WITH CHECK OPTION 違反 引数 Operation がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKされ、WITH CHECK OPTION を指定して作成された表示テーブル (または表示テーブルから派生したテーブル) に対して挿入または更新が実行され、挿入または更新の影響を受ける 1 つ以上の行が表示テーブルに存在しなくなります。
HY000 一般的なエラー 特定の SQLSTATE がなく、実装固有の SQLSTATE が定義されていないエラーが発生しました。 *MessageText バッファー内の SQLGetDiagRec によって返されるエラー メッセージは、エラーとその原因を説明します。
HY001 メモリ割り当てエラー ドライバーは、関数の実行または完了をサポートするために必要なメモリを割り当てることができませんでした。
HY008 操作が取り消されました StatementHandle に対して非同期処理が有効になりました。 関数が呼び出され、実行が完了する前に、 StatementHandleSQLCancel または SQLCancelHandle が呼び出されました。 その後、 StatementHandle で関数が再度呼び出されました。

関数が呼び出され、実行が完了する前に、マルチスレッド アプリケーションの別のスレッドから StatementHandleSQLCancel または SQLCancelHandle が呼び出されました。
HY010 関数シーケンス エラー (DM) StatementHandle に関連付けられている接続ハンドルに対して非同期実行関数が呼び出されました。 この非同期関数は、 SQLBulkOperations 関数が呼び出されたときにまだ実行されていました。

(DM) StatementHandle に対して SQLExecuteSQLExecDirect、または SQLMoreResults が呼び出され、SQL_PARAM_DATA_AVAILABLE返されました。 この関数は、すべてのストリーミング パラメーターのデータが取得される前に呼び出されました。

(DM) 指定された StatementHandle が実行された状態ではありません。 関数は、 SQLExecDirectSQLExecute、またはカタログ関数を最初に呼び出さずに呼び出されました。

(DM) 非同期実行関数 (この関数ではなく) が StatementHandle に対して呼び出され、この関数が呼び出されたときにまだ実行されていました。

(DM) StatementHandle に対して SQLExecuteSQLExecDirect、または SQLSetPos が呼び出され、SQL_NEED_DATA返されました。 この関数は、すべての実行時データ パラメーターまたは列に対してデータが送信される前に呼び出されました。

(DM) ドライバーは ODBC 2 でした。x ドライバーと SQLBulkOperations は、SQLFetchScroll または SQLFetch が呼び出される前に StatementHandle に対して呼び出されました。

(DM) SQLBulkOperations は、StatementHandleSQLExtendedFetch が呼び出された後に呼び出されました。
HY011 属性を今すぐ設定できません (DM) ドライバーは ODBC 2 でした。x ドライバーと SQL_ATTR_ROW_STATUS_PTR ステートメント属性は、SQLFetch または SQLFetchScrollSQLBulkOperations の呼び出しの間で設定されました。
HY013 メモリ管理エラー メモリが不足している可能性があるため、基になるメモリ オブジェクトにアクセスできなかったため、関数呼び出しを処理できませんでした。
HY090 文字列またはバッファーの長さが無効です Operation 引数がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKされました。データ値が null ポインターではありません。C データ型がSQL_C_BINARYまたはSQL_C_CHAR。列の長さの値は 0 未満ですが、SQL_DATA_AT_EXEC、SQL_COLUMN_IGNORE、SQL_NTS、またはSQL_NULL_DATAと等しくないか、SQL_LEN_DATA_AT_EXEC_OFFSET以下です。

長さ/インジケーター バッファー内の値がSQL_DATA_AT_EXECされました。SQL 型は、SQL_LONGVARCHAR、SQL_LONGVARBINARY、または長いデータ ソース固有のデータ型のいずれかでした。 SQLGetInfo のSQL_NEED_LONG_DATA_LEN情報の種類は "Y" でした。

引数 Operation がSQL_ADDされ、SQL_ATTR_USE_BOOKMARK ステートメント属性がSQL_UB_VARIABLEに設定され、列 0 は、この結果セットのブックマークの最大長と等しくないバッファーにバインドされました。 (この長さは IRD の SQL_DESC_OCTET_LENGTH フィールドで使用でき、 SQLDescribeColSQLColAttribute、または SQLGetDescField を呼び出すことで取得できます)。
HY092 無効な属性識別子 (DM) Operation 引数に指定された値が無効です。

Operation 引数がSQL_ADD、SQL_UPDATE_BY_BOOKMARK、またはSQL_DELETE_BY_BOOKMARKであり、SQL_ATTR_CONCURRENCY ステートメント属性が SQL_CONCUR_READ_ONLY に設定されました。

Operation 引数がSQL_DELETE_BY_BOOKMARK、SQL_FETCH_BY_BOOKMARK、またはSQL_UPDATE_BY_BOOKMARKであり、ブックマーク列がバインドされていないか、SQL_ATTR_USE_BOOKMARKSステートメント属性がSQL_UB_OFFに設定されました。
HY117 トランザクションの状態が不明なため、接続が中断されます。 切断と読み取り専用の関数のみが許可されます。 (DM) 中断状態の詳細については、「 SQLEndTran 関数」を参照してください。
HYC00 省略可能な機能が実装されていません ドライバーまたはデータ ソースは、 Operation 引数で要求された操作をサポートしていません。
HYT00 タイムアウトに達しました データ ソースが結果セットを返す前に、クエリのタイムアウト期間が期限切れになりました。 タイムアウト期間は SQLSetStmtAttr によって設定され、 Attribute 引数は SQL_ATTR_QUERY_TIMEOUT。
HYT01 接続のタイムアウト データ ソースが要求に応答する前に、接続タイムアウト期間の有効期限が切れています。 接続タイムアウト期間は、 SQLSetConnectAttr (SQL_ATTR_CONNECTION_TIMEOUT) によって設定されます。
IM001 ドライバーは、この関数をサポートしていません (DM) StatementHandle に関連付けられているドライバーは、 関数をサポートしていません。
IM017 非同期通知モードでポーリングが無効になっている 通知モデルが使用されるたびに、ポーリングは無効になります。
IM018 SQLCompleteAsync は、このハンドルで前の非同期操作を完了するために呼び出されていません。 ハンドルの前の関数呼び出しがSQL_STILL_EXECUTINGを返し、通知モードが有効になっている場合は、処理後に処理を実行して操作を完了するために、 SQLCompleteAsync をハンドルで呼び出す必要があります。

説明

注意事項

SQLBulkOperations を呼び出すことができるステートメントの状態と、ODBC 2 との互換性のために実行する必要がある内容について説明します。x アプリケーションについては、「付録 G: 下位互換性のためのドライバー ガイドライン」の「ブロック カーソル、スクロール可能カーソル、および下位互換性」セクションを参照してください。

アプリケーションでは 、SQLBulkOperations を使用して、現在のクエリに対応するベース テーブルまたはビューに対して次の操作を実行します。

  • 新しい行を追加します。

  • 各行がブックマークによって識別される一連の行を更新します。

  • 各行がブックマークによって識別される一連の行を削除します。

  • 各行がブックマークによって識別される一連の行をフェッチします。

SQLBulkOperations の呼び出し後、ブロック カーソル位置は未定義になります。 アプリケーションは SQLFetchScroll を呼び出してカーソル位置を設定する必要があります。 アプリケーションは、SQL_FETCH_FIRST、SQL_FETCH_LAST、SQL_FETCH_ABSOLUTE、またはSQL_FETCH_BOOKMARKの FetchOrientation 引数でのみ SQLFetchScroll を呼び出す必要があります。 SQL_FETCH_PRIOR、SQL_FETCH_NEXT、または SQL_FETCH_RELATIVE の FetchOrientation 引数を使用して SQLFetch または SQLFetchScroll を呼び出す場合、カーソル位置は未定義です。

SQLBindCol の呼び出しで指定された列の長さ/インジケーター バッファーを SQL_COLUMN_IGNORE に設定することで、SQLBulkOperations の呼び出しによって実行される一括操作で列を無視できます。

SQLBulkOperations を呼び出すときに、アプリケーションで SQL_ATTR_ROW_OPERATION_PTR ステートメント属性を設定する必要はありません。これは、この関数で一括操作を実行するときに行を無視できないためです。

SQL_ATTR_ROWS_FETCHED_PTR ステートメント属性が指すバッファーには、 SQLBulkOperations の呼び出しの影響を受ける行の数が含まれています。

引数 Operation がSQL_ADDまたはSQL_UPDATE_BY_BOOKMARKで、カーソルに関連付けられているクエリ指定の選択リストに同じ列への複数の参照が含まれている場合、エラーが生成されるか、重複した参照が無視され、要求された操作が実行されるかはドライバーによって定義されます。

SQLBulkOperations の使用方法の詳細については、「SQLBulkOperationsを使用したデータの更新」を参照してください。

一括挿入の実行

SQLBulkOperations を使用してデータを挿入するために、アプリケーションは次の一連の手順を実行します。

  1. 結果セットを返すクエリを実行します。

  2. SQL_ATTR_ROW_ARRAY_SIZE ステートメント属性を、挿入する行数に設定します。

  3. SQLBindCol を呼び出して、挿入するデータをバインドします。 データは、SQL_ATTR_ROW_ARRAY_SIZEの値と等しいサイズの配列にバインドされます。

    Note

    SQL_ATTR_ROW_STATUS_PTR ステートメント属性が指す配列のサイズは、SQL_ATTR_ROW_ARRAY_SIZEと等しいか、null ポインター SQL_ATTR_ROW_STATUS_PTRする必要があります。

  4. SQLBulkOperations(StatementHandle, SQL_ADD) を呼び出して挿入を実行します。

  5. アプリケーションで SQL_ATTR_ROW_STATUS_PTR ステートメント属性が設定されている場合は、この配列を検査して操作の結果を確認できます。

SQL_ADD の Operation 引数を使用して SQLBulkOperations を呼び出す前に、アプリケーションが列 0 をバインドした場合、ドライバーはバインドされた列 0 バッファーを、新しく挿入された行のブックマーク値で更新します。 これを行うには、 ステートメントを実行する前に、アプリケーションで SQL_ATTR_USE_BOOKMARKS ステートメント属性を SQL_UB_VARIABLE に設定しておく必要があります。 (これは ODBC 2 では機能しません。x ドライバー。)

長いデータは、SQLParamData と SQLPutData の呼び出しを使用して、SQLBulkOperations によってパーツに追加できます。 詳細については、この関数リファレンスで後述する「一括挿入と更新の長いデータの提供」を参照してください。

アプリケーションが SQLBulkOperations を呼び出す前に SQLFetch または SQLFetchScroll を呼び出す必要はありません (ODBC 2 に対する場合を除く)。x ドライバー。「下位互換性と標準のコンプライアンス」を参照してください。

この動作は、 sqlBulkOperations、SQL_ADDの Operation 引数を持つ場合に、重複する列を含むカーソルで呼び出された場合にドライバー定義されます。 ドライバーは、ドライバー定義の SQLSTATE を返したり、結果セットに表示される最初の列にデータを追加したり、他のドライバー定義の動作を実行したりできます。

ブックマークを使用した一括更新の実行

SQLBulkOperations でブックマークを使用して一括更新を実行するには、アプリケーションで次の手順を順番に実行します。

  1. SQL_ATTR_USE_BOOKMARKS ステートメント属性をSQL_UB_VARIABLEに設定します。

  2. 結果セットを返すクエリを実行します。

  3. SQL_ATTR_ROW_ARRAY_SIZE ステートメント属性を、更新する行数に設定します。

  4. SQLBindCol を呼び出して、更新するデータをバインドします。 データは、SQL_ATTR_ROW_ARRAY_SIZEの値と等しいサイズの配列にバインドされます。 また、 SQLBindCol を呼び出して列 0 (ブックマーク列) をバインドします。

  5. 更新対象の行のブックマークを、列 0 にバインドされた配列にコピーします。

  6. バインドされたバッファー内のデータを更新します。

    Note

    SQL_ATTR_ROW_STATUS_PTR ステートメント属性が指す配列のサイズは、SQL_ATTR_ROW_ARRAY_SIZEに等しいか、null ポインター SQL_ATTR_ROW_STATUS_PTRする必要があります。

  7. SQLBulkOperations(StatementHandle, SQL_UPDATE_BY_BOOKMARK) を呼び出します。

    Note

    アプリケーションで SQL_ATTR_ROW_STATUS_PTR ステートメント属性が設定されている場合は、この配列を調べて操作の結果を確認できます。

  8. 必要に応じて SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK) を呼び出して、バインドされたアプリケーション バッファーにデータをフェッチして、更新が発生したことを確認します。

  9. データが更新された場合、ドライバーは、適切な行の行状態配列の値をSQL_ROW_UPDATEDに変更します。

SQLBulkOperations によって実行される一括更新には、SQLParamDataSQLPutData の呼び出しを使用して、長いデータを含めることができます。 詳細については、この関数リファレンスで後述する「一括挿入と更新の長いデータの提供」を参照してください。

カーソル間でブックマークが保持される場合、ブックマークで更新する前に、アプリケーションで SQLFetch または SQLFetchScroll を呼び出す必要はありません。 前のカーソルから保存したブックマークを使用できます。 カーソル間でブックマークが保持されない場合、アプリケーションは SQLFetch または SQLFetchScroll を呼び出してブックマークを取得する必要があります。

この動作は、重複する列を含むカーソルに対して、SQL_UPDATE_BY_BOOKMARKの Operation 引数を持つ SQLBulkOperations が呼び出された場合にドライバー定義されます。 ドライバーは、ドライバー定義の SQLSTATE を返すか、結果セットに表示される最初の列を更新するか、ドライバー定義のその他の動作を実行できます。

ブックマークを使用した一括フェッチの実行

SQLBulkOperations でブックマークを使用して一括フェッチを実行するには、アプリケーションで次の手順を順番に実行します。

  1. SQL_ATTR_USE_BOOKMARKS ステートメント属性をSQL_UB_VARIABLEに設定します。

  2. 結果セットを返すクエリを実行します。

  3. SQL_ATTR_ROW_ARRAY_SIZE ステートメント属性を、フェッチする行数に設定します。

  4. SQLBindCol を呼び出して、フェッチするデータをバインドします。 データは、SQL_ATTR_ROW_ARRAY_SIZEの値と等しいサイズの配列にバインドされます。 また、 SQLBindCol を呼び出して列 0 (ブックマーク列) をバインドします。

  5. フェッチ対象の行のブックマークを、列 0 にバインドされた配列にコピーします。 (これは、アプリケーションが既に個別にブックマークを取得していることを前提としています。

    Note

    SQL_ATTR_ROW_STATUS_PTR ステートメント属性が指す配列のサイズは、SQL_ATTR_ROW_ARRAY_SIZEに等しいか、null ポインター SQL_ATTR_ROW_STATUS_PTRする必要があります。

  6. SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK) を呼び出します。

  7. アプリケーションで SQL_ATTR_ROW_STATUS_PTR ステートメント属性が設定されている場合は、この配列を調べて操作の結果を確認できます。

カーソル間でブックマークが保持される場合、ブックマークでフェッチする前に、アプリケーションで SQLFetch または SQLFetchScroll を呼び出す必要はありません。 前のカーソルから保存したブックマークを使用できます。 カーソル間でブックマークが保持されない場合、アプリケーションは、ブックマークを取得するために SQLFetch または SQLFetchScroll を 1 回呼び出す必要があります。

ブックマークを使用した一括削除の実行

SQLBulkOperations でブックマークを使用して一括削除を実行するには、アプリケーションで次の手順を順番に実行します。

  1. SQL_ATTR_USE_BOOKMARKS ステートメント属性をSQL_UB_VARIABLEに設定します。

  2. 結果セットを返すクエリを実行します。

  3. SQL_ATTR_ROW_ARRAY_SIZE ステートメント属性を、削除する行数に設定します。

  4. SQLBindCol を呼び出して、列 0 (ブックマーク列) をバインドします。

  5. 削除する行のブックマークを、列 0 にバインドされた配列にコピーします。

    Note

    SQL_ATTR_ROW_STATUS_PTR ステートメント属性が指す配列のサイズは、SQL_ATTR_ROW_ARRAY_SIZEに等しいか、null ポインター SQL_ATTR_ROW_STATUS_PTRする必要があります。

  6. SQLBulkOperations(StatementHandle, SQL_DELETE_BY_BOOKMARK) を呼び出します。

  7. アプリケーションで SQL_ATTR_ROW_STATUS_PTR ステートメント属性が設定されている場合は、この配列を調べて操作の結果を確認できます。

カーソル間でブックマークが保持される場合、ブックマークで削除する前に、アプリケーションで SQLFetch または SQLFetchScroll を呼び出す必要はありません。 前のカーソルから保存したブックマークを使用できます。 カーソル間でブックマークが保持されない場合、アプリケーションは、ブックマークを取得するために SQLFetch または SQLFetchScroll を 1 回呼び出す必要があります。

一括挿入と更新の長いデータの提供

SQLBulkOperations の呼び出しによって一括挿入と更新が実行される場合は、長いデータを提供できます。 長いデータを挿入または更新するには、このトピックで前述した「一括挿入の実行」および「ブックマークを使用した一括更新の実行」セクションで説明した手順に加えて、次の手順を実行します。

  1. SQLBindCol を使用してデータをバインドすると、アプリケーションは、実行時データ列の *TargetValuePtr バッファーに、列番号などのアプリケーション定義値を配置します。 値は、後で列を識別するために使用できます。

    アプリケーションは、SQL_LEN_DATA_AT_EXEC(length) マクロの結果を *StrLen_or_IndPtr バッファーに配置します。 列の SQL データ型がSQL_LONGVARBINARY、SQL_LONGVARCHAR、または長いデータ ソース固有のデータ型であり、ドライバーが SQLGetInfo のSQL_NEED_LONG_DATA_LEN情報型の "Y" を返す場合、 length はパラメーターに送信されるデータのバイト数です。それ以外の場合は、負でない値である必要があり、無視されます。

  2. SQLBulkOperations が呼び出されると、実行時データ列がある場合、関数は SQL_NEED_DATAを返し、次の手順 3 に進みます。 (実行中のデータ列がない場合、プロセスは完了です)。

  3. アプリケーションは SQLParamData を呼び出して、処理される最初の実行時データ列の *TargetValuePtr バッファーのアドレスを取得します。 SQLParamData はSQL_NEED_DATAを返します。 アプリケーションは、 *TargetValuePtr バッファーからアプリケーション定義値を取得します。

    Note

    実行時データ パラメーターは実行データ列に似ていますが、 SQLParamData によって返される値はそれぞれ異なります。

    実行時データ列は、行が SQLBulkOperations で更新または挿入されたときに、SQLPutData でデータが送信される行セット内の列です。 これらは SQLBindCol でバインドされます。 SQLParamData によって返される値は、処理中の *TargetValuePtr バッファー内の行のアドレスです。

  4. アプリケーションは SQLPutData を 1 回以上呼び出して、列のデータを送信します。 SQLPutData で指定された *TargetValuePtr バッファーですべてのデータ値を返すことができない場合は、複数の呼び出しが必要です。同じ列に対する SQLPutData の複数回の呼び出しは、文字、バイナリ、またはデータ ソース固有のデータ型を持つ列に文字 C データを送信する場合、または文字、バイナリ、またはデータ ソース固有のデータ型を持つ列にバイナリ C データを送信する場合にのみ許可されます。

  5. アプリケーションは SQLParamData を再度呼び出して、列のすべてのデータが送信されたことを通知します。

    • 実行データ列が多い場合、 SQLParamData は、次に処理される実行時データ列のSQL_NEED_DATAと TargetValuePtr バッファーのアドレスを返します。 アプリケーションは、手順 4 と 5 を繰り返します。

    • 実行データ列がこれ以上ない場合、プロセスは完了です。 ステートメントが正常に実行された場合、 SQLParamData は SQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOを返します。実行に失敗した場合は、SQL_ERRORを返します。 この時点で、 SQLParamDataSQLBulkOperations から返すことができる任意の SQLSTATE を返すことができます。

操作が取り消されたか、 SQLParamData または SQLPutDataSQLBulkOperations がSQL_NEED_DATAを返した後、実行中のすべてのデータ列に対してデータが送信される前にエラーが発生した場合、アプリケーションはステートメントまたはステートメントに関連付けられている接続に対して SQLCancelSQLGetDiagFieldSQLGetDiagRecSQLGetFunctionsSQLParamData、または SQLPutData のみを呼び出すことができます。 ステートメントまたはステートメントに関連付けられている接続に対して他の関数を呼び出すと、関数は SQL_ERROR および SQLSTATE HY010 (関数シーケンス エラー) を返します。

ドライバーが実行中のデータ列のデータを必要とする間にアプリケーションが SQLCancel を呼び出す場合、ドライバーは操作を取り消します。 その後、アプリケーションは SQLBulkOperations を再度呼び出すことができます。の取り消しは、カーソルの状態や現在のカーソル位置には影響しません。

行の状態の配列

行状態配列には、 SQLBulkOperations の呼び出し後に行セット内のデータの各行の状態値が含まれます。 ドライバーは、SQLFetch、SQLFetchScrollSQLSetPos、または SQLBulkOperations の呼び出しの後に、この配列の状態値を設定します。 SQLBulkOperations より前に SQLFetch または SQLFetchScroll が呼び出されていない場合、この配列は最初に SQLBulkOperations の呼び出しによって設定されます。 この配列は、SQL_ATTR_ROW_STATUS_PTR ステートメント属性によって指されます。 行状態配列内の要素の数は、(SQL_ATTR_ROW_ARRAY_SIZE ステートメント属性で定義されている) 行セット内の行数と等しい必要があります。 この行の状態配列の詳細については、「 SQLFetch」を参照してください。

コード例

次の例では、Customers テーブルから一度に 10 行のデータをフェッチします。 次に、実行するアクションをユーザーに求めます。 ネットワーク トラフィックを減らすために、バッファーの例では、バインドされた配列内でローカルに更新、削除、挿入しますが、行セット データを超えるオフセットで挿入します。 ユーザーがデータ ソースに対する更新、削除、挿入の送信を選択すると、バインディング オフセットが適切に設定され、 SQLBulkOperations が呼び出されます。 わかりやすくするために、ユーザーは 10 を超える更新、削除、または挿入をバッファーに格納できません。

// SQLBulkOperations_Function.cpp  
// compile with: ODBC32.lib  
#include <windows.h>  
#include <sqlext.h>  
#include "stdio.h"  
  
#define UPDATE_ROW 100  
#define DELETE_ROW 101  
#define ADD_ROW 102  
#define SEND_TO_DATA_SOURCE 103  
#define UPDATE_OFFSET 10  
#define INSERT_OFFSET 20  
#define DELETE_OFFSET 30  
  
// Define structure for customer data (assume 10 byte maximum bookmark size).  
typedef struct tagCustStruct {  
   SQLCHAR Bookmark[10];  
   SQLINTEGER BookmarkLen;  
   SQLUINTEGER CustomerID;  
   SQLINTEGER CustIDInd;  
   SQLCHAR CompanyName[51];  
   SQLINTEGER NameLenOrInd;  
   SQLCHAR Address[51];  
   SQLINTEGER AddressLenOrInd;  
   SQLCHAR Phone[11];  
   SQLINTEGER PhoneLenOrInd;  
} CustStruct;  
  
// Allocate 40 of these structures. Elements 0-9 are for the current rowset,  
// elements 10-19 are for the buffered updates, elements 20-29 are for  
// the buffered inserts, and elements 30-39 are for the buffered deletes.  
CustStruct CustArray[40];  
SQLUSMALLINT RowStatusArray[10], Action, RowNum, NumUpdates = 0, NumInserts = 0,  
NumDeletes = 0;  
SQLLEN BindOffset = 0;  
SQLRETURN retcode;  
SQLHENV henv = NULL;  
SQLHDBC hdbc = NULL;  
SQLHSTMT hstmt = NULL;  
  
int main() {  
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);   
  
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);   
   retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  
   retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);  
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  
   // Set the following statement attributes:  
   // SQL_ATTR_CURSOR_TYPE:           Keyset-driven  
   // SQL_ATTR_ROW_BIND_TYPE:         Row-wise  
   // SQL_ATTR_ROW_ARRAY_SIZE:        10  
   // SQL_ATTR_USE_BOOKMARKS:         Use variable-length bookmarks  
   // SQL_ATTR_ROW_STATUS_PTR:        Points to RowStatusArray  
   // SQL_ATTR_ROW_BIND_OFFSET_PTR:   Points to BindOffset  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(CustStruct), 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_VARIABLE, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &BindOffset, 0);  
  
   // Bind arrays to the bookmark, CustomerID, CompanyName, Address, and Phone columns.  
   retcode = SQLBindCol(hstmt, 0, SQL_C_VARBOOKMARK, CustArray[0].Bookmark, sizeof(CustArray[0].Bookmark), &CustArray[0].BookmarkLen);  
   retcode = SQLBindCol(hstmt, 1, SQL_C_ULONG, &CustArray[0].CustomerID, 0, &CustArray[0].CustIDInd);  
   retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, CustArray[0].CompanyName, sizeof(CustArray[0].CompanyName), &CustArray[0].NameLenOrInd);  
   retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, CustArray[0].Address, sizeof(CustArray[0].Address), &CustArray[0].AddressLenOrInd);  
   retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, CustArray[0].Phone, sizeof(CustArray[0].Phone), &CustArray[0].PhoneLenOrInd);  
  
   // Execute a statement to retrieve rows from the Customers table.  
   retcode = SQLExecDirect(hstmt, (SQLCHAR*)"SELECT CustomerID, CompanyName, Address, Phone FROM Customers", SQL_NTS);  
  
   // Fetch and display the first 10 rows.  
   retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
   // DisplayCustData(CustArray, 10);  
  
   // Call GetAction to get an action and a row number from the user.  
   // while (GetAction(&Action, &RowNum)) {  
   Action = SQL_FETCH_NEXT;  
   RowNum = 2;  
   switch (Action) {  
      case SQL_FETCH_NEXT:  
      case SQL_FETCH_PRIOR:  
      case SQL_FETCH_FIRST:  
      case SQL_FETCH_LAST:  
      case SQL_FETCH_ABSOLUTE:  
      case SQL_FETCH_RELATIVE:  
         // Fetch and display the requested data.  
         SQLFetchScroll(hstmt, Action, RowNum);  
         // DisplayCustData(CustArray, 10);  
         break;  
  
      case UPDATE_ROW:  
         // Check if we have reached the maximum number of buffered updates.  
         if (NumUpdates < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered updates section of CustArray, copy the bookmark of the row  
            // being updated to the same element, and increment the update counter.  
            // Checking to see we have not already buffered an update for this  
            // row not shown.  
            // GetNewCustData(CustArray, UPDATE_OFFSET + NumUpdates);  
            memcpy(CustArray[UPDATE_OFFSET + NumUpdates].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
            CustArray[UPDATE_OFFSET + NumUpdates].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
            NumUpdates++;  
         } else {  
            printf("Buffers full. Send buffered changes to the data source.");  
         }  
         break;  
      case DELETE_ROW:  
         // Check if we have reached the maximum number of buffered deletes.  
         if (NumDeletes < 10) {  
            // Copy the bookmark of the row being deleted to the next available element  
            // of the buffered deletes section of CustArray and increment the delete  
            // counter. Checking to see we have not already buffered an update for  
            // this row not shown.  
            memcpy(CustArray[DELETE_OFFSET + NumDeletes].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
  
            CustArray[DELETE_OFFSET + NumDeletes].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
  
            NumDeletes++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case ADD_ROW:  
         // reached maximum number of buffered inserts?  
         if (NumInserts < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered inserts section of CustArray and increment insert counter.  
            // GetNewCustData(CustArray, INSERT_OFFSET + NumInserts);  
            NumInserts++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case SEND_TO_DATA_SOURCE:  
         // If there are any buffered updates, inserts, or deletes, set the array size  
         // to that number, set the binding offset to use the data in the buffered  
         // update, insert, or delete part of CustArray, and call SQLBulkOperations to  
         // do the updates, inserts, or deletes. Because we will never have more than  
         // 10 updates, inserts, or deletes, we can use the same row status array.  
         if (NumUpdates) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumUpdates, 0);  
            BindOffset = UPDATE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_UPDATE_BY_BOOKMARK);  
            NumUpdates = 0;  
         }  
  
         if (NumInserts) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumInserts, 0);  
            BindOffset = INSERT_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_ADD);  
            NumInserts = 0;  
         }  
  
         if (NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumDeletes, 0);  
            BindOffset = DELETE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_DELETE_BY_BOOKMARK);  
            NumDeletes = 0;  
         }  
  
         // If there were any updates, inserts, or deletes, reset the binding offset  
         // and array size to their original values.  
         if (NumUpdates || NumInserts || NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
            BindOffset = 0;  
         }  
         break;  
   }  
   // }  
  
   // Close the cursor.  
   SQLFreeStmt(hstmt, SQL_CLOSE);  
}  
対象 解決方法については、
結果セット内の列にバッファーをバインドする SQLBindCol 関数
ステートメント処理の取り消し SQLCancel 関数
データブロックのフェッチまたは結果セットのスクロール SQLFetchScroll 関数
記述子の 1 つのフィールドを取得する SQLGetDescField 関数
記述子の複数のフィールドを取得する SQLGetDescRec 関数
記述子の単一フィールドの設定 SQLSetDescField 関数
記述子の複数のフィールドの設定 SQLSetDescRec 関数
カーソルの配置、行セット内のデータの更新、または行セット内のデータの更新または削除 SQLSetPos 関数
ステートメント属性の設定 SQLSetStmtAttr 関数

参照

ODBC API リファレンス
ODBC ヘッダー ファイル