Oracle® Database

アドバンスト・アプリケーション開発者ガイド

11gリリース2 (11.2)

B56259-09(原本部品番号:E41502-06)

2014年12月

Oracle Databaseアドバンスト・アプリケーション開発者ガイド, 11gリリース2 (11.2)

B56259-09

Copyright © 1996, 2014, Oracle and/or its affiliates.All rights reserved.

原本著者: Sheila Moore

原本協力者: D.Adams、L.Ashdown、P.Huey、S.Moore、E.Paapanen、R.Strohm、R.Ward

原本協力者:  D.Alpern、G.Arora、T.Chang、B.Cheng、R.Day、R.Decker、G.Doherty、D.Elson、A.Ganesh、M.Hartstein、Y.Hu、J.Huang、C.Iyer、N.Jain、V.Krishnaswamy、R.Kumar、S.Kumar、C.Lei、B.Llewellyn、K.Mohan、V.Moore、K.Muthukkaruppan、J.Muller、R.Murthy、R.Pang、B.Sinha、S.Vemuri、W.Wang、D.Wong

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXはThe Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

目次

例一覧

図一覧

表一覧

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

アプリケーション開発のための新機能

- Oracle Database 11gリリース2 (11.2.0.4)の機能

- Oracle Database 11gリリース2 (11.2.0.2)の機能

- Oracle Database 11gリリース2の機能

- Oracle Database 11gリリース1の機能

第I部 アプリケーション開発者用のSQL

1 データベース・アプリケーションにおけるSQLデータ型の使用

- SQLデータ型の概要

- 文字データの表現

- バイト数または文字数としての列の長さの指定

- CHARデータ型およびVARCHAR2データ型間の選択

- 数値データの表現

- 浮動小数点数の構成要素

- 浮動小数点数形式

- 浮動小数点2進形式

- ネイティブ浮動小数点形式の特殊な数値

- ネイティブ浮動小数点データ型の比較演算子

- ネイティブ浮動小数点データ型を使用した算術演算

- 浮動小数点データ型の変換関数

- ネイティブ浮動小数点データ型のクライアント・インタフェース

- OCIのネイティブ浮動小数点データ型SQLT_BFLOATおよびSQLT_BDOUBLE

- ADTでサポートされるネイティブ浮動小数点データ型

- ネイティブ浮動小数点データ型のPro*C/C++サポート

- 日時データの表現

- 現在の日付および時刻の表示

- デフォルト以外の書式での日付の表示および挿入

- デフォルト以外の書式での時刻の表示および挿入

- 日時データ型を使用した算術演算

- 日時データ型の変換関数

- 日時データ型のインポートおよびエクスポート

- 特殊なデータの表現

- 地理データの表現

- マルチメディア・データの表現

- 大量のデータの表現

- ラージ・オブジェクト(LOB)

- LONGおよびLONG RAWデータ型

- 検索可能なテキストの表現

- XMLデータの表現

- 動的に型指定されたデータの表現

- ANSI、DB2およびSQL/DSデータの表現

- 条件式のデータとしての表現

- アドレスによる行の識別

- ROWID疑似列の問合せ

- ROWIDデータ型

- 制限付き内部ROWID形式

- 拡張内部ROWID形式

- 外部バイナリ内部ROWID形式

- UROWIDデータ型

- Oracle Databaseによるデータ型の変換方法

- 代入中のデータ変換

- 式の評価中のデータ型変換

- SQL演算子と関数のメタデータ

- ARGnデータ型

- DISP_TYPEデータ型

- データ型ファミリ

2 アプリケーション開発者用のSQL処理

- SQL文の処理の説明

- 操作のトランザクションへのグループ化

- トランザクションへの操作のグループ化方法の決定

- トランザクションのパフォーマンスの改善

- トランザクションのコミット

- コミットREDO動作の管理

- トランザクションのロールバック

- トランザクションのセーブポイントの定義

- 読取り専用トランザクションでの反復可能読取りの保証

- カーソルの使用

- 1つのセッションでオープンできるカーソルの数

- 文を再実行するためのカーソルの使用

- スクロール可能カーソル

- カーソルのクローズ

- カーソルの取消し

- 明示的な表のロック

- 表のロックを取得するために必要な権限

- ロック方法の選択

- ROW SHARE MODEおよびROW EXCLUSIVE MODEでロックする場合

- SHARE MODEでロックする場合

- SHARE ROW EXCLUSIVE MODEでロックする場合

- EXCLUSIVE MODEでロックする場合

- Oracle Databaseによる表ロック制御

- 明示的な行ロック

- 明示的なロックにおける同時実行性の例

- Oracle Lock Managementサービス(ユーザー・ロック)の使用

- ユーザー・ロックを使用する場合

- ロックの表示および監視

- シリアライズ可能トランザクションを使用した同時実行性の制御

- トランザクションの相互作用と分離レベル

- 分離レベルの設定

- シリアライズ可能トランザクションおよび参照整合性

- READ COMMITTEDおよびSERIALIZABLE分離レベル

- トランザクション集合の整合性の違い

- トランザクション分離レベルの選択

- 自律型トランザクション

- 自律型トランザクションの例

- 商品の注文

- 銀行口座からの出金処理

- 自律型トランザクションの定義

- 記憶域割当てエラー後の実行の再開

- 再開可能記憶域割当てを含む操作

- 一時停止された記憶域割当ての処理

- アプリケーションのAFTER SUSPENDトリガーの使用

- 一時停止された文の確認

3 データベース・アプリケーションでの正規表現の使用

- 正規表現の概要

- Oracle SQLの正規表現のサポート

- Oracle SQLおよびPOSIX正規表現標準

- Oracle SQL正規表現内の演算子

- Oracle SQL正規表現内のPOSIX演算子

- Oracle SQLのPOSIX標準に対する多言語拡張機能

- Oracle SQLのPOSIX標準に対するPERLの影響を受ける拡張機能

- SQL文での正規表現の使用: 例

- 制約を使用した電話番号書式の規定

- 後方参照を使用した文字の再配置

4 データベース・アプリケーションでの索引の使用

- 索引の管理のガイドライン

- 索引の管理

- ドメイン索引を使用する場合

- ファンクション索引を使用する場合

- ファンクション索引のメリット

- ファンクション索引のデメリット

- ファンクション索引の例

5 データベース・アプリケーションにおけるデータ整合性のメンテナンス

- 制約を使用したビジネス・ルールの施行

- 制約とアプリケーション・コードの両方を使用したビジネス・ルールの施行

- 制約で使用する索引の作成

- NOT NULL制約を使用する場合

- デフォルトの列値を使用する場合

- 表の主キーの選択(PRIMARY KEY制約)

- UNIQUE制約を使用する場合

- FOREIGN KEY制約を使用した参照整合性の施行

- FOREIGN KEY制約およびNULL値

- 親表と子表との関連の定義

- 複数のFOREIGN KEY制約に関する規則

- 制約チェックの遅延

- 制約に対応付けられた索引の領域と時間のオーバーヘッドの最小化

- 外部キーを索引付けするためのガイドライン

- 分散データベース内の参照整合性

- CHECK制約を使用する場合

- CHECK制約の制限

- CHECK制約の設計

- 複数のCHECK制約に関する規則

- CHECKおよびNOT NULL制約の選択

- 制約の定義の例

- 制約の定義に必要な権限

- 制約のネーミング

- 制約の使用可能および使用禁止

- 制約を使用禁止にする理由

- 制約を使用可能にする(デフォルト)

- 制約を使用禁止にする

- 既存の制約を使用可能にする

- 既存の制約を使用禁止にする

- キー制約の使用可能および使用禁止に関するガイドライン

- 制約の例外の修正

- 制約の変更

- 制約名の変更

- 制約の削除

- FOREIGN KEY制約の管理

- 外部キー列のデータ型および名前

- 複合外部キーにおける列の制限

- デフォルトでの外部キーの主キー参照

- FOREIGN KEY制約の作成に必要な権限

- 外部キーによる参照整合性の施行方法の選択

- 制約に関する情報の表示

第II部 アプリケーション開発者用のPL/SQL

6 PL/SQLサブプログラムおよびパッケージのコード化

- PL/SQLユニットの概要

- 無名ブロック

- ストアドPL/SQLユニット

- サブプログラムのネーミング

- サブプログラムのパラメータ

- サブプログラムの作成

- サブプログラムの変更

- サブプログラムおよびパッケージの削除

- 外部サブプログラム

- PL/SQLファンクション結果キャッシュ

- PL/SQLパッケージ

- PL/SQLオブジェクト・サイズの制限

- パッケージの作成

- パッケージおよびパッケージ・オブジェクトのネーミング

- パッケージの無効化とセッションの状態

- Oracle Databaseが提供するパッケージ

- バルク・バインドの概要

- バルク・バインドを使用する場合

- トリガー

- ネイティブ実行のためのPL/SQLサブプログラムのコンパイル

- カーソル変数

- カーソル変数の宣言およびオープン

- カーソル変数の例

- PL/SQLコンパイル時のエラー処理

- PL/SQLのランタイム・エラー処理

- 例外および例外処理の宣言

- 未処理例外

- 分散問合せでのエラー処理

- リモート・サブプログラムでのエラー処理

- ストアド・サブプログラムのデバッグ

- PL/Scope

- PL/SQL階層プロファイラ

- Oracle JDeveloper

- DBMS_OUTPUTパッケージ

- PL/SQLストアド・サブプログラムおよびJavaストアド・サブプログラムのデバッグ権限

- 低レベルのデバッグ・コードの書込み

- DBMS_DEBUG_JDWPパッケージ

- DBMS_DEBUGパッケージ

- ストアド・サブプログラムの起動

- サブプログラムの起動に必要な権限

- Oracleツールを使用した対話形式によるサブプログラムの起動

- 別のサブプログラムからのサブプログラムの起動

- 3GLアプリケーションからのサブプログラムの起動

- リモート・サブプログラムの起動

- リモート・サブプログラムのシノニム

- トランザクションのコミット

- SQL文からのストアドPL/SQLファンクションの起動

- SQL文からストアドPL/SQLサブプログラムを起動する理由

- SQL文の中でPL/SQLファンクションを使用できる箇所

- SQL式の中でPL/SQLファンクションを使用できる条件

- 副作用の制御

- 制限事項

- ファンクションの宣言

- パラレル問合せおよびパラレルDML

- 下位互換性のためのPRAGMA RESTRICT_REFERENCES

- ファンクションからの大量のデータの戻し

- 独自の集計関数のコード化

7 PL/Scopeの使用

- 識別子コレクションの指定

- STANDARDおよびDBMS_STANDARDのPL/Scope識別子データ

- PL/Scopeデータによる領域の使用量

- PL/Scopeデータの表示

- 静的データ・ディクショナリ・ビュー

- 一意キー

- コンテキスト

- シグネチャ

- デモ・ツール

- SQL Developer

- PL/Scopeが収集する識別子の型

- PL/Scopeがレポートする使用方法

- サンプルPL/Scopeセッション

8 PL/SQL階層プロファイラの使用

- PL/SQL階層プロファイラの概要

- プロファイル・データの収集

- RAWプロファイラ出力の理解

- 追跡されるサブプログラムのネームスペース

- 特別な関数名

- プロファイル・データの分析

- 階層プロファイラ表の作成

- 階層プロファイラ表の理解

- 階層プロファイラ・データベース表の列

- オーバーロードされたサブプログラムの区別

- サンプルのPL/SQLプロシージャの階層プロファイラ表

- オプションを使用したDBMS_HPROF.analyzeのコール例

- plshprofユーティリティ

- plshprofのオプション

- 単一のRAWプロファイラ出力ファイルから生成するHTMLレポート

- レポートの最初のページ

- 関数レベルのレポート

- モジュール・レベルのレポート

- ネームスペース・レベルのレポート

- 関数の親子レポート

- 2つのRAWプロファイラ出力ファイルから生成するHTML差分レポート

- 差分レポートの表記規則

- 差分レポートの最初のページ

- 関数レベルの差分レポート

- モジュール・レベルの差分レポート

- ネームスペース・レベルの差分レポート

- 関数の親子差分レポート

9 PL/SQL Webアプリケーションの開発

- PL/SQL Webアプリケーションの概要

- PL/SQL Webアプリケーションの実装

- PL/SQLゲートウェイ

- mod_plsql

- 埋込みPL/SQLゲートウェイ

- PL/SQL Web Toolkit

- mod_plsqlゲートウェイを使用したクライアント・リクエストのPL/SQL Webアプリケーションへのマップ

- 埋込みPL/SQLゲートウェイの使用

- 埋込みPL/SQLゲートウェイによるクライアント・リクエストの処理方法

- 埋込みPL/SQLゲートウェイのインストール

- 埋込みPL/SQLゲートウェイの構成

- 埋込みPL/SQLゲートウェイの構成: 概要

- 埋込みPL/SQLゲートウェイのユーザー認証に関する構成

- 埋込みPL/SQLゲートウェイを介したPL/SQLストアド・サブプログラムの起動

- 埋込みPL/SQLゲートウェイによるアプリケーション・アクセスの保護

- 埋込みPL/SQLゲートウェイの制限事項

- 埋込みPL/SQLゲートウェイの使用: 使用例

- PL/SQLを使用したHTML出力の生成

- PL/SQL Webアプリケーションへのパラメータ渡し

- HTMLフォームからのリスト・パラメータおよびドロップダウン・リスト・パラメータ渡し

- HTMLフォームからのオプション・パラメータおよびチェック・ボックス・パラメータ渡し

- HTMLフォームからの入力フィールド・パラメータ渡し

- HTMLフォームからの非表示パラメータ渡し

- HTMLフォームからのファイルのアップロード

- 記入済HTMLフォームの送信

- HTMLフォームの欠落した入力の処理

- Webページ間での状態情報の保持

- PL/SQLサブプログラムでのネットワーク操作の実行

- PL/SQLからの電子メールの送信

- PL/SQLからのホスト名またはアドレスの取得

- PL/SQLからのTCP/IP接続の使用

- PL/SQLからのHTTP URLコンテンツの取得

- PL/SQLからの表、イメージ・マップ、Cookie、およびCGI変数の使用

10 PL/SQL Server Pages(PSP)の開発

- PL/SQL Server Pagesの概要およびPL/SQL Server Pagesを使用する理由

- PL/SQL Server Pagesを開発してデプロイするための前提条件

- PL/SQL Server PagesおよびHTPパッケージ

- PL/SQL Server Pagesおよびその他のスクリプティング・ソリューション

- PL/SQL Server Pagesの開発

- 基本的なPL/SQL Server Pages特性の指定

- スクリプト言語の指定

- クライアント・ブラウザへのデータの戻し方

- スクリプト・エラーの処理

- ユーザー入力の受入れ

- PL/SQLストアド・プロシージャのネーミング

- 他のファイルのコンテンツの挿入

- PSPスクリプトでのグローバル変数の宣言

- PSPスクリプトでの実行可能文の指定

- PSPスクリプトでの式の値の置換

- PSPスクリプトでの引用符およびエスケープ文字列の使用

- PSPスクリプトへのコメントの挿入

- データベースへのPL/SQL Server Pagesのロード

- PL/SQL Server Pagesソース・コードの問合せ

- URLを介したPL/SQL Server Pagesの実行

- PL/SQL Server Pagesの例

- PL/SQL Server Pagesの例のための設定

- ループを使用したサンプル表の出力

- ユーザー選択の許可

- HTMLフォームを使用したPL/SQL Server Pagesの起動

- PSPファイルへのJavaScriptの挿入

- PL/SQL Server Pagesのデバッグ

- PL/SQL Server Pagesの商品化

11 連続問合せ通知(CQN)の使用

- オブジェクト変更通知(OCN)

- 問合せ結果変更通知(QRCN)

- 保証モード

- ベストエフォート・モード

- 通知を生成するイベント

- DMLトランザクションのコミット

- DDL文のコミット

- 登録解除

- グローバル・イベント

- 通知内容

- CQNに適したアプリケーション

- CQN登録の作成

- PL/SQL CQN登録インタフェース

- CQN登録オプション

- 「通知タイプ」オプション

- QRCNモード(QRCN通知タイプのみ)

- ROWIDオプション

- 操作フィルタ・オプション(OCN通知タイプのみ)

- トランザクション・ラグ・オプション(OCN通知タイプのみ)

- 通知グループ化オプション

- 信頼可能オプション

- 「通知時にパージ」および「タイムアウト」オプション

- CQN登録を作成するための前提条件

- オブジェクト変更通知(OCN)に対して登録可能な問合せ

- 問合せ結果変更通知(QRCN)に対して登録可能な問合せ

- 保証モードでQRCNに対して登録可能な問合せ

- ベストエフォート・モードでのみQRCNに対して登録可能な問合せ

- どちらのモードでもQRCNに対して登録不可能な問合せ

- PL/SQLを介したCQNに対する問合せの登録

- PL/SQL通知ハンドラの作成

- CQ_NOTIFICATION$_REG_INFOオブジェクトの作成

- 通知内の各問合せの識別

- 既存の登録への問合せの追加

- CQN登録のベスト・プラクティス

- CQN登録のトラブルシューティング

- CQN登録の問合せ

- 通知の解析

- CQ_NOTIFICATION$_DESCRIPTORオブジェクトの解析

- CQ_NOTIFICATION$_TABLEオブジェクトの解析

- CQ_NOTIFICATION$_QUERYオブジェクトの解析

- CQ_NOTIFICATION$_ROWオブジェクトの解析

- 登録の削除

- CQNの構成: 使用例

- PL/SQL通知ハンドラの作成

- 問合せの登録

第III部 アプリケーション開発者向けの高度なトピック

12 Oracle Flashback Technologyの使用

- Oracle Flashback Technologyの概要

- アプリケーション開発機能

- データベース管理機能

- Oracle Flashback Technologyに関するデータベースの構成

- 自動UNDO管理に関するデータベースの構成

- Oracle Flashback Transaction Queryに関するデータベースの構成

- フラッシュバック・トランザクションに関するデータベースの構成

- 特定のLOB列に対するOracle Flashback操作の有効化

- 必要な権限の付与

- Oracle Flashback Query(SELECT AS OF)の使用

- 過去のデータの検査およびリストアの例

- Oracle Flashback Queryのガイドライン

- Oracle Flashback Version Queryの使用

- Oracle Flashback Transaction Queryの使用

- Oracle Flashback Transaction QueryとOracle Flashback Version Queryの併用

- DBMS_FLASHBACKパッケージの使用

- フラッシュバック・トランザクションの使用

- 依存トランザクション

- TRANSACTION_BACKOUTパラメータ

- TRANSACTION_BACKOUTレポート

- *_FLASHBACK_TXN_STATE

- *_FLASHBACK_TXN_REPORT

- フラッシュバック・データ・アーカイブの使用(Oracle Total Recall)

- フラッシュバック・データ・アーカイブの作成

- フラッシュバック・データ・アーカイブの変更

- フラッシュバック・データ・アーカイブの削除

- デフォルト・フラッシュバック・データ・アーカイブの指定

- フラッシュバック・データ・アーカイブの有効化および無効化

- フラッシュバック・データ・アーカイブが有効な表のDDL文

- フラッシュバック・データ・アーカイブ・データの表示

- フラッシュバック・データ・アーカイブの使用例

- 使用例: フラッシュバック・データ・アーカイブを使用したデジタル・シュレッディングの実行

- 使用例: フラッシュバック・データ・アーカイブを使用した履歴データへのアクセス

- 使用例: フラッシュバック・データ・アーカイブを使用したレポートの生成

- 使用例: フラッシュバック・データ・アーカイブの監査への使用

- 使用例: フラッシュバック・データ・アーカイブを使用したデータのリカバリ

- Oracle Flashback Technologyの一般ガイドライン

- Oracle Flashback Technologyのパフォーマンス・ガイドライン

13 プログラミング環境の選択

- アプリケーション・アーキテクチャの概要

- クライアント/サーバー・アーキテクチャ

- サーバー側のプログラミング

- 2層アーキテクチャと3層アーキテクチャ

- プログラム・インタフェースの概要

- ユーザー・インタフェース

- ステートフル・ユーザー・インタフェースとステートレス・ユーザー・インタフェース

- PL/SQLの概要

- Oracle Database Javaサポートの概要

- Oracle JVMの概要

- Oracle JDBCの概要

- Oracle JDBCドライバ

- JDBC 2.0のサンプル・プログラム

- JDBC 2.0より前のサンプル・プログラム

- Oracle SQLJの概要

- SQLJのメリット

- サーバー内のSQLJストアド・サブプログラム

- Oracle JDBCとOracle SQLJの比較

- Oracle JPublisherの概要

- Javaストアド・サブプログラムの概要

- Oracle Database Webサービスの概要

- PL/SQLまたはJavaの選択

- PL/SQLとJavaの類似性

- Javaに対するPL/SQLの利点

- PL/SQLに対するJavaの利点

- プリコンパイラの概要

- Pro*C/C++プリコンパイラの概要

- Pro*COBOLプリコンパイラの概要

- OCIおよびOCCIの概要

- OCIおよびOCCIのメリット

- OCIおよびOCCI関数

- OCIおよびOCCIアプリケーションの手続き型要素および非手続き型要素

- OCIアプリケーションまたはOCCIアプリケーションの作成

- プリコンパイラまたはOCIの選択

- Oracle Data Provider for .NET(ODP.NET)の概要

- OraOLEDBの概要

- Oracle Objects for OLE(OO4O)の概要

- OO4Oオートメーション・サーバー

- OO4Oオブジェクト・モデル

- OraSession

- OraServer

- OraDatabase

- OraDynaset

- OraField

- OraMetaDataおよびOraMDAttribute

- OraParameterおよびOraParameters

- OraParamArray

- OraSQLStmt

- OraAQ

- OraAQMsg

- OraAQAgent

- Oracle LOBおよびオブジェクト・データ型のサポート

- OraBLOBおよびOraCLOB

- OraBFILE

- Oracle Data Control

- Oracle Objects for OLE C++クラス・ライブラリ

14 複数のプログラミング言語を使用したアプリケーションの開発

- 複数言語プログラムの概要

- 外部プロシージャの概要

- 外部プロシージャ用のコール仕様の概要

- 外部プロシージャのロード

- Javaクラス・メソッドのロード

- 外部Cプロシージャのロード

- Cプロシージャの定義

- 環境の設定

- DLLを識別する

- 外部プロシージャを公開する

- 外部プロシージャの公開

- Javaクラス・メソッド用のAS LANGUAGE句

- 外部Cプロシージャ用のAS LANGUAGE句

- LIBRARY

- NAME

- LANGUAGE

- CALLING STANDARD

- WITH CONTEXT

- PARAMETERS

- AGENT IN

- Javaクラス・メソッドの発行

- 外部Cプロシージャの発行

- コール仕様の位置

- 例: PL/SQLパッケージ内へのコール仕様の配置

- 例: PL/SQLパッケージ本体内へのコール仕様の配置

- 例: ADT仕様内へのコール仕様の配置

- 例: ADT本体内へのコール仕様の配置

- 例: AUTHIDを指定したJava

- 例: オプションのAUTHIDを指定したC

- 例: パッケージ内でのコール仕様の混合使用

- コール仕様による外部Cプロシージャへのパラメータの受渡し

- データ型の指定

- 外部データ型のマッピング

- BY VALUEまたはBY REFERENCEによるパラメータの受渡し

- 仮パラメータの宣言

- デフォルトのデータ型マッピングのオーバーライド

- プロパティの指定

- INDICATOR

- LENGTHおよびMAXLEN

- CHARSETIDおよびCHARSETFORM

- パラメータの再配置

- SELF

- BY REFERENCE

- WITH CONTEXT

- 言語間のパラメータ・モードのマッピング

- CALL文による外部プロシージャの実行

- 外部プロシージャの事前条件

- 外部プロシージャの権限

- 許可の管理

- 外部プロシージャのシノニムの作成

- CALL文の構文

- Javaクラス・メソッドのコール

- 外部Cプロシージャのコール

- 複数言語のプログラム・エラーおよび例外処理

- 外部Cプロシージャでのサービス・ルーチンの使用

- OCIExtProcAllocCallMemory

- OCIExtProcRaiseExcp

- OCIExtProcRaiseExcpWithMsg

- 外部Cプロシージャを使用したコールバックの実行

- OCIExtProcGetEnv

- OCIコールバック用のオブジェクト・サポート

- コールバックに関する制限事項

- 外部プロシージャのデバッグ

- 例: 外部プロシージャのコール

- 外部Cプロシージャのグローバル変数

- 外部Cプロシージャの静的変数

- 外部Cプロシージャに関する制限事項

15 Oracle XAを使用したアプリケーションの開発

- X/Open DTP

- DTP用語

- 必須のパブリック情報

- Oracle XAライブラリ・サブプログラム

- Oracle XAライブラリ・サブプログラム

- Oracle XAインタフェース拡張機能

- XAアプリケーションの開発およびインストール

- DBAまたはシステム管理者の責任

- アプリケーション開発者の責任

- xa_open文字列の定義

- xa_open文字列の構文

- xa_open文字列の必須フィールド

- xa_open文字列のオプション・フィールド

- プリコンパイラでのOracle XAの使用

- デフォルトのデータベースでのプリコンパイラの使用

- 指定されたデータベースでのプリコンパイラの使用

- OCIでのOracle XAの使用

- Oracle XAを使用したトランザクション制御の管理

- プリコンパイラ・アプリケーションの例

- プリコンパイラまたはOCIアプリケーションのTPMアプリケーションへの移行

- Oracle XAライブラリ・スレッド・セーフティの管理

- オープン文字列でのスレッドの指定

- Oracle XAのスレッドにおける制限事項

- DBMS_XAパッケージの使用

- XAアプリケーションのトラブルシューティング

- Oracle XAトレース・ファイルへのアクセス

- xa_open文字列DbgFl

- トレース・ファイルの位置

- インダウトまたはペンディングのOracle XAトランザクションの管理

- SYSアカウント表を使用したOracle XAトランザクションの監視

- Oracle XAの問題および制限事項

- Oracle XAアプリケーションでのデータベース・リンクの使用

- Oracle XAアプリケーションでのトランザクション・ブランチの管理

- Oracle Real Application Clusters(Oracle RAC)でのOracle XAの使用

- GLOBAL_TXN_PROCESSES初期化パラメータ

- Oracle RACでのトランザクション・ブランチの管理

- Oracle RACでのDTPサービスを使用したインスタンス・リカバリの管理

- Oracle RACのXIDのグローバル一意性

- 密結合と疎結合

- SQLに基づくOracle XAの制限事項

- ロールバックおよびコミット

- DDL文

- セッション状態

- EXEC SQL

- その他の制限事項

16 パブリッシュ・サブスクライブ・モデルでのアプリケーションの開発

- パブリッシュ・サブスクライブ・モデルの概要

- パブリッシュ・サブスクライブのアーキテクチャ

- データベース・イベント

- Oracle Advanced Queuing

- クライアント通知

- パブリッシュ・サブスクライブの概念

- パブリッシュ・サブスクライブ・メカニズムの例

17 識別コード・パッケージの使用

- 識別の概念

- 識別コード・パッケージの概要

- 識別コード・パッケージの使用

- MGD_ID ADTを使用したOracle DatabaseへのRFIDタグの格納

- MGD_ID列型を使用した表の作成と、列へのEPCタグ・エンコーディングの格納

- RFIDタグを表現するMGD_IDオブジェクトの構成

- データベース表へのMGD_IDオブジェクトの挿入

- MGD_ID列型の問合せ

- MGD_ID列型のメンバー関数を使用したファンクション索引の構築

- MGD_ID ADT関数の使用

- MGD_IDオブジェクトとget_component関数の使用

- 標準的な表現からのタグ・データの解析

- フィールドからのタグ表現の再構成

- タグ表現間の翻訳

- 識別コードのカテゴリの定義と既存のカテゴリへのコード体系の追加

- 識別コードのカテゴリの作成

- 新規作成したカテゴリへの2つのメタデータ・スキームの追加

- 識別コード・パッケージ・タイプ

- DBMS_MGD_ID_UTLパッケージ

- 識別コード・メタデータ表およびビュー

- 電子製品コード(EPC)の概念

- RFIDテクノロジとEPCバージョン1.1コード体系

- 製品コードの概念と現在の使用

- 電子製品コード(EPC)

- Global Trade Identification Number(GTIN)およびSerializable Global Trade Identification Number(SGTIN)

- Serial Shipping Container Code(SSCC)

- Global Location Number(GLN)およびSerializable Global Location Number(SGLN)

- Global Returnable Asset Identifier(GRAI)

- Global Individual Asset Identifier(GIAI)

- RFID EPCネットワーク

- Oracle Database Tag Data Translationスキーマ

18 スキーマ・オブジェクトの依存性

- スキーマ・オブジェクトの依存性の概要

- オブジェクトの依存性の問合せ

- オブジェクトのステータス

- 依存オブジェクトの無効化

- セッションの状態と参照パッケージ

- セキュリティ認可

- 無効化を回避するためのガイドライン

- パッケージの最後へのアイテムの追加

- ビューを介した各表の参照

- オブジェクトの再有効化

- スキーマの範囲内での名前解決

- ローカル依存性の管理

- リモート依存性の管理

- ローカル・データベース・プロシージャとリモート・データベース・プロシージャの間の依存性

- その他のリモート・オブジェクト間の依存性

- アプリケーションの依存性

- リモート・プロシージャ・コール(RPC)の依存性管理

- タイムスタンプ依存性モード

- RPCシグネチャ依存性モード

- パラメータの名前とデフォルト値の変更

- パラメータ・モードINの指定の変更

- サブプログラム本体の変更

- パラメータのデータ型クラスの変更

- パッケージ・タイプの変更

- 依存性モードの制御

- 依存性の解決

- 依存性管理の提案

- 共有SQLの依存性管理

19 エディションベースの再定義

- エディション

- エディション・オブジェクトと非エディション・オブジェクト

- エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ

- エディション・オブジェクトの規則

- ユーザーに対するエディションの有効化

- エディションの作成

- 継承オブジェクトと実オブジェクト

- 継承オブジェクトの削除

- 参照されているオブジェクトの実オブジェクト化

- 一部のユーザーに対してエディションを使用可能にする

- すべてのユーザーに対してエディションを使用可能にする

- 現行エディションとセッション・エディション

- 最初のセッション・エディション

- セッション・エディションの変更

- 現行エディション名とセッション・エディション名の表示

- 現行エディションがセッション・エディションと異なる状況

- エディションのリタイア

- エディションの削除

- エディショニング・ビュー

- エディショニング・ビューの作成

- パーティション拡張エディショニング・ビュー名

- エディショニング・ビューの書込み可能性の変更

- エディショニング・ビューの置換

- 実表の削除または名前変更

- 実表への索引と制約の追加

- SQLオプティマイザ索引ヒント

- crosseditionトリガー

- forward crosseditionトリガー

- reverse crosseditionトリガー

- crosseditionトリガーとエディションの相互作用

- 表示可能なトリガー

- 起動できるトリガーの種類

- 起動順序

- crosseditionトリガーの実行

- crosseditionトリガーの作成

- forward crosseditionトリガー本体のコーディング

- アップグレード前の表現をアップグレード後の表現に変換

- 更新内容の消失の防止

- crosseditionトリガーの削除

- エディション、エディショニング・ビュー、crosseditionトリガーの情報の表示

- アプリケーションをアップグレードするためのエディションベースの再定義の使用

- アプリケーションでのエディショニング・ビューの使用準備

- エディションのみを使用するエディションベースの再定義の手順

- エディショニング・ビューを使用するエディションベースの再定義の手順

- crosseditionトリガーを使用するエディションベースの再定義の手順

- アプリケーション・アップグレードのロールバック

- 使用されていない表の列が占める領域の再利用

- 例: アプリケーションをアップグレードするためのエディションベースの再定義の使用

- 既存のアプリケーション

- アプリケーションでのエディショニング・ビューの使用準備

- アプリケーションをアップグレードするためのエディションベースの再定義の使用

A マルチスレッドextprocエージェント

- マルチスレッドextprocエージェントを使用する理由

- 専用エージェント・アーキテクチャの課題

- マルチスレッド化のメリット

- マルチスレッドextprocエージェントのアーキテクチャ

- 監視スレッド

- ディスパッチャ・スレッド

- タスク・スレッド

- マルチスレッドextprocエージェントの管理

- エージェント制御ユーティリティ(agtctl)のコマンド

- 単一行コマンド・モードでのagtctlの使用

- マルチスレッドextprocエージェントの構成パラメータの設定

- マルチスレッドextprocエージェントの起動

- マルチスレッドextprocエージェントの停止

- 構成パラメータの値の確認

- 構成パラメータのデフォルト値へのリセット

- 制御ファイルからの特定のSIDのエントリの削除

- ヘルプのリクエスト

- シェル・モード・コマンドの使用

- 例: 構成パラメータの設定

- 例: マルチスレッドextprocエージェントの起動

- マルチスレッドextprocエージェント制御用の構成パラメータ

索引

例一覧

- 1-1 デフォルト以外の書式での現在の日付および時刻の表示

- 1-2 デフォルト以外の書式での日付の挿入および表示

- 1-3 デフォルト以外の書式での日付および時刻の挿入および表示

- 1-4 SYS.ANYDATA列の情報へのアクセス

- 1-5 ROWID擬似列の問合せ

- 2-1 SHARE MODEでのLOCK TABLE

- 2-2 Pro*COBOLプリコンパイラによるロックの使用方法

- 2-3 パッケージ・サブプログラムの自律型としてのマーク

- 2-4 AFTER SUSPENDトリガーによる一時停止された記憶域割当ての処理

- 3-1 正規表現を使用した電話番号書式の規定

- 3-2 正しい書式と誤った書式での電話番号の挿入

- 3-3 後方参照を使用した文字の再配置

- 4-1 算術式の事前計算用のファンクション索引

- 4-2 オブジェクト列でのファンクション索引

- 4-3 大/小文字を区別しないより高速の検索用のファンクション索引

- 4-4 言語依存ソート用のファンクション索引

- 5-1 制約を使用したビジネス・ルールの施行

- 5-2 制約とアプリケーション・コードの両方を使用したビジネス・ルールの施行

- 5-3 NOT NULL制約がある列へのNULL値の挿入

- 5-4 制約チェックの遅延

- 5-5 CREATE TABLE文を使用した制約の定義

- 5-6 ALTER TABLE文を使用した制約の定義

- 5-7 制約を使用可能にする

- 5-8 制約を使用禁止にする

- 5-9 既存の制約を使用可能にする

- 5-10 既存の制約を使用禁止にする

- 5-11 制約の変更

- 5-12 制約名の変更

- 5-13 制約の削除

- 5-14 制約に関する情報の表示

- 6-1 無名ブロック

- 6-2 事前定義されたエラーの例外ハンドラを持つ無名ブロック

- 6-3 ユーザー定義例外の例外ハンドラを持つ無名ブロック

- 6-4 パラメータを使用するストアド・プロシージャ

- 6-5 %TYPEおよび%ROWTYPE属性

- 6-6 PL/SQLパッケージの作成とパッケージ・サブプログラムの起動

- 6-7 ORA-04068の呼び出し

- 6-8 ORA-04068の検出

- 6-9 コレクションを参照するDML文

- 6-10 コレクションを参照するSELECT文

- 6-11 コレクションを参照しDMLを返すFORループ

- 6-12 カーソル変数を使用するデータのフェッチ

- 6-13 識別子を使用したカーソル変数

- 6-14 コンパイル時のエラー

- 6-15 SQL*Plusを使用した対話形式によるサブプログラムの起動

- 6-16 SQL*Plusを使用したセッション変数の作成と使用

- 6-17 別のサブプログラムからのサブプログラムの起動

- 6-18 SQL式でのPL/SQLファンクション(規則に従った場合)

- 6-19 SQL式でのPL/SQLファンクション(規則への例外がある場合)

- 6-20 PRAGMA RESTRICT_REFERENCES

- 6-21 起動される側にTRUSTが指定されたPRAGMA RESTRICT REFERENCES

- 6-22 起動する側にTRUSTが指定されたPRAGMA RESTRICT REFERENCES

- 6-23 PRAGMA RESTRICT_REFERENCESを含むパッケージ・ファンクションのオーバーロード

- 7-1 STANDARDおよびDBMS_STANDARDのPL/Scope識別子データの有無

- 7-2 PL/Scopeデータによる領域の使用量

- 7-3 USAGE_CONTEXT_IDおよびUSAGE_ID

- 7-4 名前がpの2つの識別子を持つプログラム・ユニット

- 8-1 PL/SQLプロシージャのプロファイリング

- 8-2 DBMS_HPROF.analyzeの起動

- 8-3 サンプルのPL/SQLプロシージャのDBMSHP_RUNS表

- 8-4 サンプルのPL/SQLプロシージャのDBMSHP_FUNCTION_INFO表

- 8-5 サンプルのPL/SQLプロシージャのDBMSHP_PARENT_CHILD_INFO表

- 8-6 オプションを使用したDBMS_HPROF.analyzeの起動

- 9-1 DADの作成および構成

- 9-2 後で作成または変更されるDADの認証

- 9-3 DADの認証モードの決定

- 9-4 全DADの認証モードの表示

- 9-5 無効なDAD認可の表示

- 9-6 例9-1のepgstat.sqlスクリプトの出力

- 9-7 HTPファンクションを使用したHTMLタグの生成

- 9-8 HTP.PRINTを使用したHTMLタグの生成

- 9-9 HTMLドロップダウン・リスト

- 9-10 HTMLフォームからの入力フィールド・パラメータ渡し

- 9-11 PL/SQLからの電子メールの送信

- 9-12 PL/SQLからのHTTP URLコンテンツの取得

- 10-1 simple.psp

- 10-2 戻されるHTMLページのサンプル

- 10-3 simplewithuserinput.psp

- 10-4 PSPファイル内のサンプル・コメント

- 10-5 PL/SQL Server Pagesのロード

- 10-6 PL/SQL Server Pageソース・コードの問合せ

- 10-7 show_prod_simple.psp

- 10-8 show_catalog_raw.psp

- 10-9 show_catalog_pretty.psp

- 10-10 show_product_partial.psp

- 10-11 show_product_highlighed.psp

- 10-12 product_form.psp

- 10-13 show_product_javascript.psp

- 11-1 変更通知として登録される問合せ

- 11-2 保証モードのQRCNに対して複雑すぎる問合せ

- 11-3 簡略バージョンによってオブジェクトが無効になる問合せ

- 11-4 CQ_NOTIFICATION$_REG_INFOオブジェクトの作成

- 11-5 既存の登録への問合せの追加

- 11-6 サーバー側PL/SQL通知ハンドラの作成

- 11-7 問合せの登録

- 12-1 Oracle Flashback Queryを使用した失われた行の取得

- 12-2 Oracle Flashback Query後の失われた行のリストア

- 13-1 Pro*C/C++アプリケーション

- 13-2 Pro*COBOLアプリケーション

- 15-1 xa_open文字列

- 15-2 オープン文字列構成のサンプル

- 15-3 アプリケーション・サーバーによって開始されるトランザクション

- 15-4 アプリケーション・クライアントによって開始されるトランザクション

- 15-5 DBMS_XAパッケージの使用

- 18-1 依存オブジェクト・タイプと参照オブジェクト・タイプの表示

- 18-2 一部の依存オブジェクトを無効にするスキーマ・オブジェクトの変更

- 18-3 複数のオブジェクトに依存するビュー

- 18-4 プロシージャget_hire_dateの本体の変更

- 18-5 get_hire_dateパラメータのデータ型クラスの変更

- 18-6 パッケージ・レコード型のフィールド名の変更

- 19-1 継承オブジェクトと実オブジェクト

- 19-2 継承オブジェクトの削除

- 19-3 削除済継承オブジェクトの名前を使用したオブジェクトの作成

- 19-4 セッション・エディションと異なる現行エディション

- 19-5 データ変換の衝突に対応するcrosseditionトリガー

- 19-6 非常に単純なプロシージャのエディションベースの再定義

- 19-7 既存のアプリケーションの作成

- 19-8 既存の表のデータ表示

- 19-9 既存の表のエディショニング・ビューの作成

- 19-10 アプリケーションをアップグレードするエディションの作成

- 19-11 表の変更とエディショニング・ビューの置換

- 19-12 crosseditionトリガーの作成と有効化

- 19-13 トランスフォームの適用

- 19-14 変更された表のデータ表示

- A-1 構成パラメータの設定とagtctlの起動

図一覧

- 2-1 シリアライズ可能トランザクションと別のトランザクションの相互作用

- 2-2 参照整合性チェック

- 2-3 トランザクション制御フロー

- 2-4 自律型トランザクションの順序

- 2-5 例: 購買指示

- 2-6 預金払戻し - 十分な預金残高がある場合

- 2-7 預金払戻し - 貸越し保護があり預金残高が不十分な場合

- 2-8 預金払戻し - 貸越し保護がなく預金残高が不十分な場合

- 5-1 UNIQUE制約に違反および一意制約を満たす行

- 5-2 FOREIGN KEY制約に違反およびFOREIGN KEY制約を満たす行

- 6-1 例外およびユーザー定義エラー

- 9-1 PL/SQL Webアプリケーション

- 9-2 埋込みPL/SQLゲートウェイによるクライアント・リクエストの処理

- 11-1 中間層キャッシュ

- 11-2 連続問合せ通知(CQN)の基本プロセス

- 13-1 OCIまたはOCCIの開発過程

- 13-2 ソフトウェア・レイヤー

- 13-3 オブジェクトおよびそのリレーション

- 13-4 サポートされているOracle Databaseデータ型

- 14-1 Oracle Databaseと外部プロシージャ

- 15-1 DTPモデルの例

- 16-1 Oracleのパブリッシュ・サブスクライブの機能

- 17-1 RFIDコード・カテゴリおよびそのスキーム

- 17-2 Oracle Database Tag Data Translationマークアップ言語スキーマ図

- A-1 マルチスレッドextprocエージェントのアーキテクチャ

表一覧

- 1-1 SQL文字データ型

- 1-2 浮動小数点2進形式の構成要素

- 1-3 2進形式の記憶域パラメータの概要

- 1-4 浮動小数点データ型の範囲および精度

- 1-5 ネイティブ浮動小数点形式の特殊な数値

- 1-6 例外により生成される値

- 1-7 SQL日時データ型

- 1-8 日時データ型のSQL変換関数

- 1-9 ラージ・オブジェクト(LOB)

- 1-10 SQL関数の表示タイプ

- 1-11 データ型ファミリ

- 2-1 COMMIT文のオプション

- 2-2 COMMIT、SAVEPOINTおよびROLLBACKの使用方法

- 2-3 明示的なロックにおける同時実行性の例

- 2-4 ロック情報の表示方法

- 2-5 ANSI/ISO SQL分離レベルおよび可能なトランザクションの相互作用

- 2-6 Oracle Databaseで用意されるANSI/ISO SQL分離レベル

- 2-7 READ COMMITTEDトランザクションとSERIALIZABLEトランザクションの比較

- 2-8 トランザクションの結果

- 3-1 Oracle SQLパターン一致条件および関数

- 3-2 Oracle SQLパターン一致条件および関数のパターン一致オプション

- 3-3 Oracle SQL正規表現内のPOSIX演算子

- 3-4 POSIX演算子と多言語演算子の関係

- 3-5 Oracle SQL正規表現でPERLの影響を受ける演算子

- 3-6 例3-1の正規表現要素の説明

- 3-7 例3-3の正規表現要素の説明

- 6-1 サブプログラム・パラメータの属性

- 7-1 PL/Scopeが収集する識別子の型

- 7-2 PL/Scopeがレポートする使用方法

- 8-1 RAWプロファイラ出力ファイルのインジケータ

- 8-2 PL/SQL階層プロファイラによって追跡される操作の関数名

- 8-3 PL/SQL階層プロファイラ・データベース表

- 8-4 DBMSHP_RUNS表の列

- 8-5 DBMSHP_FUNCTION_INFO表の列

- 8-6 DBMSHP_PARENT_CHILD_INFO表の列

- 9-1 PL/SQL Web Toolkitで一般的に使用されるパッケージ

- 9-2 mod_plsqlと埋込みPL/SQLゲートウェイDAD属性間のマッピング

- 9-3 mod_plsqlと埋込みPL/SQLゲートウェイ・グローバル属性間のマッピング

- 9-4 DADの認証の可能性

- 10-1 PSP要素

- 11-1 連続問合せ通知登録オプション

- 11-2 CQ_NOTIFICATION$_REG_INFOの属性

- 11-3 サービスのクオリティ・フラグ

- 11-4 CQ_NOTIFICATION$_DESCRIPTORの属性

- 11-5 CQ_NOTIFICATION$_TABLEの属性

- 11-6 CQ_NOTIFICATION$_QUERYの属性

- 11-7 CQ_NOTIFICATION$_ROWの属性

- 12-1 Oracle Flashback Version Queryにおける行データ疑似列

- 12-2 フラッシュバックTRANSACTION_BACKOUTオプション

- 12-3 フラッシュバック・データ・アーカイブ・ファイルの静的データ・ディクショナリ・ビュー

- 13-1 PL/SQLパッケージおよび相当するJavaでの操作

- 14-1 パラメータ・データ型のマッピング

- 14-2 外部データ型のマッピング

- 14-3 プロパティおよびデータ型

- 15-1 Oracle Databaseが発行する必要のあるXA機能

- 15-2 XAライブラリ・サブプログラム

- 15-3 Oracle XAインタフェース拡張機能

- 15-4 xa_open文字列の必須フィールド

- 15-5 xa_open文字列のオプション・フィールド

- 15-6 TXインタフェース関数

- 15-7 TPM用に置き換える文

- 15-8 サンプル・トレース・ファイルの内容

- 15-9 密結合および疎結合トランザクション・ブランチ

- 17-1 EPCエンコーディングの一般的な構造

- 17-2 識別コード・パッケージADT

- 17-3 MGD_ID ADTサブプログラム

- 17-4 DBMS_MGD_ID_UTLパッケージ・ユーティリティ・サブプログラム

- 17-5 MGD_ID_CATEGORYメタデータ・ビューの定義と説明

- 17-6 USER_MGD_ID_CATEGORYメタデータ・ビューの定義と説明

- 17-7 MGD_ID_SCHEMEメタデータ・ビューの定義と説明

- 17-8 USER_MGD_ID_SCHEMEメタデータ・ビューの定義と説明

- 18-1 データベース・オブジェクトのステータス

- 18-2 高度な無効化が発生する操作

- 18-3 データ型クラス

- 19-1 エディション情報を含む*_ディクショナリ・ビュー

- 19-2 エディショニング・ビュー情報を含む*_ディクショナリ・ビュー

- A-1 エージェント制御ユーティリティ(agtctl)のコマンド

- A-2 agtctlの構成パラメータ

はじめに

『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』では、経験豊富なアプリケーション開発者が頻繁に参照する内容について説明します。このマニュアルの内容は、サポートされるすべてのプラットフォーム上で同様に動作する機能に適用されるもので、システム固有の情報は含みません。

内容は次のとおりです。

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

対象読者

『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』は、アプリケーションの開発や、Oracle Database環境で実行できるようにアプリケーションの変換を行うアプリケーション開発者を対象にしています。このマニュアルは、システム・アナリストやプロジェクト管理者など、データベース・アプリケーション開発に関心があるすべての方にも役立ちます。

このマニュアルを使用するには、次に関する実践的な知識が必要です。

- アプリケーション・プログラミング

- Structured Query Language(SQL)

- オブジェクト指向プログラミング

ドキュメントのアクセシビリティについて

Oracleのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイトhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=docaccを参照してください。

Oracleサポートへのアクセス

サポートをご購入のOracleのお客様は、My Oracle Supportにアクセスして電子サポートを受けることができます。詳細情報はhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=infoか、聴覚に障害のあるお客様はhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trsを参照してください。

関連ドキュメント

詳細は、Oracle Database 11gリリース2ドキュメント・セットの次のドキュメントを参照してください。

- 『Oracle Database PL/SQL言語リファレンス』

- 『Oracle Call Interfaceプログラマーズ・ガイド』

- 『Oracle Databaseセキュリティ・ガイド』

- 『Pro*C/C++プログラマーズ・ガイド』

- 『Oracle Database SQL言語リファレンス』

- 『Oracle Database管理者ガイド』

- 『Oracle Database概要』

- 『Oracle XML Developer's Kitプログラマーズ・ガイド』

- 『Oracle XML DB開発者ガイド』

- 『Oracle Databaseグローバリゼーション・サポート・ガイド』

- 『Oracle Databaseサンプル・スキーマ』

参照:

- 『Oracle PL/SQL Tips and Techniques』、Joseph C.Trezzo著。Oracle Press、1999年。

- 『Oracle PL/SQL Programming』、Steven Feuerstein著、3rd Edition。O'Reilly & Associates、2002年。

- 『Oracle PL/SQL Developer's Workbook』、Steven Feuerstein著。O'Reilly & Associates、2000年。

- 『Oracle PL/SQL Best Practices』、Steven Feuerstein著。O'Reilly & Associates、2001年。

表記規則

このマニュアルでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック体

イタリックは、ドキュメントのタイトル、強調またはユーザーが特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

付記:

- *_viewは、名前がviewで終わるすべての静的データ・ディクショナリ・ビューを示します。たとえば、*_ERRORSは、ALL_ERRORS、DBA_ERRORSおよびUSER_ERRORSを示します。静的データ・ディクショナリ・ビューの詳細または概要は、『Oracle Databaseリファレンス』を参照してください。

- スキーマ名で修飾されていない表名は、サンプル・スキーマHRにあります。サンプル・スキーマの詳細は、『Oracle Databaseサンプル・スキーマ』を参照してください。

アプリケーション開発のための新機能

ここでは、このマニュアルで扱うOracle Databaseの新機能を簡単に説明し、詳細情報へのリンクを示します。

内容は次のとおりです。

- Oracle Database 11gリリース2 (11.2.0.4)の機能

- Oracle Database 11gリリース2 (11.2.0.2)の機能

- Oracle Database 11gリリース2の機能

- Oracle Database 11gリリース1の機能

Oracle Database 11gリリース2 (11.2.0.4)の機能

フラッシュバック・データ・アーカイブの履歴表の最適化

リリース11.2.0.4までは、フラッシュバック・データ・アーカイブを作成または変更する際に、対応する履歴表の最適化を無効化できませんでした。

リリース11.2.0.4では、フラッシュバック・データ・アーカイブを作成または変更する際、CREATE FLASHBACK ARCHIVE文またはALTER FLASHBACK ARCHIVE文のOPTIMIZE DATA句を使用して対応する履歴表の最適化を有効化または無効化できます。詳細は、「フラッシュバック・データ・アーカイブの作成」および「Oracle Flashback Technologyの一般ガイドライン」を参照してください。

Oracle Database 11gリリース2 (11.2.0.2)の機能

データベース・サービスのエディション属性

リリース11.2.0.2までは、データベース・サービスを使用してOracle Databaseに接続するときに、初期セッション・エディションを指定できませんでした。ホット・ロールオーバーのためにエディションベースの再定義を使用する場合、アップグレード前のエディションを使用するデータベース・クライアントと、アップグレード後のエディションを使用するデータベース・クライアントがあれば、クライアント・コードを変更する必要がありました。

リリース11.2.0.2では、データベース・サービスの属性として初期セッション・エディションを指定できます。これにより、さらに容易に、各セッションがホット・ロールオーバー中に目的のエディションを確実に使用することができるようになります。詳細は、「初期セッション・エディション」を参照してください。

リリース11.2.0.2では、各*_SERVICES静的データ・ディクショナリ・ビューに、デフォルトの初期セッション・エディションを表示するEDITION列が含まれます。詳細は、「エディション、エディショニング・ビューおよびCrosseditionトリガーの情報の表示」を参照してください。

Oracle Database 11gリリース2の機能

Oracle Database 11gリリース2でのOracle Databaseの機能は、次のとおりです。

- トランザクションのフラッシュバック外部キー依存性のトラッキング

- トリガーの高度な無効化

- エディションベースの再定義

- APPLYING_CROSSEDITION_TRIGGERファンクション

- IGNORE_ROW_ON_DUPKEY_INDEXヒント

- CHANGE_DUPKEY_ERROR_INDEXヒント

- DBMS_PARALLEL_EXECUTEパッケージ

- IPv6(Internet Protocol version 6)のサポート

トランザクションのフラッシュバック外部キー依存性のトラッキング

CASCADEオプションを使ったトランザクションのフラッシュバック(DBMS_FLASHBACK.TRANSACTION_BACKOUTプロシージャ)では、データベースがオンラインである間にトランザクションおよびその依存トランザクションがロールバックされます。

Oracle Database 11gリリース2以前、トランザクションのフラッシュバックでは、外部キーの依存性は追跡されませんでした。したがって、CASCADEオプションを付けてトランザクションのフラッシュバックを使用し、外部キーに依存しているトランザクションをロールバックしようとすると、外部キー違反エラーが発生しました。これを回避するには、ロールバックするトランザクションのリストに外部キー依存トランザクションを含める必要がありました。

Oracle Database 11gリリース2以降、CASCADEオプションを付けてトランザクションのフラッシュバックを使用する場合、ロールバックされるトランザクションのリストに依存トランザクションを入れる必要はありません。

トランザクションのフラッシュバックにおける外部キー依存性を追跡するには、外部キーのサプリメンタル・ロギングを有効化する必要があります。手順は、「フラッシュバック・トランザクションに関するデータベースの構成」を参照してください。トランザクションのフラッシュバックの詳細は、「フラッシュバック・トランザクションの使用」を参照してください。

トリガーの高度な無効化

Oracle Database 11gリリース1の機能である「高度な無効化」がトリガーにも拡張されています。

エディションベースの再定義

エディションベースの再定義を使用すると、アプリケーションの使用中にそのデータベース・コンポーネントをアップグレードでき、停止時間を最小化あるいは排除することができます。

使用中にアプリケーションをアップグレードするには、アプリケーションを構成するデータベース・オブジェクトをコピーし、コピーしたオブジェクトを分離した状態で再定義します。変更内容はアプリケーションのユーザーには影響しません。ユーザーは変更されていないアプリケーションの実行を継続します。変更内容が正しいことを確認したら、アップグレードしたアプリケーションをすべてのユーザーが使用できるようにします。

エディションベースの再定義では、1つ以上のコンポーネント機能を使用します。使用する機能と停止時間は次の要素によって異なります。

- 再定義するデータベース・オブジェクトの種類

- データベース・オブジェクトの再定義中に、ユーザーがそのデータベース・オブジェクトをどの程度使用できるか

- 以前のアプリケーションを使用しているユーザーがいるときに、アップグレードしたアプリケーションを他のユーザーが使用できるようにするかどうか

エディション機能は常に使用します。これにより、データベース・オブジェクトをコピーして、コピーしたオブジェクトを分離して再定義することができます。

1つ以上の表の構造を変更する場合は、エディショニング・ビュー機能も使用します。

表の構造を変更している間、他のユーザーがその表のデータを変更する必要がある場合は、forward crosseditionトリガーも使用します。アップグレード前のアプリケーションとアップグレード後のアプリケーションが同時に通常使用(ホット・ロールオーバー)されている場合、reverse crosseditionトリガーも使用します。crosseditionトリガーはアプリケーションの永続的な要素ではありません。全ユーザーがアップグレード後のアプリケーションを使用するようになったら削除します。

詳細は、第19章「エディションベースの再定義」を参照してください。

APPLYING_CROSSEDITION_TRIGGERファンクション

forward crosseditionトリガーの本体はデータ変換の衝突を処理する必要があります。衝突処理方法がトリガーの実行理由に応じて変わる場合、その理由は、パッケージDBMS_STANDARDで定義されているファンクションAPPLYING_CROSSEDITION_TRIGGERにより判断できます。

詳細は、「データ変換における衝突の処理」を参照してください。

IGNORE_ROW_ON_DUPKEY_INDEXヒント

INSERT INTO target subquery形式の文を実行すると、挿入される一部の行に対する一意キーが既存の行と衝突する可能性があります。アプリケーションはこのような衝突を無視する必要があると仮定し、既存の行と衝突しない行を挿入します。

Oracle Database 11gリリース2以前、DUP_VAL_ON_INDEX例外用のNULLハンドラを持つブロックに、ソース行を選択し、これらを一度に1つずつターゲットに挿入するPL/SQLプログラムを書く必要がありました。

Oracle Database 11gリリース2では、PL/SQLプログラムを書く必要はありません。INSERT文で、より記述しやすく、実行も早いIGNORE_ROW_ON_DUPKEY_INDEXヒントを使用できます。このヒントはcrosseditionトリガーを実装するときに特に便利です。

詳細は、「データ変換における衝突の処理」を参照してください。

CHANGE_DUPKEY_ERROR_INDEXヒント

INSERTまたはUPDATE文を実行した時に、一意キーが既存の行と衝突する可能性があります。

Oracle Database 11gリリース2以前、この衝突はエラーORA-00001の原因でした。衝突が発生したことはわかりましたが、どこで発生したかはわかりませんでした。

Oracle Database 11gリリース2以降、INSERTまたはUPDATE文でCHANGE_DUPKEY_ERROR_INDEXヒントを使用し、指定された索引または列セットで一意キー違反が発生したときに、ORA-00001のかわりにORA-38911が表示されるようにすることができます。このヒントはcrosseditionトリガーを実装するときに特に便利です。

詳細は、「データ変換における衝突の処理」を参照してください。

DBMS_PARALLEL_EXECUTEパッケージ

DBMS_PARALLEL_EXECUTEパッケージを使用すると、大容量の表のデータを並列で増分的に更新することができます。これは次の2つの手順で行われます。

1. 表の行をグループ化して小さなチャンクに分けます。

2. 必要なUPDATE文を並列でチャンクに適用し、1チャンクの処理が終了するたびにコミットします。

この方法では、パフォーマンスが向上し、ロールバックによる領域消費が削減され、保持される行ロック数が削減されます。たとえばforward crosseditionトリガーの適用など、大量のデータを更新するときは常にDBMS_PARALLEL_EXECUTEパッケージを使用してください。

詳細は、「アップグレード前の表現をアップグレード後の表現に変換」を参照してください。

IPv6(Internet Protocol version 6)のサポート

IPv6(Internet Protocol version 6)では、IPv4に比べてかなり大きなアドレス空間がサポートされます。IPv6アドレスは128ビットですが、IPv4アドレスは32ビットです。

ネットワーク・アドレスを使用するアプリケーションでは、IPv6アドレスを処理するために、わずかな変更と再コンパイルが必要になる場合があります。詳細は、「PL/SQLサブプログラムでのネットワーク操作の実行」を参照してください。

マルチスレッドextprocエージェントを起動するエージェント制御ユーティリティagtctlは、IPv6アドレスを受け入れるようになりました。詳細は、「マルチスレッドextprocエージェント制御用の構成パラメータ」を参照してください。

参照:
Oracle DatabaseでのIPv6サポートの詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。

Oracle Database 11gリリース1の機能

Oracle Database 11gリリース1でのアプリケーション開発機能は、次のとおりです。

- データ定義言語(DDL)文のWAITオプション

- Oracle XML DatabaseのバイナリXMLのサポート

- SQL演算子と関数のメタデータ

- 正規表現SQL関数への拡張機能

- 非表示の索引

- PL/SQLファンクション結果キャッシュ

- PL/SQL式の順序

- PL/Scope

- PL/SQL階層プロファイラ

- 問合せ結果変更通知

- フラッシュバック・トランザクション

- フラッシュバック・データ・アーカイブ(Oracle Total Recall)

- PL/SQL内で使用可能なXA API

- Oracle Real Application Clusters(Oracle RAC)でのXA/JTAのサポート

- 識別コード・パッケージ

- オンライン索引作成および再構築の機能拡張

- 埋込みPL/SQLゲートウェイ

- デフォルトでマルチスレッド・エージェントextprocを直接起動するOracle Database

- 高度な無効化

データ定義言語(DDL)文のWAITオプション

DDL文では内部構造に対する排他ロックを必要とします。DDL文の発行時にこれらのロックが使用できない場合、そのDDL文は失敗します。ただし、発行がサブセカンド後であれば成功していた可能性があります。SQL文LOCK TABLEのWAITオプションによって、DDL文は指定された期間ロックを待機して、失敗を避けることができます。

詳細は、「ロック方法の選択」を参照してください。

Oracle XML DatabaseのバイナリXMLのサポート

バイナリXMLは、XML文書を表す第3の方法です。バイナリXMLは、既存のオブジェクト・リレーショナル記憶域およびCLOB記憶域表現を置換するのではなく補足します。バイナリXMLには2つの重要なメリットがあります。

- XMLスキーマが使用できるかどうかに関係なく、XML操作が大幅に最適化されます。

- XMLの内部表現が、ディスク上、メモリー内、およびワイヤ上で同一です。

他の記憶域メカニズムと同様、バイナリXML記憶域の詳細は透過的です。継続してXMLTypeおよびその関連メソッドおよび演算子を使用します。

詳細は、「XMLデータの表現」を参照してください。

参照:
『Oracle XML DB開発者ガイド』

SQL演算子と関数のメタデータ

SQL演算子および関数のメタデータは、動的パフォーマンス(V$)ビューを介してアクセス可能です。サード・パーティのツールは、アプリケーション・レイヤーのメタデータをメンテナンスすることなくSQL関数を活用できます。

詳細は、「SQL演算子および関数のメタデータ」を参照してください。

正規表現SQL関数への拡張機能

正規表現SQL関数REGEXP_INSTRおよびREGEXP_SUBSTRでは、機能が強化されています。新しい正規表現SQL関数REGEXP_COUNTでは、文字列にパターンが出現する回数が戻されます。このファンクションはSQLおよびPL/SQLでの場合と同じ働きをします。

詳細は、「Oracle SQLの正規表現のサポート」を参照してください。

参照:
『Oracle Database SQL言語リファレンス』

非表示の索引

非表示の索引は、すべてのデータ操作言語(DML)文でOracle Databaseによってメンテナンスされますが、セッションまたはシステム・レベルで明示的にパラメータOPTIMIZER_USE_INVISIBLE_INDEXESをTRUEに設定しないかぎりは、オプティマイザによって無視されます。

索引を非表示にするのは、使用禁止または削除の代替手段です。非表示の索引を使用すると、次のことができます。

- 索引を実際に削除する前にそのテストをします。

- 既存のアプリケーションの動作に影響を及ぼすことなく、オンライン・アプリケーションのアップグレードなど、特殊な標準外操作用に一時的に非表示の索引を作成します。

詳細は、『Oracle Database管理者ガイド』を参照してください。

PL/SQLファンクション結果キャッシュ

Oracle Database 11gリリース1より前は、PL/SQLアプリケーションにファンクションの結果をキャッシュさせた場合、キャッシュおよびキャッシュ管理のサブプログラムを設計およびコーディングする必要がありました。複数セッションでアプリケーションを実行する場合、各セッションではそのキャッシュおよびキャッシュ管理のサブプログラム・コピーが必要でした。各セッションで同じ高価な演算を実行する必要がある場合もありました。

Oracle Database 11gリリース1では、PL/SQLはファンクション結果キャッシュを提供します。ファンクション結果キャッシュは共有グローバル領域(SGA)に格納されるため、アプリケーションが実行されるすべてのセッションで使用可能です。

詳細は、「PL/SQLファンクション結果キャッシュ」を参照してください。

参照:
『Oracle Database PL/SQL言語リファレンス』

PL/SQL式の順序

疑似列CURRVALおよびNEXTVALによって、PL/SQLソース・コードの記述が容易になり、実行時のパフォーマンスおよびスケーラビリティが向上します。NUMBER式が使用できる場所であればどこにでも、sequence_name.CURRVALおよびsequence_name.NEXTVALを使用できます。

例6-6を参照してください。

参照:
『Oracle Database PL/SQL言語リファレンス』

PL/Scope

PL/Scopeはコンパイラ駆動方式のツールであり、PL/SQLソース・コードからユーザー定義の識別子に関するデータを収集して構成します。PL/Scopeはコンパイラ駆動方式のツールであるため、直接使用するのではなく、対話型の開発環境(SQL DeveloperやJDeveloperなど)を介して使用します。

PL/Scopeによって、強力で効率的なPL/Scopeソース・コード・ブラウザの開発が可能になります。このブラウザは、ソース・コードの参照および理解に費やされる時間を最小限にすることによって、PL/SQL開発者の生産性を向上させます。

PL/Scopeの詳細は、第7章「PL/Scopeの使用」を参照してください。

PL/SQL階層プロファイラ

非階層(フラット)プロファイラにより、プログラムによって各サブプログラム内で費やされた時間(サブプログラムの関数時間または自己時間)が記録されます。関数時間は役に立ちますが、たいていこれでは十分ではありません。たとえば、サブプログラムINSERT_ORDERでプログラム全体の40%が費やされたことがわかれば参考になりますが、INSERT_ORDERを頻繁にコールするプログラムや、INSERT_ORDERの下(子サブプログラムを含む)で費やされた合計時間がわかればさらに便利です。階層プロファイラは、このような情報を提供します。

PL/SQL階層プロファイラには、次の機能があります。

- サブプログラム・コール別に編成されたPL/SQLプログラムの動的実行プロファイルのレポート

- SQL実行時間およびPL/SQL実行時間の個別の説明

- 特殊なソースやコンパイル時間の準備が不要

- カスタム・レポートを生成するために統合開発環境(IDE)ツール(SQL Developerやサード・パーティ・ツールなど)によって処理された結果のデータベース表(階層プロファイラ表)への格納
RAWプロファイラ出力から単純なHTMLレポートを生成するには、plshprofコマンドライン・ユーティリティを使用できます。

動的実行プロファイルのサブプログラムレベルの各サマリーには、次のような情報が含まれます。

- サブプログラムに対するコールの数

- サブプログラム自体で費やされた時間(関数時間または自己時間)

- サブプログラム自体およびその子サブプログラムで費やされた時間(サブツリー時間)

- 次のような、詳細な親子情報

- 特定のサブプログラムのすべてのコール元(親)

- 特定のサブプログラムによってコールされたすべてのサブプログラム(子)

- サブプログラムxがyからコールされたときに費やされた時間

- サブプログラムxがyからコールされた回数

生成されたHTMLレポートは任意のブラウザで参照できます。ブラウザのナビゲーション機能と厳選したリンクを組み合せた効率的な手段により、大規模なアプリケーションのパフォーマンスを分析し、アプリケーションのパフォーマンスを向上させ、開発コストを削減できます。

PL/SQL階層プロファイラの詳細は、第8章「PL/SQL階層プロファイラの使用」を参照してください。

問合せ結果変更通知

Oracle Database 11gリリース1より前は、連続問合せ通知(CQN)によってオブジェクト変更通知のみが発行されていました。これは、登録済の問合せに関連付けられたオブジェクトのDML変更またはDDL変更の結果でした。

Oracle Database 11gリリース1では、CQNは問合せ結果変更通知も発行できます。これは、登録済の問合せに関連付けられた結果セットのDML変更またはDDL変更の結果です。新しい静的データ・ディクショナリ・ビューでは、結果セット変更通知に対してどの問合せが登録されているかを確認できます(「CQN登録の問合せ」を参照)。

詳細は、第11章「連続問合せ通知(CQN)の使用」を参照してください。

フラッシュバック・トランザクション

DBMS_FLASHBACK.TRANSACTION_BACKOUTプロシージャでは、データベースがオンラインである間にトランザクションおよびその依存トランザクションをロールバックします。このリカバリ操作では、UNDOデータを使用して補正トランザクションを作成および実行します。このトランザクションによって影響のあったデータが元の状態に戻ります。

詳細は、「フラッシュバック・トランザクションの使用」を参照してください。

フラッシュバック・データ・アーカイブ(Oracle Total Recall)

フラッシュバック・データ・アーカイブにより、その存続期間中、記録に対するトランザクションによる変更を格納および追跡できます。今後、アプリケーションにこのインテリジェンスを組み込む必要はありません。フラッシュバック・データ・アーカイブは、レコード・ステージ・ポリシーと監査レポートのコンプライアンスに役立ちます。

詳細は、「フラッシュバック・データ・アーカイブの使用(Oracle Total Recall)」を参照してください。

PL/SQL内で使用可能なXA API

XAインタフェース機能は、データベースやキューなど複数のリソース管理に関するトランザクションをサポートし、現在はPL/SQL内で使用できます。PL/SQLを使用して、SQL*Plusセッション間およびプロセス間のトランザクションを切替えおよび共有できます。

詳細は、「DBMS_XAパッケージの使用」を参照してください。

Oracle Real Application Clusters(Oracle RAC)でのXA/JTAのサポート

現在、XAトランザクションはデフォルトで複数のOracle RACインスタンスにまたがっており、XAを使用するすべてのアプリケーションはOracle RAC環境を最大限に活用でき、アプリケーションの可用性およびスケーラビリティを拡張します。

詳細は、「Oracle Real Application Clusters(Oracle RAC)でのOracle XAの使用」を参照してください。

識別コード・パッケージ

識別コード・パッケージは、Oracle Databaseの電子製品コード(EPC)など各種製品コードや識別コード間の格納、取得、エンコード、デコード、および変換を行うツールを提供します。また、新しいデータ型、メタデータ表およびビュー、およびEPC標準RFIDタグまたは新型RFIDタグをユーザー表に格納するためのPL/SQLパッケージも提供します。

識別コード・パッケージによって、Oracle Databaseは、EPCコード体系の認識、効率的な記憶域およびコンポーネント・レベルのEPCデータの取得、EPCglobal Tag Data Translation 1.0(TDT)標準に準拠することが可能になります。TDT標準は、各種EPC RFIDタグ表現間のデコード、エンコード、および変換の方法について定義したものです。

識別コード・パッケージでは、拡張可能なフレームワークも提供しており、EPC標準に含まれないアプリケーションで既存のコード体系を使用でき、Oracle Databaseを古いシステムと将来のEPC標準の一部になる可能性のある進化する識別コードの両方に対応させることができます。

また、識別コード・パッケージでは、最初に新しいエンコード・カテゴリを登録して新しいエンコード・タイプを登録し、次に新しいエンコード・タイプに関連付けられた新しいコンポーネントを登録して、独自の識別コードを作成できます。

詳細は、第17章「識別コード・パッケージの使用」を参照してください。

オンライン索引作成および再構築の機能拡張

オンライン索引作成および再構築では、今後DMLブロッキング・ロックを必要としません。

Oracle Database 11gリリース1より前は、オンライン索引作成および再構築では、再構築の終了時に非常に短期のDMLブロッキング・ロックが必要でした。DMLブロッキング・ロックは、待機中のDML操作の数の急上昇の原因となる可能性があったため、システム使用の一時的な遮断と急激な増加が発生しました。システムの使用状況の異常性によって、オペレーティング・システムのアラーム・レベルがトリガーされる可能性がありました。

埋込みPL/SQLゲートウェイ

PL/SQLゲートウェイを使用すると、HTTPリクエストから導出されたパラメータのあるURLに応答して、ユーザーが作成したPL/SQLサブプログラムを起動できます。mod_plsqlは、Oracle HTTP Serverへのプラグインとして存在するゲートウェイの形式です。現在はPL/SQLゲートウェイも、データベース自体に埋め込まれています。埋込みPL/SQLゲートウェイは内部のOracle XML Database Listenerを使用し、Oracle HTTP Serverに依存していません。DBMS_EPGパッケージを使用して、ゲートウェイの埋込みバージョンを構成します。

詳細は、「埋込みPL/SQLゲートウェイの使用」を参照してください。

デフォルトでマルチスレッド・エージェントextprocを直接起動するOracle Database

アプリケーションが外部Cプロシージャをコールすると、Oracle DatabaseまたはOracle Listenerが外部プロシージャ・エージェントextprocを起動します。

Oracle Database 11gリリース1より前は、Oracle Listenerによってマルチスレッド・エージェントextprocが起動され、ユーザーがlistener.oraファイルにextprocの環境変数を定義していました。

Oracle Database 11gリリース1では、Oracle Databaseによってデフォルトでextprocが直接起動され、Oracle Listenerが誤ってextprocを起動する危険性が解消されています。セキュリティを最大限にするため、このデフォルト構成をお薦めします。使用する場合は、extproc.oraファイルにextprocの環境変数を定義します。

デフォルト構成を使用できない状況も含め、詳細は、「外部プロシージャのロード」を参照してください。

高度な無効化

Oracle Database 11gリリース1より前は、参照オブジェクトを変更するDDL文によって、そのすべての依存が無効になっていました。

Oracle Database 11gリリース1では、参照オブジェクトを変更するDDL文で依存が無効になるのは、次のいずれかに該当する場合のみです。

- 依存オブジェクトが、DDL文によって変更された参照オブジェクトの属性に依存している場合。

- 依存オブジェクトのコンパイル済メタデータが、変更された参照オブジェクトに対して正しいものでなくなった場合。

たとえば、ビューvが表tの列c1およびc2を選択している場合、tの列c3のみを変更するDDL文では、vは無効になりません。

詳細は、「依存オブジェクトの無効化」を参照してください。

第I部

アプリケーション開発者用のSQL

ここでは、アプリケーション開発者がOracle Databaseで情報を管理する場合に使用されるStructured Query Language(SQL)について必要となる情報を説明します。

章:

- 第2章「アプリケーション開発者用のSQL処理」

- 第1章「データベース・アプリケーションにおけるSQLデータ型の使用」

- 第3章「データベース・アプリケーションでの正規表現の使用」

- 第4章「データベース・アプリケーションでの索引の使用」

- 第5章「データベース・アプリケーションにおけるデータ整合性のメンテナンス」

参照:
SQLの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

1 データベース・アプリケーションにおけるSQLデータ型の使用

この章では、データベース・アプリケーションにおけるSQLデータ型の使用方法について説明します。

内容は次のとおりです。

- SQLデータ型の概要

- 文字データの表現

- 数値データの表現

- 日時データの表現

- 特殊なデータの表現

- 条件式のデータとしての表現

- アドレスによる行の識別

- Oracle Databaseによるデータ型の変換方法

- SQL演算子と関数のメタデータ

参照:

- PL/SQLデータ型の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- 抽象データ型(ADT)の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- ADTの詳細は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。
ADTはデータ構造体と、データを操作するサブプログラムから構成されます。静的データ・ディクショナリ・ビュー*_OBJECTSでは、ADEのOBJECT_TYPEはTYPEです。静的データ・ディクショナリ・ビュー*_TYPESでは、ADEのTYPECODEはOBJECTです。

SQLデータ型の概要

データ型は、ある限定されたプロパティの集合を、表の列に挿入できる、あるいはサブプログラムのパラメータに渡すことのできる値と対応付けます。このプロパティの集合によって、Oracle Databaseはあるデータ型の値を別のデータ型の値とは異なるものとして扱うようになります。たとえば、Oracle Databaseは、NUMBERデータ型の値は加算できますが、RAWデータ型の値は加算できません。

Oracle Databaseには、多数のデータ型と、データ型として使用できるユーザー定義型の複数のカテゴリが用意されています。

Oracleプリコンパイラでは、埋込みSQLプログラム内の他のデータ型が認識されます。このようなデータ型は外部データ型と呼ばれ、ホスト変数に関連付けられています。Oracle Databaseの組込みデータ型、Oracle提供のデータ型およびユーザー定義のデータ型を外部データ型と混同しないでください。

参照:

- SQLデータ型の詳細情報は、『Oracle Database SQL言語リファレンス』を参照してください。

- SQLデータ型(Oracleデータ型とも呼ばれます)の追加の概要は、『Oracle Database概要』を参照してください。

文字データの表現

表1-1に、英数字データを格納するSQLデータ型の概要を示します。

表1-1 SQL文字データ型

データ型

格納される値

CHAR

固定長文字リテラル

NCHAR

固定長Unicode文字リテラル

VARCHAR2

可変長文字リテラル

NVARCHAR2

可変長Unicode文字リテラル

CLOB

最大(4 GB - 1) * (DBMS_LOB.GETCHUNKSIZEから取得した値)のシングルバイトおよびマルチバイト文字列

NCLOB

最大(4 GB - 1) *(DBMS_LOB.GETCHUNKSIZEから取得した値)のシングルバイトおよびマルチバイトUnicode文字列

LONG

最大2 GB - 1の可変長文字データ。下位互換性のためだけに提供されています。

クライアント/サーバー・アプリケーションで、クライアント側の文字セットがサーバー側と異なる場合、Oracle DatabaseはCHAR、VARCHAR2およびLONGデータをデータベース文字セット(NLS_LANGUAGEパラメータで決定)からユーザー・セッション用に定義した文字セットに自動的に変換します。

内容は次のとおりです。

- バイト数または文字数としての列の長さの指定

- CHARデータ型およびVARCHAR2データ型間の選択

参照:

- CHAR、VARCHAR2、NCHARおよびNVARCHAR2データ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- CLOBおよびNCLOBデータ型の詳細は、「ラージ・オブジェクト(LOB)」を参照してください。

- LONGデータ型の詳細は、「LONGおよびLONG RAWデータ型」を参照してください。

バイト数または文字数としての列の長さの指定

CHAR列およびVARCHAR2列の長さは、バイト数または文字数として指定できます。NCHAR列およびNVARCHAR2列の長さは、必ず文字単位で指定し、1つの文字が複数バイトで構成される場合にUnicode文字リテラルを格納するために適した長さにします。次の表は、一部の列の長さの指定とその意味をまとめたものです。

列の長さの指定

意味

id VARCHAR2(32 BYTE)

id列には最高32個のシングルバイト文字が含まれます。

name VARCHAR2(32 CHAR)

name列には、最高32文字のデータベース・キャラクタ・セットが格納されます。データベース・キャラクタ・セットにマルチバイト・キャラクタが含まれる場合は、32バイトを超えても32文字まで格納できます。

biography NVARCHAR2(2000)

biography列には、Unicodeで表現可能な任意の言語による最高2000文字を格納できます。エンコーディングは、各国語キャラクタ・セットによって異なります。データベース・キャラクタ・セットがシングルバイトの場合も、列にはマルチバイト値を格納できます。

comment VARCHAR2(2000)

comment列には、初期化パラメータNLS_LENGTH_SEMANTICSの値に応じて、最高2000バイトまたは文字を格納できます。

マルチバイトのデータベース文字コード体系を使用する場合は、文字データ型の列を持つ表のために必要となる領域を慎重に検討してください。データベースの文字コード体系がシングルバイトである場合、1つの列内のバイト数と文字数は同じです。ただし、マルチバイトの場合は、通常このような対応はありません。1つの文字は、マルチバイト・コード体系と、シフトイン/シフトアウト制御コードの有無に応じて、1バイトで構成される場合と、複数バイトで構成される場合があります。バッファのオーバーフローを回避するため、データベース・キャラクタ・セットと異なるUnicodeエンコーディングを使用する可能性がある場合、データをNCHARまたはNVARCHAR2として指定します。

参照:

- SQLデータ型NCHARおよびNVARCHAR2の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

- SQLデータ型NCHARおよびNVARCHAR2の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

CHARデータ型およびVARCHAR2データ型間の選択

表の英数字データを格納する列のデータ型を選択する場合、次を考慮してください。

- 使用領域
Oracle Databaseでは、CHAR列に格納されている値には空白を埋めますが、VARCHAR2列に格納された値にはこれを行いません。そのため、VARCHAR2列の方がCHAR列よりもより効率的に領域を使用します。

- パフォーマンス
空白を埋める違いのため、VARCHAR2列のある大規模な表の全表スキャンでは、CHAR列に同じデータが格納されている表の全表スキャンより、読み込むデータ・ブロックが少なくなる可能性があります。アプリケーションが文字データを含む大規模な表に対して全表スキャンを行う場合、CHAR列よりVARCHAR2列にデータを格納することによってパフォーマンスを改善できる可能性が高くなります。

- 比較セマンティクス
比較セマンティクスでANSI互換性が必要な場合は、CHARデータ型を使用します。文字列の比較において後続空白が重要である場合は、VARCHAR2データ型を使用します。

参照:
これらのデータ型の比較セマンティクスの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 将来の互換性
CHARデータ型およびVARCHAR2データ型は、完全なサポートが保証されています。現在、VARCHARデータ型はVARCHAR2データ型と同義であるとみなされるため、将来も使用できる予定です。

数値データの表現

数値データを格納するSQLデータ型は、NUMBER、BINARY_FLOATおよびBINARY_DOUBLEです。

NUMBERデータ型は、実数を固定小数点形式または浮動小数点形式で格納します。NUMBERは、最大で10進数38桁の精度を提供します。NUMBER列には、1 x 10-130から9.99 x10^125の正と負の数値および0(ゼロ)を格納できます。すべてのOracle DatabaseプラットフォームはNUMBER値をサポートします。

BINARY_FLOATデータ型およびBINARY_DOUBLEデータ型は、それぞれ単精度(32ビット)IEEE 754形式、および倍精度(64ビット)IEEE 754形式で、浮動小数点データを格納します。高精度の値は、BINARY_FLOATおよびBINARY_DOUBLEとして格納するほうが、NUMBERとして格納するよりも必要とする領域は少なくなります。浮動小数点データの算術演算は通常、BINARY_FLOATおよびBINARY_DOUBLE値のほうが、NUMBER値よりも高速です。

Oracle Databaseでサポートされているクライアント・インタフェースでは、BINARY_FLOATデータ型およびBINARY_DOUBLE値の算術演算は、ハードウェアのベンダーが提供する固有の命令セットによって実行されます。ネイティブ浮動小数点データ型という用語は、データ型BINARY_FLOATおよびBINARY_DOUBLE、およびサポートされているクライアント・インタフェースで実装されているこれらの型すべてを指します。

ネイティブ浮動小数点データ型は、電気電子技術者協会(IEEE)の2進浮動小数点演算についての規格であるIEEE規格754-1985(IEEE754)に実質的に準拠しています。詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

内容は次のとおりです。

- 浮動小数点数の構成要素

- 浮動小数点数形式

- ネイティブ浮動小数点データ型の比較演算子

- ネイティブ浮動小数点データ型を使用した算術演算

- 浮動小数点データ型の変換関数

- ネイティブ浮動小数点データ型のクライアント・インタフェース

参照:

- NUMBERデータ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- BINARY_FLOATおよびBINARY_DOUBLEデータ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

浮動小数点数の構成要素

浮動小数点数は次の構成要素からなります。

- 2進値符号

- 符号付き指数

- 仮数

- 基数

浮動小数点数の値は、次の式で表されます。

(-1)sign.significand.baseexponent

たとえば、4.31という値は次のように表されます。

(-1)0.431.10-2

この表現の構成要素は、次のとおりです。

構成要素の名前

構成要素の値

符号

0

仮数

431

基数

10

指数

-2

浮動小数点数形式

浮動小数点数形式は、浮動小数点数の構成要素の表記方法を指定し、それにより、形式が表す値の範囲および精度が決定されます。範囲とは最小値から最大値までの間隔であり、精度とは仮数の桁数です。範囲と精度のどちらも有限です。指定された形式よりも高い精度の浮動小数点数は丸められます。

数値を丸める方法は、10進または2進のいずれかが可能な、形式の基数によって決まります。10進の形式に格納された数値は、最も近い10進の桁に丸められます(例: 1000、10または0.01)。2進の形式に格納された数値は、最も近い2進の桁に丸められます(例: 1024、512または1/64)。

NUMBERの値は、10進の形式で格納されます。10進の桁への丸めを必要とする計算の場合は、NUMBERデータ型を使用してください。

ネイティブ浮動小数点の値は、2進の形式で格納されます。

内容は次のとおりです。

- 浮動小数点2進形式

- ネイティブ浮動小数点形式の特殊な数値

浮動小数点2進形式

2進形式を使用する浮動小数点数の値は、次に示す算式によって決まります。

(-1)sign 2E (bit_0 bit_1 bit_2 ... bitp-1)

表1-2に、算式の構成要素を示します。

表1-2 浮動小数点2進形式の構成要素

構成要素

構成要素の値

sign

0または1

E (指数)

単精度(32ビット)データ型の場合、-126以上127以下の整数です。

倍精度(64ビット)データ型の場合、-1022以上1023以下の整数です。

biti

0または1(ビットの連続は基数2の数値を表します)。

p (精度)

単精度データ型の場合、24。

倍精度データ型の場合、53。

仮数の先頭のビットb_0は、非正規の数値(後述)の場合を除いて、(1)に設定する必要があります。したがって、先頭のビットは実際には格納されないため、2進形式では精度としてnビットを指定しますが、格納されるのはn-1ビットになります。IEEE 754標準は、単精度および倍精度データ型のインメモリー形式を定義します。表1-3に概要を示します。

表1-3 2進形式の記憶域パラメータの概要

データ型

符号ビット

指数ビット

仮数ビット

ビット数合計

単精度

1

8

24(23が格納されます)

32

倍精度

1

11

53(52が格納されます)

64

注意:
IEEE 754標準で定義されている拡張単精度および拡張倍精度形式は、Oracle Databaseではサポートされていません。

仮数の先頭ビットが設定されている場合、正規化されていると呼ばれます。IEEE 754標準では非正規化数(subnormal numbers、denormal numbers)という、小さすぎて正規化された仮数で表せない数値を定義します。非正規化数の仮数を正規化すると、指数が大きくなりすぎます。非正規数では、条件がx-y==0.0(浮動小数点減算を使用)、結果がx==y、というプロパティが保持されます。IEEE 754形式では、非正規の値がサポートされています。

表1-4に、IEEE 754の単精度と倍精度形式およびOracle Database NUMBERの範囲と精度を示します。範囲の制限は、正数として表しますが、この制限は負数の絶対値にも適用されます(ここで使用される「数値e指数」という表記法は、数値*10指数という意味です)。

表1-4 浮動小数点データ型の範囲および精度

範囲および精度

単精度32ビット脚注1

倍精度64ビット^1

Oracle Database NUMBERデータ型

正の最大正規数

3.40282347e+38

1.7976931348623157e+308

< 1.0e126

正の最小正規数

1.17549435e-38

2.2250738585072014e-308

1.0e-130

正の最大非正規数

1.17549421e-38

2.2250738585072009e-308

適用なし

正の最小非正規数

1.40129846e-45

4.9406564584124654e-324

適用なし

精度(10進数)

6 - 9

15 - 17

38 - 40

脚注1これらの数値は『IEEE Numerical Computation Guide』から引用されています。

参照:

- 数値のリテラル表現の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 浮動小数点形式の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 浮動小数点条件の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ネイティブ浮動小数点形式の特殊な数値

表1-5に、IEEE 754標準がサポートする特殊な数値を示します。

表1-5 ネイティブ浮動小数点形式の特殊な数値

値

意味

+INF

正の無限大

-INF

負の無限大

NaN

非数

+0

正のゼロ

-0

負のゼロ

表1-5に示す各値は、NaNを除き、特殊なビット・パターンで表現されます。NaNは未定義の演算の結果であり、多数のビット・パターンで表されます。ビット・パターンには、符号ビット・セットを含むものも含まないものもありますが、符号ビットに意味はありません。

IEEE 754標準では、quiet NaN(ほとんどの演算への伝播時に追加の例外が発生しない)とsignalling NaN(発生する)が区別されます。IEEE 754標準では、例外が有効および無効の場合の動作が指定されています。

Oracle Databaseでは、例外の有効化は許可されません。Oracle Databaseの動作は、IEEE 754標準で指定されている、例外が無効化されている場合の動作になります。特に、Oracle Databaseではquietとsignalling NaNは区別されません。Oracle Call Interface(OCI)を使用して、Oracle DatabaseからNaN値を取得できますが、取得されるNaN値がsignallingかquietかは、クライアント・プラットフォームによって決まり、Oracle Databaseの制御外です。

IEEE 754標準は次の特殊な値のクラスを定義します。

- ゼロ

- 非正規

- 正規

- 無限大

- NaN

NaNを除き、このリストの各クラスの値は、小さい方から順に示されています(符号は考慮していません)。IEEE 754では、NaNは、他の特殊な値のクラスともNaN自体とも順序付けることはできません。

Oracle Databaseの場合

- NaNはすべてquietです。

- すべての非NaN value < NaN

- 任意のNaN == 他のNaN

- NaNはすべて同じビット・パターンに変換されます。

- -0は+0に変換されます。

- IEEE 754例外は発生しません。

参照:
浮動小数点条件の詳細は、『Oracle Database SQL言語リファレンス』を参照してください(浮動小数点条件では、式が無限か、または演算の未定義の結果(非数値(NaN))かを判断します)。

ネイティブ浮動小数点データ型の比較演算子

Oracle Databaseでは、ネイティブ浮動小数点データについて、次の比較演算子が定義されています。

- 等しい

- 等しくない

- より大きい

- 以上

- より小さい

- 以下

- 不規則

比較では、ゼロの符号は無視されます(-0は、+0と等しいとみなされます)。

参照:
特殊な値の比較結果、順序付けおよびその他の動作の詳細は、「ネイティブ浮動小数点形式の特殊な数値」を参照してください。

ネイティブ浮動小数点データ型を使用した算術演算

Oracle Databaseでは、ネイティブ浮動小数点データ型について、次の算術演算子が定義されています。

- 乗算

- 除算

- 加算

- 減算

- 剰余

- 平方根

演算の結果を丸めるために使用されるモードを定義できます。演算が実行されると、例外が発生することがあります。例外を無効化することもできます。

従来、Javaでは、浮動小数点算術に厳密な再現性が求められていました。IEEE 754にはこの要件はありません。このため、演算(算術を含む)の結果を、演算のオペランドが使用するよりも大きい範囲を使用する格納先に格納できます。

倍精度乗算の結果は、拡張倍精度格納先での計算に使用できます。しかし、計算結果は、格納先が単精度または倍精度であるかのように丸められます。結果の範囲(指数のビット数)としては、より高精度(拡張倍精度)の格納先でサポートされている範囲が使用できます。ただし、二重丸め誤差(結果の最下位ビットが不正)が発生する可能性があります。

この問題は、IA-32およびIA-64命令セット・アーキテクチャを実装するハードウェアで、倍精度乗算および除算を実行した場合のみ発生します。したがって、この例を除き、これらのデータ型に対する算術をプラットフォームを渡って再現できます。計算の結果がNaNの場合、すべてのプラットフォームでIS NANがTRUEの値が作成されます。ただし、すべてのプラットフォームで同じビット・パターンを使用する必要はありません。

浮動小数点データ型の変換関数

Oracle Databaseでは、浮動小数点と他のデータ型(10進数精度を使用する文字列形式など)の間で変換を行う関数が定義されています(変換中に精度が失われることがあります)。次に例を示します。

- TO_BINARY_DOUBLE(『Oracle Database SQL言語リファレンス』を参照)

- TO_BINARY_FLOAT(『Oracle Database SQL言語リファレンス』を参照)

- TO_CHAR(『Oracle Database SQL言語リファレンス』を参照)

- TO_NUMBER(『Oracle Database SQL言語リファレンス』を参照)

Oracle Databaseでは、変換時に例外が発生する可能性があります。IEEE 754標準では、次の例外が定義されています。

- 無効

- 不正確

- ゼロ除算

- アンダーフロー

- オーバーフロー

Oracle Databaseでは、ネイティブ浮動小数点データ型に対して、これらの例外は発生しません。例外が発生する操作では、通常、表1-6に示す値が生成されます。

表1-6 例外により生成される値

例外

値

アンダーフロー

0

オーバーフロー

-INF、+INF

無効な演算

NaN

ゼロ除算

-INF、+INF、NaN

不正確

任意の値: 端数処理が実行されました。

ネイティブ浮動小数点データ型のクライアント・インタフェース

Oracle Databaseは、ネイティブ浮動小数点データ型を次のクライアント・インタフェースでサポートします。

- SQL

- PL/SQL

- Oracle Call Interface(OCI)

- Oracle C++ Call Interface(OCCI)

- Pro*C/C++

- JDBC

内容は次のとおりです。

- OCIのネイティブ浮動小数点データ型SQLT_BFLOATおよびSQLT_BDOUBLE

- ADTでサポートされるネイティブ浮動小数点データ型

- ネイティブ浮動小数点データ型のPro*C/C++サポート

OCIのネイティブ浮動小数点データ型SQLT_BFLOATおよびSQLT_BDOUBLE

OCI APIでは、IEEE 754の単精度および倍精度のネイティブ浮動小数点データ型が実装されており、それぞれのデータ型はSQLT_BFLOATおよびSQLT_BDOUBLEです。これらのデータ型とSQLデータ型BINARY_FLOATおよびBINARY_DOUBLEとの変換は、Cデータ型FLOATおよびDOUBLEに対してIEEE 754標準を実装するプラットフォームで正確に行われます。

参照:
『Oracle Call Interfaceプログラマーズ・ガイド』

ADTでサポートされるネイティブ浮動小数点データ型

Oracle Databaseでは、SQLデータ型BINARY_FLOATおよびBINARY_DOUBLEは、ADTの属性としてサポートされています。

ネイティブ浮動小数点データ型のPro*C/C++サポート

Pro*C/C++では、列データ型BINARY_FLOATおよびBINARY_DOUBLEを使用して、ネイティブFLOATデータ型およびネイティブDOUBLEデータ型がサポートされています。これらのデータ型は、Oracle Database NUMBERデータ型と同じ方法で使用できます。FLOATおよびDOUBLEを、それぞれBINARY_FLOATおよびBINARY_DOUBLEデータ型にバインドできます。そのためには、アプリケーションのコンパイル時に、Pro*C/C++プリコンパイラ・コマンドライン・オプションNATIVE_TYPESをY(yes)に設定します。

日時データの表現

Oracle Databaseでは、日時(datetime)データを、独自の内部形式で、世紀、年、月、日、時間、分および秒に対応する7バイトのフィールドに格納します。

表1-7に、SQL日時データ型の概要を示します。日時データ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

表1-7 SQL日時データ型

日付タイプ

使用方法

DATE

ある時点(日時)の値を表に格納するために使用します。たとえば、ジョブの日付に使用します。

TIMESTAMP

小数秒を含む正確な日付の値を格納するために使用します。たとえば、発生順序を決定するために比較する必要があるイベントの時間に使用します。

TIMESTAMP WITH TIME ZONE

複数の地域にまたがって収集または調整する必要がある日時の値を格納するために使用します。

TIMESTAMP WITH LOCAL TIME ZONE

タイムゾーンが重要でない場合に日時の値を格納するために使用します。たとえば、テレビ会議のスケジュールを立てるアプリケーションでは、各参加者は自分のタイムゾーンで開始時間および終了時間を確認します。

クライアント・システムのタイムゾーンを使用して日時を表示する必要がある2層アプリケーションに適しています。通常、3層アプリケーションでこのデータ型を使用するのは不適切です。これは、Webブラウザに表示されるデータがブラウザのタイムゾーンではなくWebサーバーのタイムゾーンによって書式化されるためです。Webサーバーはデータベース・クライアントであるため、ローカル時間が使用されます。

INTERVAL YEAR TO MONTH

年および月のみが重要な場合に、2つの日時の値の違いを格納するために使用します。たとえば、アラームを18か月後の日付に設定したり、特定の日付から6か月経過したことを確認できます。

INTERVAL DAY TO SECOND

2つの日時の値の正確な違いを格納するために使用します。たとえば、アラームを36時間後に設定したり、レースの開始から終了までの時間を記録できます。長い時間を高精度で表すには、日の部分に大きな値を使用します。

内容は次のとおりです。

- 現在の日付および時刻の表示

- デフォルト以外の書式での日付の表示および挿入

- デフォルト以外の書式での時刻の表示および挿入

- 日時データ型を使用した算術演算

- 日時データ型の変換関数

- 日時データ型のインポートおよびエクスポート

参照:
Oracle Database内部日時タイプの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

現在の日付および時刻の表示

現在の日付および時刻を表示する最も簡単な方法は次のとおりです。

SELECT SYSDATE FROM DUAL

このコマンドは、現在の日付および時刻を、初期化パラメータNLS_DATE_FORMATによって異なる、デフォルトの日付書式で表示します。

Oracle Databaseのデフォルトの標準日付書式はDD-MON-RRです。RR日時書式要素を使用すると、年の末尾2桁のみを指定して20世紀の日付を21世紀に格納できます。たとえば、DD-MON-YY日付書式の13-NOV-54は、1950年から2049年に発行された問合せでは1954年を指しますが、2050年から2099年に発行される問合せでは2054年を指します。

SYSDATEをデフォルト以外の書式で表示するには、TO_CHAR関数を日付書式モデルを指定して使用します。

例1-1では、TO_CHARを書式モデルを指定して使用して、SYSDATEを、デフォルト以外の書式で、BCまたはAD修飾子付きで表示します(デフォルトではSYSDATEは修飾子なしで表示されます)。

例1-1 デフォルト以外の書式での現在の日付および時刻の表示

SELECT TO_CHAR(SYSDATE, 'DD-MON-YYYY BC') NOW FROM DUAL;

結果:

NOW
-----------------------
18-MAR-2009 AD

1 row selected.

ヒント:
SYSDATEを使用するコードをテストするときに、SYSDATEを定数に設定できるのは便利です。これには初期化パラメータFIXED_DATEを使用します(『Oracle Databaseリファレンス』を参照)。

参照:

- SYSDATEの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- NLS_DATE_FORMATの詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

- TO_CHARの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 日時書式モデルの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- RR日時書式要素の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

デフォルト以外の書式での日付の表示および挿入

Oracle Databaseでは日付は常にデフォルトの日付書式(初期化パラメータNLS_DATE_FORMATで設定)で格納されますが、TO_CHARおよびTO_DATE関数を、それぞれ日時書式モデルを指定して使用すると、デフォルト以外の書式で日付を表示および挿入できます。

例1-2では、DATE列を含む表を作成し、デフォルト以外の書式で指定した日付を挿入します。日付は最初のSELECT文で示すように、デフォルトの書式で格納されます。2番目のSELECT文は日付をデフォルト以外の書式で表示します。

例1-2 デフォルト以外の書式での日付の挿入および表示

DROP TABLE dates;
CREATE TABLE dates (d DATE);

INSERT INTO dates VALUES (TO_DATE('OCT 27, 1998', 'MON DD, YYYY'));

SELECT d FROM dates;

結果:

D
---------
27-OCT-98

1 row selected.

SELECT TO_CHAR(d, 'YYYY-MON-DD') D FROM dates;

結果:

D
--------------------
1998-OCT-27

1 row selected.

注意:
YY日時書式要素を使用して現在の世紀の年を表示する場合は注意します。たとえば、21世紀では、書式DD-MON-YY、31-DEC-92は2092年の12月31日です( 推察のとおり、1992年12月31日ではありません)。年の末尾2桁のみを指定して20世紀の日付を21世紀に格納するには、RR日時書式要素を使用します(デフォルト)。

参照:

- NLS_DATE_FORMATの詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

- TO_CHARの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- TO_DATEの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 日時書式モデルの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- RR日時書式要素の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

デフォルト以外の書式での時刻の表示および挿入

Oracle Databaseでは時刻は常にHH24:MI:SSのような24時間形式で格納されますが、TO_CHARおよびTO_DATE関数を、それぞれ日時書式モデルを指定して使用すると、デフォルト以外の書式で時刻を表示および挿入できます。

DATE列では

- デフォルトの時刻は12:00:00 A.M.(真夜中)です。
デフォルトの時刻は、時刻部分に何も指定されなかった、または値が切捨てられたという理由のどちらの場合でも、時刻部分のない列の値に適用されます。

- デフォルトの日付は現在の月の最初の日です。
デフォルトの日付は、日付部分に何も指定されなかった場合、列の値に適用されます。

例1-3では、DATE列を含む表を作成し、デフォルト以外の書式で指定した3つの日付を挿入します。1つは日付および時刻部分があり、1つは時刻部分がなく、もう1つは日付部分がありません。最初のSELECT文は現在の日付を示します。2番目のSELECT文は、日付および時刻部分の両方を含む、デフォルト以外の書式で3つの日付を表示します。

例1-3 デフォルト以外の書式での日付および時刻の挿入および表示

DROP TABLE birthdays;
CREATE TABLE birthdays (name VARCHAR2(20), day DATE);

INSERT INTO birthdays (name, day)
VALUES ('Annie',
TO_DATE('13-NOV-92 10:56 A.M.','DD-MON-RR HH:MI A.M.')
);

INSERT INTO birthdays (name, day)
VALUES ('Bobby',
TO_DATE('5-APR-02','DD-MON-RR')
);

INSERT INTO birthdays (name, day)
VALUES ('Cindy',
TO_DATE('8:25 P.M.','HH:MI A.M.')
);

現在の日付を表示します。

SELECT SYSDATE FROM DUAL;

結果:

SYSDATE
---------
05-NOV-10

1 row selected.

格納された日時の値の日付および時刻部分の両方を表示します。

SELECT name,
TO_CHAR(day, 'Mon DD, RRRR') DAY,
TO_CHAR(day, 'HH:MI A.M.') TIME
FROM birthdays;

結果:

NAME                 DAY                   TIME
-------------------- --------------------- ----------
Annie                Nov 13, 1992          10:56 A.M.
Bobby                Apr 05, 2002          12:00 A.M.
Cindy                Nov 01, 2010          08:25 P.M.

3 rows selected.

日時データ型を使用した算術演算

日時の値に算術演算を実行できます。そのような演算の結果は、『Oracle Database SQL言語リファレンス』 に記載のルールによって決定されます。

SQLには、日時の式に使用できる多くの日時関数があります。たとえば、関数ADD_MONTHSは、指定した日付から指定した月数である日付を戻します。日時関数のすべてのリストは、『Oracle Database SQL言語リファレンス』を参照してください。

日時データ型の変換関数

表1-8に、日時データ型間で変換を行うSQLファンクションの概要を示します。

表1-8 日時データ型のSQL変換関数

関数

変換元

変換先

NUMTODSINTERVAL

NUMBER

INTERVAL DAY TO SECOND

NUMTOYMINTERVAL

NUMBER

INTERVAL DAY TO MONTH

TO_CHAR

DATE

TIMESTAMP

TIMESTAMP WITH TIME ZONE

TIMESTAMP WITH LOCAL TIME ZONE

INTERVAL DAY TO SECOND

INTERVAL YEAR TO MONTH

VARCHAR2

TO_DATE

CHAR

VARCHAR2

NCHAR

NVARCHAR2

DATE

TO_DSINTERVAL

CHAR

VARCHAR2

NCHAR

NVARCHAR2

INTERVAL DAY TO SECOND

TO_TIMESTAMP

CHAR

VARCHAR2

NCHAR

NVARCHAR2

TIMESTAMP

TO_TIMESTAMP_TZ

CHAR

VARCHAR2

NCHAR

NVARCHAR2

TIMESTAMP WITH TIME ZONE

TO_YMINTERVAL

CHAR

VARCHAR2

NCHAR

NVARCHAR2

INTERVAL DAY TO MONTH

日時データ型のインポートおよびエクスポート

TIMESTAMP WITH TIME ZONEおよび TIMESTAMP WITH LOCAL TIME ZONE値はデータベースに正規化された書式で格納されるため、タイムゾーンのオフセットを考慮することなく、インポート、エクスポートおよび比較ができます。

DATEおよびTIMESTAMP値はデータベースでタイムゾーンを格納しないため、ソース・データベースとターゲット・データベース間のタイムゾーンの違いを考慮して調整する必要があります。

特殊なデータの表現

内容は次のとおりです。

- 地理データの表現

- マルチメディア・データの表現

- 大量のデータの表現

- 検索可能なテキストの表現

- XMLデータの表現

- 動的に型指定されたデータの表現

- ANSI、DB2およびSQL/DSデータの表現

地理データの表現

MDSYS.SDO_GEOMETRYデータ型などの機能を使用して、地理情報システム(GIS)または空間データを表すことができます。オブジェクト・リレーショナル・モデルまたはリレーショナル・モデルを使用して、データベースにデータを格納できます。PL/SQLパッケージのセットを使用して、データを操作および問い合せることができます。

参照:
Oracle Spatial機能の詳細は、『Oracle Spatial開発者ガイド』を参照してください。

マルチメディア・データの表現

Oracle Multimediaを使用すると、Oracle Databaseで他の企業情報と統合された方法でイメージ、オーディオ、ビデオまたは他の異機種メディア・データを格納、管理および取得できます。Oracle Multimediaにより、Oracle Databaseの信頼性、可用性およびデータ管理が従来型、インターネット、E-Commerceおよびマルチメディア・アプリケーションのマルチメディア・コンテンツへと拡張されます。

この種のマルチメディア・データをBLOB値またはBFILE値としてデータベースに格納したり、Webサーバーまたはその他のサーバーに外部的に格納する場合、Oracle Multimediaを使用して、オブジェクト・リレーショナル・モデルまたはリレーショナル・モデルのいずれかでデータにアクセスし、一連のADTを使用してデータを操作および問い合せることができます。

Oracle Multimediaは、次の用途にあったORDAudio、ORDDoc、ORDImage、ORDImageSignature、ORDVideoおよびSI_StillImageADT(メソッドを含む)を提供します。

- マルチメディア・データからのメタデータと属性の抽出

- Oracle Multimedia、Webサーバー、ファイル・システムおよび他のサーバーからのマルチメディア・データの取得および管理

- イメージ・データの操作の実行

参照:
Oracle Multimediaの詳細は、『Oracle Multimediaリファレンス』を参照してください。

大量のデータの表現

大量のデータを表現するために、Oracle Databaseでは次のものが提供されています。

- ラージ・オブジェクト(LOB)

- LONGおよびLONG RAWデータ型(下位互換性のため)

ラージ・オブジェクト(LOB)

ラージ・オブジェクト(LOB)は大量のデータを格納するためのデータ型です(LOBの最大サイズはデータベースの構成方法により異なります)。LOBにデータを格納することで、アプリケーションでデータを効果的にアクセスし操作することができます。

表1-9に、LOBの概要を示します。

表1-9 ラージ・オブジェクト(LOB)

データ型

説明

BLOB

バイナリ・ラージ・オブジェクト

さまざまな種類のバイナリ形式のデータを格納します。

通常、イメージ、音声および映像などのマルチメディア・データに使用されます。

CLOB

キャラクタ・ラージ・オブジェクト

文字列データをデータベース・キャラクタ・セット形式で格納します。

データベース・キャラクタ・セットのみを使用する大量の文字列またはドキュメントに使用されます。

NCLOB

各国語キャラクタ・ラージ・オブジェクト

各国語キャラクタ・セット形式で文字列データを格納します。

各国語キャラクタ・セットの大量の文字列またはドキュメントに使用されます。

BFILE

外部ラージ・オブジェクト

バイナリ・ファイルをホストのオペレーティング・システム・ファイル・システム内のデータベース外に格納します。アプリケーションはBFILEに対し読取り専用のアクセス権を持ちます。

イメージ・データなど、アプリケーションが操作しない静的データに使用されます。

あらゆる種類のデータ(つまりオペレーティング・システム・ファイル)はBFILEに格納できます。たとえば、キャラクタ・データをBFILEに格納し、キャラクタ・セットを指定してBFILEデータをCLOBにロードします。

BLOB、CLOBまたはNCLOB型のインスタンスは一時的(アプリケーションのスコープ内で宣言される)か、または永続的(データベースで作成および格納される)のいずれも可能です。

参照:

- LOBのその他の一般的な情報は、『Oracle Database SQL言語リファレンス』を参照してください。

- アプリケーション開発でのLOBの使用の詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。

LONGおよびLONG RAWデータ型

注意:
OracleではLONGおよびLONG RAWデータ型を下位互換性のためにサポートしますが、LONG列をLOB列に、LONG RAW列をBLOB列に変換することを強くお薦めします。

LONG列には最大2 GB - 1バイトの可変長文字列が格納されます。LONG列にはVARCHAR2列の多くの特性があります。LONG列を使用して長いテキスト文字列を格納できます。LONG値の長さはコンピュータの使用可能なメモリの量により制限されることがあります。LONGデータ型の制限を含む詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

LONG RAWデータ型(およびRAWデータ型)は、Oracle Databaseによって、異なるシステム間でデータを移動するときに明示的に変換されないデータを格納します。これらのデータ型は、2進データおよびバイト列のために用意されています。たとえば、LONG RAWを使用して、図形データ、音声データ、文書データおよび2進データの配列を格納できます。解析方法は使用方法によって異なります。RAWデータには索引を付けることができますが、LONG RAWデータには索引を付けることができません。RAWデータ型およびLONG RAWデータ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

検索可能なテキストの表現

全文検索を行うには、低レベルのコードを作成するのではなく、Oracle Textを使用します。Oracle Textを使用すると、検索データが特別な索引に格納され、演算子およびPL/SQLパッケージを使用して検索データを問い合せることができます。このテクノロジによって、表、ファイルまたはURLのデータを使用する独自の検索エンジンの作成、および検索ロジックとリレーショナル問合せの結合が可能になります。この方法では、XPath表記法を使用してXMLデータを検索することもできます。

参照:
Oracle Textの詳細は、『Oracle Textアプリケーション開発者ガイド』を参照してください。

XMLデータの表現

XML形式のファイルとして格納されている情報がある場合、またはADTをXML形式で格納する場合、Oracle提供のXMLType型を使用できます。

表にXMLType列を作成する場合、次の方法でXMLデータを格納できます。

- CLOB列に

- バイナリXMLとして(内部的にはCLOBとして格納)

- オブジェクト・リレーショナルに

XMLTypeにはW3C XPath式を使用してXMLデータにアクセス、抽出および問い合わせるメンバー関数があります(『Oracle XML DB開発者ガイド』を参照)。また、OracleはXMLドキュメントの全体または一部を操作または戻すSQL XML関数(『Oracle Database SQL言語リファレンス』を参照)および次のPL/SQLパッケージ(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を提供しています。

- DBMS_XMLDOM、XMLTypeオブジェクトのアクセス用

- DBMS_XMLGEN、SQL問合せの結果の正規XML形式への変換用

- DBMS_XMLINDEX、非同期索引作成の実装用

- DBMS_XMLPARSER、XMLドキュメントのコンテンツと構造へのアクセス用

- DBMS_XMLQUERY、データベースからXMLTypeへの機能用

- DBMS_XMLSAVE、XMLからデータベース型への機能用

- DBMS_XMLSCHEMA、XMLスキーマの管理用

- DBMS_XMLSTORE、XMLデータのリレーショナル表への格納用

- DBMS_XMLTRANSLATIONS、さまざまな言語で検索または表示できるための文字列の変換用

参照:

- Oracle XML DBの詳細と、それを使用してXMLデータをデータベースに格納、生成、操作、管理および問合せする方法は、『Oracle XML DB開発者ガイド』を参照してください。

- XMLを使用したクライアント側プログラミングの詳細は、『Oracle XML Developer's Kitプログラマーズ・ガイド』を参照してください。

動的に型指定されたデータの表現

いくつかの言語では、実行時にデータ型を変更したり、プログラムに変数の型を確認させることができます。たとえば、C言語にはunionキーワードおよびvoid*ポインタがあり、Javaにはtypeof演算子およびNumberなどのラッパー型があります。

Oracle Databaseでは、すべての型のデータを保持できる変数および列を作成することができ、その値をテストして基礎となる表現を判断できます。たとえば、表の単一の列で、数値、文字列およびオブジェクトをそれぞれ別の行に表現できます。

Oracleが提供するSYS.ANYDATA ADTを使用すると、すべてのスカラー型またはADTの値を表現できます。SYS.ANYDATAには、任意の型のスカラー値を受け取り、スカラーまたはオブジェクトに戻すメソッドがあります。同様に、Oracleが提供するSYS.ANYDATASET ADTを使用すると、すべてのコレクション型の値を表現できます。これらのADTの詳細は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。

型の情報を確認および操作するには、例1-4に示すDBMS_TYPESパッケージを使用します。このパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

OCIを使用するときは、OCIAnyDataおよびOCIAnyDataSetインタフェースを使用します。『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

例1-4 SYS.ANYDATA列の情報へのアクセス

CREATE OR REPLACE TYPE employee_type AS
OBJECT (empno NUMBER, ename VARCHAR2(10));
/

DROP TABLE mytab;
CREATE TABLE mytab (id NUMBER, data SYS.ANYDATA);

INSERT INTO mytab (id, data)
VALUES (1, SYS.ANYDATA.ConvertNumber(5));

INSERT INTO mytab (id, data)
VALUES (2, SYS.ANYDATA.ConvertObject(Employee_type(5555, 'john')));

CREATE OR REPLACE PROCEDURE p IS
CURSOR cur IS SELECT id, data FROM mytab;
v_id                        mytab.id%TYPE;
v_data                      mytab.data%TYPE;
v_type                      SYS.ANYTYPE;
v_typecode                  PLS_INTEGER;
v_typename                  VARCHAR2(60);
v_dummy                     PLS_INTEGER;
v_n                         NUMBER;
v_employee                  employee_type;
non_null_anytype_for_NUMBER exception;
unknown_typename            exception;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id, v_data;
EXIT WHEN cur%NOTFOUND;

/* typecode signifies type represented by v_data.
GetType also produces a value of type SYS.ANYTYPE with methods you
can call to find precision and scale of a number, length of a
string, and so on. */

v_typecode := v_data.GetType (v_type /* OUT */);

/* Compare typecode to DBMS_TYPES constants to determine type of data
and decide how to display it. */

CASE v_typecode
WHEN DBMS_TYPES.TYPECODE_NUMBER THEN
IF v_type IS NOT NULL THEN  -- This condition should never happen.
RAISE non_null_anytype_for_NUMBER;
END IF;

-- For each type, there is a Get method.
v_dummy := v_data.GetNUMBER (v_n /* OUT */);
DBMS_OUTPUT.PUT_LINE
(TO_CHAR(v_id) || ': NUMBER = ' || TO_CHAR(v_n) );

WHEN DBMS_TYPES.TYPECODE_OBJECT THEN
v_typename := v_data.GetTypeName();
IF v_typename NOT IN ('HR.EMPLOYEE_TYPE') THEN
RAISE unknown_typename;
END IF;
v_dummy := v_data.GetObject (v_employee /* OUT */);
DBMS_OUTPUT.PUT_LINE
(TO_CHAR(v_id) || ': user-defined type = ' || v_typename ||
' ( ' || v_employee.empno || ', ' || v_employee.ename || ' )' );
END CASE;
END LOOP;
CLOSE cur;
EXCEPTION
WHEN non_null_anytype_for_NUMBER THEN
RAISE_Application_Error (-20000,
'Paradox: the return AnyType instance FROM GetType ' ||
'should be NULL for all but user-defined types');
WHEN unknown_typename THEN
RAISE_Application_Error( -20000, 'Unknown user-defined type ' ||
v_typename || ' - program written to handle only HR.EMPLOYEE_TYPE');
END;
/

SELECT t.data.gettypename() AS "Type Name" FROM mytab t;

結果:

Type Name
--------------------------------------------------------------------------------
SYS.NUMBER
HR.EMPLOYEE_TYPE

2 rows selected.

ANSI、DB2およびSQL/DSデータの表現

表およびクラスタを作成するSQL文は、ANSIデータ型と、IBM社の製品SQL/DSおよびDB2のデータ型を使用できます(次の段落の注意を除く)。Oracle DatabaseはANSIまたはIBMデータ型を対応するOracleデータ型に変換し、Oracleデータ型を列データ型の名前として記録し、列データをOracleデータ型で格納します。変換の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

注意:
SQL文ではSQL/DSおよびDB2のTIME、GRAPHIC、VARGRAPHICおよびLONG VARGRAPHICデータ型を使用できません。対応するOracleデータ型がないからです。

条件式のデータとしての表現

Oracle Expression Filter(ルール・マネージャの機能)により、条件式をデータベース表の1つまたは複数の列に格納、索引作成および評価できます。Oracle Expression Filterは、格納された式を受信データと比較し、目的の行を識別します。

シナリオ: 各行に株式取引の口座名義人のデータが含まれる表を作成しました。各投資家が関心を持っている株式の情報を条件式として格納する列を定義しようとしています。

DROP TABLE traders;
CREATE TABLE traders (
name     VARCHAR2(10),
email    VARCHAR2(20),
interest VARCHAR2(30)
);

解決方法:

1. 取引記号、指値、株価の変動額を示す属性を含むデータ型を作成します。

CREATE OR REPLACE TYPE ticker AS OBJECT (
symbol VARCHAR2(20),
price  NUMBER,
change NUMBER
);
/

2. データ型tickerに基づいて属性セットを作成します。

BEGIN
DBMS_EXPFIL.DROP_ATTRIBUTE_SET (attr_set  => 'ticker');
END;
/
BEGIN
DBMS_EXPFIL.CREATE_ATTRIBUTE_SET
(attr_set  => 'ticker',
from_type => 'YES');
END;
/

3. 次のように、列trader.interestに格納された式セットに属性セットを関連付けます。

BEGIN
DBMS_EXPFIL.ASSIGN_ATTRIBUTE_SET
(attr_set => 'ticker',
expr_tab => 'traders',
expr_col => 'interest');
END;
/

このコードによって、interest列に有効な条件式が格納されるようになります。

4. この表に、投資家名、電子メール・アドレス、特定の価格で投資家が関心を持っている株式を表す条件式を移入します。次に例を示します。

INSERT INTO traders (name, email, interest)
VALUES ('Vishu', 'vishu@example.com', 'symbol = ''ABC'' AND price > 25');

5. EVALUATE演算子を使用して、指定したデータ項目をTRUEと評価する条件式を識別します。たとえば、次の問合せでは、株価(symbol='ABC', price=31, change=5.2)に関心を持っている投資家が戻されます。

SELECT name, email
FROM traders
WHERE EVALUATE (
interest,
'symbol=>''ABC'',
price=>31,
change=>5.2'
) = 1;

結果:

NAME       EMAIL
---------- --------------------
Vishu      vishu@example.com

1 row selected.

ヒント:
問合せを高速化するには、interest列にOracle Expression Filter索引を作成します。

参照:
Oracle Expression Filterを使用したアプリケーションの開発の詳細は、『Oracle Databaseルール・マネージャおよび式フィルタ開発者ガイド』を参照してください。

アドレスによる行の識別

行にアクセスするには、そのアドレス、または行を一意に識別するROWIDを使用するのが最も高速な方法です。同じデータ・ブロック内の異なる行は、これらが異なるクラスタ化表にある場合のみ、同じROWIDを持つことができます。行が1データ・ブロックよりも長い場合、ROWIDによって最初の行断片が識別されます。

ROWIDを確認するには、疑似列ROWIDを問い合せます。この値は、行のアドレスを表す文字列です。この文字列のデータ型はROWIDまたはUROWIDです。

注意:
ハイブリッド列圧縮(HCC)で圧縮された表の行を更新すると、行のROWIDが変更されます。特定のOracleストレージ・システムの機能であるHCCの詳細は、『Oracle Database概要』を参照してください。

内容は次のとおりです。

- ROWID疑似列の問合せ

- ROWIDデータ型

- UROWIDデータ型

参照:
ROWID疑似列の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ROWID疑似列の問合せ

Oracle Databaseデータベース内の各表はROWIDという名前の疑似列を持っています。これはSELECTリスト、またはWHERE句に含まれる問合せで使用できます。

例1-5では、ROWIDデータ型の列を持つ表を作成し、INSERT文でROWID擬似列を問い合せることでROWIDを移入し、表示します。表のROWID列により、格納方法が表示されます。

例1-5 ROWID擬似列の問合せ

DROP TABLE t_tab;  -- in case it exists
CREATE TABLE t_tab (col1 ROWID);

INSERT INTO t_tab (col1)
SELECT ROWID
FROM employees
WHERE employee_id > 199;

問合せ:

SELECT employee_id, rowid
FROM employees
WHERE employee_id > 199;

ROWIDは異なりますが、次に類似した結果が得られます。

EMPLOYEE_ID ROWID
----------- ------------------
200 AAAPeSAAFAAAABTAAC
201 AAAPeSAAFAAAABTAAD
202 AAAPeSAAFAAAABTAAE
203 AAAPeSAAFAAAABTAAF
204 AAAPeSAAFAAAABTAAG
205 AAAPeSAAFAAAABTAAH
206 AAAPeSAAFAAAABTAAI

7 rows selected.

問合せ:

SELECT * FROM t_tab;

COL1は異なりますが、次に類似した結果が得られます。

COL1
------------------
AAAPeSAAFAAAABTAAC
AAAPeSAAFAAAABTAAD
AAAPeSAAFAAAABTAAE
AAAPeSAAFAAAABTAAF
AAAPeSAAFAAAABTAAG
AAAPeSAAFAAAABTAAH
AAAPeSAAFAAAABTAAI

7 rows selected.

ROWIDデータ型

Oracle Databaseにより生成されたヒープ構成表では、ROWID疑似列の値のデータ型はROWIDです。内部的に、このデータ型は、データベース・サーバーが行にアクセスするために必要な情報を保持する構造体です。この構造体の形式は、制限付き形式、拡張形式、および外部バイナリ形式のいずれかです。

注意:
ROWID型の列(例1-5のcol1など)を作成しても、その値が有効なROWIDであるという保証はありません。

内容は次のとおりです。

- 制限付き内部ROWID形式

- 拡張内部ROWID形式

- 外部バイナリ内部ROWID形式

制限付き内部ROWID形式

制限付き内部形式のROWID構造体は、次のコンポーネントを含みます。

- データファイル識別子

- ブロック識別子

- 行識別子

ほとんどのプラットフォームでは、構造体のサイズは6バイトです。

データベース・サーバーにより、ROWID疑似列は18文字の文字列で、16進数でコード化された各コンポーネントとともに、クライアント・アプリケーションに戻されます。

拡張内部ROWID形式

拡張内部形式のROWID構造体は、制限付き形式と同じコンポーネントとデータとデータ・オブジェクト番号を含みます。これによりデータベース・セグメントが識別されます。ほとんどのプラットフォームでは、この構造体のサイズは10バイトです。

データベース・サーバーにより、ROWID疑似列の値は、18文字の文字列形式で、各コンポーネントをbase 64にエンコードして、クライアント・アプリケーションに戻されます。たとえば、文字列AAAA8mAALAAAAQkAAAは、4つの部分からなる形式OOOOOOFFFBBBBBBRRRの拡張ROWIDのコンポーネントをbase 64にエンコードしたものを表します。

拡張ROWIDの内容をアクセスおよび解析するには、DBMS_ROWIDパッケージを使用します。『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

外部バイナリ内部ROWID形式

一部のクライアント・アプリケーションでは、バイナリ内部形式のROWID構造体を使用します。たとえば、OCIおよび一部のプリコンパイラ・アプリケーションでは、バインドまたは定義のコールで3GL構造体に対してROWIDデータ型をマップできます。

バイナリ内部形式では、ROWID構造体のサイズは、拡張および制限付きROWIDのサイズと同じです。制限付きROWIDの場合、オブジェクト番号は未使用フィールドに格納されています。

拡張バイナリROWIDの形式は、Cのstructで表すと、次のようになります。

struct riddef {
ub4    ridobjnum; /* data obj#--this field is
unused in restricted ROWIDs */
ub2    ridfilenum;
ub1    filler;
ub4    ridblocknum;
ub2    ridslotnum;
}

UROWIDデータ型

外部表(Oracle Databaseにより生成されていない)または索引構成表では、ROWID擬似列の値はUROWIDデータ型になります。このデータ型にはユニバーサルROWID(UROWID)が格納されます。

外部表のUROWID(ゲートウェイを介してアクセスされるDB2表など)は外部ROWIDと呼ばれます。

索引構成表のUROWI(表の行は索引リーフに格納されますが、これは移動できます)は論理ROWIDと呼ばれます。Oracle Databaseでは、論理ROWIDは表の主キーに基づいて作成されます。主キーが変更されていない場合、論理ROWIDは変更されません。

表にUROWIDを格納するには、表に対してUROWIDデータ型の列を定義し、その列にROWID疑似列の値を取り出します。

Oracle Databaseによるデータ型の変換方法

一般には、あるデータ型の値を別のデータ型の変数または列に割り当てる、または別のデータ型の値を使用して式を作成することはできません。しかし、Oracle Databaseでは、あるデータ型のデータが予想される箇所で、別のデータ型のデータを受け入れ、受け入れたデータを予想されるデータ型に自動的に変換する場合があります。これは暗黙的データ変換と呼ばれます。

内容は次のとおりです。

- 代入中のデータ変換

- 式の評価中のデータ型変換

参照:
データ型変換の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

代入中のデータ変換

次のような代入の場合、

variable := expression

expressionのデータ型がvariableと異なる場合、Oracle Databaseはexpressionのデータ型をvariableのデータ型に変換しようとします。どのような場合に可能かは、『Oracle Database SQL言語リファレンス』を参照してください。

文字からNUMBERへの変換は、文字列が有効な数字を表している場合にのみ正常に行われます。文字からDATEへの変換は、文字列がセッションのデフォルト日付書式に合致している場合にのみ正常に行われます(デフォルト日付書式の詳細は、「現在の日付および時刻の表示」を参照してください)。

例

test_package、パブリック変数var1およびtable1_tabが次のように宣言されています。

CREATE OR REPLACE PACKAGE test_package AS
var1 CHAR(5);
END;
/

DROP TABLE table1_tab;
CREATE TABLE table1_tab (col1 NUMBER);

次の代入について説明します。

variable := expression

expressionのデータ型は、variableのデータ型と同じか、そのデータ型に暗黙的に変換可能である必要があります。たとえば、次の代入では、Oracle Databaseによって0がvar1のデータ型(CHAR(5))に自動的に変換されます。

var1 := 0;

次の文について説明します。

INSERT INTO table1_tab (col1) VALUES (expression)

expressionのデータ型は、col1のデータ型と同じか、そのデータ型に暗黙的に変換可能である必要があります。たとえば、次の文では、Oracle Databaseによって文字列'19'がcol1のデータ型(NUMBER)に自動的に変換されます。

INSERT INTO table1_tab (col1) VALUES ('19')

次の文について説明します。

UPDATE table1_tab SET column = expression

expressionのデータ型は、columnのデータ型と同じか、そのデータ型に暗黙的に変換可能である必要があります。たとえば、次の文では、Oracle Databaseによって文字列'30'がcol1のデータ型(NUMBER)に自動的に変換されます。

UPDATE table1_tab SET col1 = '30';

次の文について説明します。

SELECT column INTO variable FROM table1_tab

columnのデータ型は、variableのデータ型と同じか、そのデータ型に変換可能である必要があります。たとえば、次の文では、Oracle Databaseによって、col1から選択された値(30)がvar1のデータ型(CHAR(5))に自動的に変換されます。

SELECT col1 INTO var1 FROM table1_tab WHERE col1 = 30;

式の評価中のデータ型変換

式の評価では、Oracle Databaseは割当ての場合と同じ変換を自動的に行うことができます。ターゲット・データ型は、式の内容により決定されます。たとえば、式が算術演算子のオペランドである場合、Oracle Databaseは、式の値をNUMBERに変換しようとします。式が文字列関数のオペランドである場合、Oracle Databaseは、式の値をVARCHAR2に変換しようとします。

次のような割当ての場合、

variable := expression

Oracle Databaseでは、式変換規則を使用して、最初にexpressionを評価します。評価が正常に行われると、結果は単一のデータ型の単一の値となり、その後、Oracle Databaseは、割当て変換規則を使用して、variableにこの値を割り当てようとします。

SQL演算子と関数のメタデータ

動的パフォーマンス・ビューV$SQLFN_METADATAには、SQL演算子と関数のメタデータが含まれます。V$SQLFN_METADATAの各関数に対し、動的パフォーマンス・ビューV$SQLFN_ARG_METADATAには、それぞれの関数の引数に関するメタデータの1行が含まれます。関数の引数が反復可能な場合(関数LEASTおよびGREATEST内など)、V$SQLFN_ARG_METADATAには、それぞれの反復引数向けに1行のみが含まれます。FUNCIDでこれらの2つのビューを結合できます。

これらのビューによって、サード・パーティ・ツールは、アプリケーション・レイヤーでメタデータをメンテナンスすることなくSQL関数を活用できます。

内容は次のとおりです。

- ARGnデータ型

- DISP_TYPEデータ型

- データ型ファミリ

参照:

- V$SQLFN_METADATAの詳細は、『Oracle Databaseリファレンス』を参照してください。

- V$SQLFN_ARG_METADATAの詳細は、『Oracle Databaseリファレンス』を参照してください。

ARGnデータ型

ビューV$SQLFN_METADATAの中で列DATATYPEは、関数のデータ型(つまり、関数が戻すデータ型)です。このデータ型は、Oracleデータ型、データ型ファミリ(「データ型ファミリ」を参照)、またはARGnのいずれかです。ARGnは、関数のn番目の引数のデータ型です。次に例を示します。

- MAX関数(『Oracle Database SQL言語リファレンス』を参照)は、その最初の引数のデータ型を持つ値を戻すため、MAX関数はデータ型ARG1を戻します。

- DECODE関数(『Oracle Database SQL言語リファレンス』を参照)は、その3番目の引数のデータ型を持つ値を戻すため、DECODE関数のデータ型は、ARG3です。

DISP_TYPEデータ型

ビューV$SQLFN_METADATAの中では、DISP_TYPEが任意の式を持つ引数のデータ型です。式は、単一の値、または値と単一の値を持つSQL関数の組合せから構成されています。

表1-10 SQL関数の表示タイプ

表示タイプ

説明

例

NORMAL

FUNC(A,B,...)

LEAST(A,B,C)

ARITHMETIC

A FUNC B)

A+B

PARENTHESIS

FUNC()

SYS_GUID()

RELOP

A FUNC B

A IN B

CASE_LIKE

CASE文またはDECODEデコード

NOPAREN

FUNC

SYSDATE

データ型ファミリ

通常、SQL関数の引数には、データ型ファミリの任意のデータ型を含めることができます。表1-11に、データ型ファミリとそのメンバーのデータ型を示します。

表1-11 データ型ファミリ

ファミリ

データ型

STRING

CHARACTER

VARCHAR2

CLOB

NCHAR

NVARCHAR2

NCLOB

LONG

NUMERIC

NUMBER

BINARY_FLOAT

BINARY_DOUBLE

DATETYPE

DATE

TIMESTAMP

TIMESTAMP WITH TIME ZONE

TIMESTAMP WITH LOCAL TIME ZONE

INTERVAL YEAR TO MONTH

INTERVAL DAY TO SECOND

BINARY

BLOB

RAW

LONGRAW

2 アプリケーション開発者用のSQL処理

この章では、Oracle DatabaseでのSQL文の処理方法について、アプリケーション開発者が知っておく必要がある内容について説明します。この章を読む前に、『Oracle Database概要』でSQL処理の基本情報について参照してください。

内容は次のとおりです。

- SQL文の処理の説明

- 操作のトランザクションへのグループ化

- 読取り専用トランザクションでの反復可能読取りの保証

- カーソルの使用

- 明示的な表のロック

- Oracle Lock Managementサービス(ユーザー・ロック)の使用

- シリアライズ可能トランザクションを使用した同時実行性の制御

- 自律型トランザクション

- 記憶域割当てエラー後の実行の再開

SQL文の処理の説明

ここでは、SQL文の実行時に処理の各ステージで何が行われるかを、例としてDML文を使用して説明します。

ある部門の全従業員の昇給を行うためにPro*Cプログラムを使用しているとします。プログラムはOracle Databaseに接続しており、操作を行うユーザーはemployees表を所有するHRスキーマに接続しています。プログラムには次のSQL文を埋め込むことができます。

EXECUTE SQL UPDATE employees SET salary = 1.10 * salary
WHERE department_id = :department_id;

プログラムでは、SQL文の実行時に使用するバインド変数プレースホルダ:department_idの値が提供されます。

SQL文の処理のステージ

注意:
DML文はすべてのステージを使用します。トランザクション管理、セッション管理およびシステム管理のSQL文が使用するのは、ステージ2および8のみです。

1. カーソルをオープンまたは作成します。
プログラム・インタフェース・コールにより、SQL文を予想して、カーソルがオープンまたは作成されます。ほとんどのアプリケーションではカーソルの作成は暗黙的(自動的)に行われます。プリコンパイラ・プログラムでは、カーソルを暗黙的または明示的に作成します。

2. 文を解析します。

SQL文がユーザー・プロセスからOracle Databaseに渡され、文の解析済表現が共有SQL領域にロードされます。Oracle Databaseは、解析中に多くのエラーを捕捉できます。

注意:
DDL文では、解析にデータ・ディクショナリの参照と実行が含まれます。

参照:

- 索引の詳細は、Oracle Database概要を参照

- 「共有SQL領域」

3. 文が問合せかどうかを判別します。

4. 文が問合せの場合、結果を記述します。

注意:
このステージが必要になるのは、結果の性質が不明な場合のみです。たとえば、ユーザーが対話的に問合せを入力する場合などです。

Oracle Databaseによって結果の性質(データ型、長さおよび名前)が決まります。

5. 文が問合せの場合、出力を定義します。
フェッチされる各値を受け取るために定義する変数の場所、サイズおよびデータ型を指定します。このような変数は定義変数と呼ばれます。必要な場合にはOracle Databaseによってデータ型の変換が行われます。

参照:
DEFINEステージの詳細は、『Oracle Database概要』を参照してください。

6. 変数がある場合はバインドします。
Oracle DatabaseはSQL文の意味を判別していますが、文を実行するために十分な情報は得ていません。Oracle Databaseでは、文に指定されているすべてのバインド変数プレースホルダの値が必要です。例では、:department_idの値が必要です。これらの値を獲得するプロセスは変数のバインドと呼ばれます。

値の場所(メモリー・アドレス)をプログラムで指定する必要があります。アプリケーションのエンド・ユーザーは、Oracle Databaseユーティリティから値の入力を求められることがあるため、バインド変数プレースホルダの値を指定していると認識していない場合もあります。

値の場所(つまり参照によるバインド)がプログラムによって指定されるため、値が変更された場合でも、文の再実行の前に変数を再バインドする必要はありません。Oracle Databaseは文の実行のたびにそのアドレスから変数の値を取得します。

Oracle Databaseでデータ型変換を実行する必要がある場合は、デフォルトでまたは暗黙的に指定する場合を除き、各値のデータ型と長さも指定する必要があります。

参照:
値のデータ型と長さの指定の詳細は、次の資料を参照してください。

- 『Oracle Call Interfaceプログラマーズ・ガイド』

- 『Pro*C/C++プログラマーズ・ガイド』

7. (オプション)文をパラレル化します。
Oracle Databaseでは、問合せと一部のデータ定義言語(DDL)操作(索引作成、副問合せによる表作成、パーティションに対する操作など)をパラレル化することができます。パラレル化では、処理が早く完了するように、複数のサーバー・プロセスでSQL文の処理を実行します。

8. 文を実行します。

Oracle Databaseは文を実行します。文が問合せまたはINSERT文の場合、データは変更されないためデータベースは行をロックする必要はありません。ただし、文がUPDATE文またはDELETE文の場合は、それにより影響を受けるすべての行を、そのトランザクションの次のCOMMIT、ROLLBACKまたはSAVEPOINTまで、データベースがロックします。これによりデータの整合性が確保されます。

一部の文では実行が複数回行われるように指定できます。これは配列処理と呼ばれます。実行回数をnと指定すると、バインドおよび定義の場所が、サイズnの配列の先頭であるとみなされます。

9. 文が問合せの場合、行をフェッチします。
Oracle Databaseは行を選択し、問合せにORDER BY句が含まれる場合は、行の順序付けを行います。後続の各フェッチにより結果セットの行が1行ずつ取得され、最後の行がフェッチされるまで続きます。

10. カーソルをクローズします。
Oracle Databaseはカーソルをクローズします。

注意:
トランザクション管理、セッション管理またはシステム管理SQL文を再実行するには、別のEXECUTE文を使用します。

共有SQL領域

Oracle Databaseは、アプリケーションが類似したSQL文をデータベースに送信すると自動的に検出します。その文の最初の処理時に使用されたSQL領域が共有されます。つまり、後で出現する同じ文の処理に使用されます。このため、一意の文に対して存在する共有SQL領域は1つのみです。共有SQL領域は共有メモリー領域であるため、すべてのOracle Databaseプロセスが共有SQL領域を使用できます。SQL領域の共有により、データベース・サーバーでのメモリー使用量が減るため、システム・スループットが向上します。

Oracle Databaseでは、文が類似しているか同一かを決定する際に、ユーザーやアプリケーションによって直接発行されたSQL文と、DDL文によって内部的に発行された再帰的SQL文の両方が比較されます。

参照:
共有SQLの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

操作のトランザクションへのグループ化

内容は次のとおりです。

- トランザクションへの操作のグループ化方法の決定

- トランザクションのパフォーマンスの改善

- トランザクションのコミット

- コミットREDO動作の管理

- トランザクションのロールバック

- トランザクションのセーブポイントの定義

参照:
トランザクションの基本情報は、『Oracle Database概要』を参照してください。

トランザクションへの操作のグループ化方法の決定

一般に、トランザクションへの操作のグループ化方法の決定は、Oracle Databaseのプログラム・インタフェースを使用するアプリケーション設計者が考慮します。トランザクションのグループ化方法を決定する際は、次の規則に従います。

- 論理単位ごとに作業が完成し、データの一貫性が保たれるように、トランザクションを定義します。

- すべての参照表の中のデータは、トランザクションが開始する前および終了した後で、一貫した状態であることを確認します。

- 各トランザクションは、データに対する一貫した変更を1つ含むSQL文またはPL/SQLブロックのみで構成されていることを確認します。

たとえば、口座間で預金を移動できるWebアプリケーションを作成すると仮定します。このトランザクションには、一方の口座の借方への記帳(1つのSQL文で実行)ともう一方の口座の貸方への記帳(もう1つのSQL文で実行)が含まれる必要があります。2つの文で1つの作業単位となり、両方が成立するか両方が不成立かのいずれかである必要があります。つまり、片方の文はもう片方のコミットなしでコミットすることはできません。一方の口座への預金など、関連のないアクションは、同じトランザクションに含めないでください。

トランザクションのパフォーマンスの改善

アプリケーション開発者は、パフォーマンスの改善を試みる必要があります。アプリケーションの設計および作成では、次のパフォーマンス改善のテクニックを使用することを検討してください。

- 各トランザクションに対して、次を行います。

1. 単一のSQL文を使用できる場合、それを使用します。

2. 単一のSQL文を使用できないが、PL/SQLを使用できる場合、できるだけ小さいPL/SQLを使用します。
PL/SQLの詳細は、第II部「アプリケーション開発者用のPL/SQL」を参照してください。

3. (電子メールの送信など、実行する必要のあることができないため)PL/SQLを使用できない場合、Javaを使用します。

4. Javaを使用できない場合(非常に低速な場合など)、または既存の第三世代言語(3GL)コードがある場合、外部Cサブプログラムを使用します。

アプリケーションでのJavaおよびCの使用方法の詳細は、第14章「複数のプログラミング言語を使用したアプリケーションの開発」を参照してください。

- 共有SQL領域を利用できるように、SQL文の発行基準を確立します。
Oracle Databaseが同一のSQL文を認識し、SQL文がメモリー領域を共有できるようにします。これによって、データベース・サーバー上のメモリー使用量が減少し、システム・スループットが向上します。

- 統計を収集します。Oracle Databaseは統計を使用して、SQL文を最適化するコストベースの方法を実装することができます。必要に応じて、オプティマイザへの追加のヒントを使用できます。
ほとんどの統計の収集にはDBMS_STATSパッケージを使用します。このパッケージでは、パラレルでの統計の収集、パーティション化されたオブジェクトのグローバル統計の収集、その他の方法での統計収集の微調整を行うことができます。このパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

コストベースのオプティマイザに関係しない統計収集(空きリスト・ブロックに関する情報収集など)では、SQL文ANALYZEを使用します。この文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- トランザクションを開始する前にDBMS_APPLICATION_INFO.SET_ACTIONプロシージャを起動し、トランザクションの名前をデータベースに登録し、後でOracle TraceおよびSQLトレース機能を使用してパフォーマンスをトラッキングするときに使用できるようにします。DBMS_APPLICATION_INFOパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- ユーザーが作成したPL/SQLファンクションをSQL式に組み込んで、ユーザーの生産性および問合せ効率を向上させます。詳細は、「SQL文からのストアドPL/SQLファンクションの起動」を参照してください。

参照:
トランザクション管理の詳細は、『Oracle Database概要』を参照してください。

トランザクションのコミット

トランザクションをコミットするには、COMMIT文を使用します。次の2つの文は同等で、現行のトランザクションをコミットします。

COMMIT WORK;
COMMIT;

COMMIT文には、コミットされるトランザクションに関する情報を示すコメントを指定したCOMMENTパラメータを含めることができます。コメントは、分散トランザクションをコミットするときに、トランザクションの起点に関する情報を含める場合に有効です。

COMMIT COMMENT 'Dallas/Accts_pay/Trans_type 10B';

参照:
COMMIT文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

コミットREDO動作の管理

トランザクションがOracle Databaseを更新するとき、これに対応するREDOエントリが生成されます。このREDOエントリは、トランザクションが完了するまで、Oracle DatabaseによりREDOログにバッファリングされます。トランザクションがコミットされると、それに応じてログ・ライター・プロセス(LGWR)により、トランザクション内のすべての変更のバッファリングされたREDOエントリに対し、REDOレコードがディスクに書き込まれます。デフォルトでは、REDOエントリは、コールがクライアントに戻される前に、Oracle Databaseによりディスクに書き込まれます。この動作のためにアプリケーションはREDOエントリがディスクに永続的に書き込まれるのを待機する必要があり、コミットに待機時間が発生します。

Oracle Databaseでは、アプリケーションのニーズに応じてコミットREDOの処理を変更できます。アプリケーションで非常に高いトランザクション・スループットが必要とされるため、コミットでの待機時間を短くするためにコミットの永続性を放棄してもよい場合は、デフォルトのCOMMITオプションを変更して、データベースでデータがオンラインREDOログへ書き込まれるのをアプリケーションが待機しなくて済むようにできます。

表2-1はCOMMITオプションの一覧です。

注意:
NOWAITオプションを指定した場合、コミット・メッセージの受信後、REDOログ・レコードへの書込み前に障害が発生すると、トランザクションにその変更が永続的であると誤って示す可能性があります。

表2-1 COMMIT文のオプション

オプション

効果

WAIT
(デフォルト)

対応するREDO情報がオンラインREDOログに永続的に書き込まれるまで、COMMIT文が戻されないことを確認します。このCOMMIT文から成功として戻されたコミットをクライアントが受信した場合、そのトランザクションは永続的なメディアにコミットされています。

ログに正常に書き込まれた後に障害が発生すると、成功メッセージがクライアントに戻されない場合があります。その場合、クライアントはトランザクションがコミットされたかどうかを判断できません。

NOWAIT
(
WAITの代替)

COMMIT文は、REDOログへの書込みが完了したかどうかにかかわらず、クライアントに戻されます。この動作はトランザクションのスループットを向上させます。

BATCH
(
IMMEDIATEの代替)

REDO情報は、同時に実行しているトランザクションとともにREDOログにバッファリングされます。十分なREDO情報が収集されると、REDOログのディスク書込みが開始されます。この動作では、複数のトランザクションのREDO情報が1回のI/O操作でログに書き込まれるため、グループ・コミットと呼ばれます。

IMMEDIATE
(デフォルト)

LGWRがトランザクションのREDO情報をログに書き込みます。この操作オプションではディスクI/Oが発生するため、トランザクションのスループットが低下する場合があります。

COMMITオプションを変更するには、COMMIT文(『Oracle Database SQL言語リファレンス』を参照)、または適切な初期化パラメータを使用します。初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

注意:
分散トランザクションの場合、デフォルトのIMMEDIATEおよびWAITアクションは変更できません。

Oracle Call Interface(OCI)を使用するアプリケーションの場合、アプリケーション内でOCITransCommitファンクションに次のフラグを設定することにより、REDO動作を変更できます。

- OCI_TRANS_WRITEWAIT

- OCI_TRANS_WRITENOWAIT

- OCI_TRANS_WRITEBATCH

- OCI_TRANS_WRITEIMMED

注意:
OCI_TRANS_WRITENOWAITの使用時には、トランザクションが強制終了、強制起動、インスタンス障害またはノード障害で警告なしに消失する可能性があります。Oracle RACシステムでは非同期にコミットした変更は、他のインスタンスですぐに読み込めない場合があります。

参照:
OCITransCommitファンクションの詳細は『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

NOWAITおよびBATCHオプションの指定では、問題が発生しやすい期間が短くなります(このような期間には、アプリケーションがコミット済として認識するトランザクションをOracle Databaseがロールバックできます)。アプリケーションは、次のような状況に対応できる必要があります。

- データベース・ホストの障害。バッファには格納されていても、まだオンラインREDOログに書き込まれていないREDOエントリが失われる可能性があります。

- ファイルI/Oの問題で、LGWRによるバッファ済REDOエントリのディスクへの書込みが妨げられる場合。REDOログが多重化されていない場合、コミットが失われます。

トランザクションのロールバック

トランザクションの全体または一部を(セーブポイントまで)ロールバックするには、ROLLBACK文を使用します。たとえば、次の文はどちらも、現行のトランザクション全体をロールバックします。

ROLLBACK WORK;
ROLLBACK;

ROLLBACK文のWORKオプションには、何も機能はありません。

現行のトランザクション内に定義されたセーブポイントまでロールバックするには、ROLLBACK文のTOオプションを使用します。たとえば、次の文はいずれもPOINT1という名前のセーブポイントまで現行のトランザクションをロールバックします。

SAVEPOINT Point1;
...
ROLLBACK TO SAVEPOINT Point1;
ROLLBACK TO Point1;

トランザクションのセーブポイントの定義

トランザクション内にセーブポイントを定義するには、SAVEPOINT文を使用します。次の文は、現行のトランザクション内にADD_EMP1という名前のセーブポイントを作成します。

SAVEPOINT Add_emp1;

前のセーブポイントと同じ識別子でセーブポイントを作成すると、前のセーブポイントが消去されます。セーブポイントを作成した後は、そのセーブポイントまでロールバックできます。

アクティブ・セーブポイントとは、最後のCOMMITまたは最後のROLLBACK文の後に作成されたセーブポイントのことです。セッション当たりのアクティブ・セーブポイントの数に制限はありません。

表2-2に、トランザクション内のCOMMIT文、SAVEPOINT文およびROLLBACK文の使用を示す一連のSQL文を示します。

表2-2 COMMIT、SAVEPOINTおよびROLLBACKの使用方法

SQL文

結果

SAVEPOINT a;

このトランザクションの最初のセーブポイント

DELETE...;

このトランザクションの最初のDML文

SAVEPOINT b;

このトランザクションの2番目のセーブポイント

INSERT INTO...;

このトランザクションの2番目のDML文

SAVEPOINT c;

このトランザクションの3番目のセーブポイント

UPDATE...;

このトランザクションの3番目のDML文

ROLLBACK TO c;

UPDATE文がロールバックされ、セーブポイントCは定義されたままになります。

ROLLBACK TO b;

INSERT文がロールバックされ、セーブポイントCは失われます。セーブポイントBは定義されたままです。

ROLLBACK TO c;

ORA-01086

INSERT INTO...;

このトランザクションの新しいDML文

COMMIT;

最初のDML文(DELETE文)および最後のDML文(2番目のINSERT文)によって行われたすべてのアクションがコミットされます。

トランザクションのその他すべての文(2番目および3番目の文)はCOMMITの前にロールバックされています。セーブポイントAは、すでにアクティブではありません。

読取り専用トランザクションでの反復可能読取りの保証

デフォルトでは、Oracle Databaseでは、文レベルの読取り一貫性は保証されますが、トランザクション・レベルの読取り一貫性は保証されません。文レベルの読取り一貫性を持つ場合、ある文に含まれる問合せは、この文の存続中、一貫性のあるデータを生成します。その他の文による変更は反映されません。トランザクション・レベルの読取り一貫性(反復可能読取り)を持つ場合、あるトランザクションに含まれる問合せは、このトランザクションの存続中、一貫性のあるデータを生成します。その他のトランザクションによる変更は反映されません。

DML文を含まないトランザクションに対するトランザクション・レベルの読取り一貫性を保証するには、このトランザクションを読取り専用に指定します。読取り専用トランザクションに含まれる問合せには、このトランザクションが開始される前にコミットされた編集以外見えないため、トランザクションの存続中、問合せの結果の一貫性が保たれます。

読取り専用トランザクションは、データ・ロックを追加取得することなしに、トランザクション・レベルの読取り一貫性を提供します。したがって、読取り専用トランザクションがデータを問い合せている間、別のトランザクションが同じデータを問い合せ、更新することができます。

ある読取り専用トランザクションは次の文で始まります。

SET TRANSACTION READ ONLY [ NAME string ];

SET TRANSACTION READ ONLY文の前に来ることができるのは、DDL文のみです。SET TRANSACTION READ ONLY文の実行が正常に終了した後で、このトランザクションはSELECT(ただし、FOR UPDATEなしで)、COMMIT、ROLLBACK、または非DML文(SET ROLE、ALTER SYSTEM、LOCK TABLEなど)のみを含むことができます。COMMIT、ROLLBACK、またはDDL文は読取り専用トランザクションで終わります。

参照:
SET TRANSACTION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

実行時間の長い問合せでは、読取り一貫性(CR)操作に必要なUNDO情報が無効になったためにエラーが発生することがあります。これは、アクティブなトランザクションによって、コミット済UNDOブロックが上書きされた場合に起こります。

自動UNDO管理を行うと、データベース管理者(DBA)は、パラメータUNDO_RETENTIONを使用してUNDO情報のデータベースでの保存期間を明示的に制御できます。たとえば、UNDO_RETENTIONを30分に設定すると、すべてのコミット済UNDO情報は、最低30分間データベースに保持されます。この設定により、実行時間が30分以内の問合せでOERエラー「スナップショットが古すぎます。」が発生することはなくなります。

参照:
実行時間の長い問合せおよび再開可能領域割当ての詳細は、『Oracle Database管理者ガイド』を参照してください。

カーソルの使用

PL/SQLでは、1行のみ戻す問合せも含めて、すべてのSQLデータ操作文に対してカーソルを暗黙的に宣言します。複数行を戻す問合せの場合、カーソルを明示的に宣言して行を別々に処理できます。

カーソルは、特定のプライベートSQL領域の名前と考えることができます。PL/SQLカーソル変数を使用すると、ストアド・サブプログラムから複数の行を取得できます。3GLアプリケーション内のパラメータとしてカーソル変数を渡すことができます。カーソル変数の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

ほとんどのOracle Databaseユーザーは、データベース・ユーティリティの自動カーソル処理を使用しますが、アプリケーション設計者は、プログラム・インタフェースを使用した方がカーソルを制御しやすくなります。アプリケーション開発では、カーソルはプログラムで使用できる名前付きのリソースであり、アプリケーションに埋め込まれたSQL文の解析に特に有効です。

内容は次のとおりです。

- 1つのセッションでオープンできるカーソルの数

- 文を再実行するためのカーソルの使用

- スクロール可能カーソル

- カーソルのクローズ

- カーソルの取消し

1つのセッションでオープンできるカーソルの数

1つのセッションで同時にオープンできるカーソル数は、次のものにより決まります。

- セッションで使用可能なメモリーの量

- 初期化パラメータOPEN_CURSORSの値( 『Oracle Databaseリファレンス』を参照)

プリコンパイラ・プログラムに対して明示的にカーソルを作成すると、アプリケーションのチューニング時に有効です。たとえば、カーソル数を増加させると、解析頻度が削減されパフォーマンスが改善されます。ある時点で必要となるカーソル数がわかっている場合、その数のカーソルを同時にオープンできます。

文を再実行するためのカーソルの使用

各ステージの実行後、カーソルはそのSQL文に関する十分な情報を保持しているため、同じカーソルに他のSQL文が対応付けられていない場合、最初から実行しなおさなくてもその文を再実行できます。文は、解析ステージを含めなくても再実行できます。

カーソルをいくつかオープンすることによって、いくつかのSQL文の解析済表現を保存できます。同じSQL文を繰り返し実行する場合、記述手順、定義手順、バインド手順または実行手順から開始することができ、カーソルのオープンおよび解析を繰り返す必要がなくなります。

あるカーソルのパフォーマンス特性を理解するために、DBAは、V$SQL動的パフォーマンス・ビューを使用して、関連する問合せのテキストを表示します(『Oracle Databaseリファレンス』を参照)。元の問合せに対するEXPLAIN PLANの結果は、データベースによる問合せの実際の処理方法とは異なる場合があるので、DBAは、次の動的パフォーマンス・ビューを調べることによってさらに正確な情報を取得できます。

ビュー

説明

V$SQL_PLAN

ライブラリ・キャッシュにロードされた各子カーソルの実行計画情報。詳細は、『Oracle Databaseリファレンス』を参照してください。

V$SQL_PLAN_STATISTICS

各子カーソルの行ソース・レベルでの実行統計。詳細は、『Oracle Databaseリファレンス』を参照してください。

V$SQL_PLAN_STATISTICS_ALL

(ソートまたはハッシュ結合に)SQLメモリーを使用する行ソースのメモリー使用量統計。このビューは、V$SQL_PLAN内の情報をV$SQL_PLAN_STATISTICSおよびV$SQL_WORKAREAからの実行統計と連結します。詳細は、『Oracle Databaseリファレンス』を参照してください。

スクロール可能カーソル

カーソルを実行すると、結果セットと呼ばれる一連の行に問合せの結果が入力されます。スクロール可能カーソルは、結果の行が前方順次でフェッチされる必要のないカーソルです。スクロール可能カーソルの場合、以前フェッチした行をフェッチ、結果セットのn行目をフェッチ、および結果セットの現在位置からn行目をフェッチするためのインタフェースがあります。

参照:
OCIでのスクロール可能なカーソルの使用の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

カーソルのクローズ

カーソルのクローズとは、その情報にアクセスできなくなり、使用しているメモリーの割当てが解除されることです。カーソルはオープンされると、ユーザー・プログラムがサーバーへの接続を終了するまで、クローズされません。

適切なプログラミング・プラクティスに従うOCIプログラムまたはプリコンパイラ・アプリケーションは、そのプログラムの実行中にオープン状態のカーソルを明示的にクローズします。オープン状態のカーソルをクローズせずにプログラムを終了すると、カーソルは暗黙的にクローズされます。

カーソルの取消し

カーソルを取り消すと、現在のフェッチからリソースが解放されます。対応付けられたプライベート領域にある情報は失われますが、カーソルはオープンしたままになり、解析され、バインド変数に対応付けられます。

注意:
Pro*C/C++またはPL/SQLを使用してカーソルを取り消すことはできません。

参照:
OCIStmtFetch2文によるカーソルの取消しの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

明示的な表のロック

Oracle Databaseには、データの同時実行性、データの整合性、および文レベルでの読取り一貫性を保持するための、デフォルト・ロック・メカニズムが用意されています。ただし、これらのメカニズムは表を明示的にロックすることによりオーバーライドできます。表の明示的なロックは次のような状況で役立ちます。

- アプリケーション内のあるトランザクションが他のトランザクションの完了を待機する必要がなくなるように、リソースに対して排他的にアクセスするトランザクションが必要な場合。

- アプリケーションで、トランザクション・レベルの読取り一貫性(反復可能読取り)が必要な場合。
トランザクション・レベルの読取り一貫性を保証する他の方法については、「読取り専用トランザクションでの反復可能読取りの保証」、および「シリアライズ可能トランザクションを使用した同時実行性の制御」を参照してください。

次のどのSQL文を使用しても、デフォルト・ロックをトランザクション・レベルでオーバーライドできます。

- LOCK TABLE(『Oracle Database SQL言語リファレンス』を参照)

- FOR UPDATE句付きSELECT文(『Oracle Database SQL言語リファレンス』を参照)

- READ ONLYまたはISOLATION LEVEL SERIALIZABLEオプションを指定したSET TRANSACTION(『Oracle Database SQL言語リファレンス』を参照)

これらの文によって取得されるロックは、トランザクションのコミット後またはロールバック後に解除されます。

参照:
ALTER SESSION文のISOLATION_LEVELパラメータの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

DMLロックの最大数は、DML_LOCKS初期化パラメータ(『Oracle Databaseリファレンス』を参照)によって決定されます。通常、デフォルト値には十分な値が設定されていますが、明示的なロックを使用する際に、この値を大きくする必要がある場合があります。

注意:
いずれかのレベルでOracle Databaseのデフォルト・ロックをオーバーライドする場合は、データ整合性が保証されていること、データ同時実行性が許容されていること、およびデッドロックの可能性がないか、デッドロックが適切に処理されていることを確認してください。

内容は次のとおりです。

- 表のロックを取得するために必要な権限

- ロック方法の選択

- Oracle Databaseによる表ロック制御

- 明示的な行ロック

- 明示的なロックにおける同時実行性の例

表のロックを取得するために必要な権限

自らのスキーマの表に対して表のロックを取得するためには、特別な権限は必要ありません。他スキーマ内の表に対して表ロックを取得するには、LOCK ANY TABLEシステム権限またはその表に対する(SELECTやUPDATEなどの)オブジェクト権限が必要です。

ロック方法の選択

LOCK TABLE文が実行されると、トランザクションは指定された表ロックを明示的に取得します。LOCK TABLE文は、デフォルト・ロックを明示的にオーバーライドします。ビューに対してLOCK TABLE文が発行されると、基礎となる実表がロックされます。次の文は、その文が含まれるトランザクションのために、employees表およびdepartments表に対する排他表ロックを取得します。

LOCK TABLE employees, departments
IN EXCLUSIVE MODE NOWAIT;

ロック・モードが同じ場合は、ロックする表またはビューを複数指定できます。ただし、各LOCK TABLE文に指定できるロック・モードは1つのみです。

注意:
表がロックされると、その表のすべての行がロックされます。他のユーザーは、その表を変更できません。個々の行のロックについて詳細は、「明示的な行ロック」を参照してください。

LOCK TABLE文では、表ロックの待ち時間も指示できます。

- ロックを待機しない場合は、NOWAITまたはWAIT 0を指定します。
表ロックがすぐに使用可能である場合にのみ表ロックを取得します。すぐに使用可能でない場合は、その時点ではロックを使用できないことを示すエラーが戻されます。

- 表ロックを取得するためにn秒まで待機する場合は、WAIT nを指定します。ここで、nは0より大きく、100000以下です。
n秒経過しても表ロックを使用できない場合は、その時点ではロックを使用できないことを示すエラーが戻されます。

- ロックを取得するまで無限に待機する場合は、NOWAITおよびWAITのいずれも指定しないでください。
データベースは表が使用可能になるまで無限に待機し、表をロックして制御を戻します。データベースでDML文と同時にDDL文を実行すると、タイムアウトやデッドロックが発生する場合があります。これらのタイムアウトやデッドロックがデータベースで検出されると、エラーが戻されます。

内容は次のとおりです。

- ROW SHARE MODEおよびROW EXCLUSIVE MODEでロックする場合

- SHARE MODEでロックする場合

- SHARE ROW EXCLUSIVE MODEでロックする場合

- EXCLUSIVE MODEでロックする場合

参照:
LOCK TABLE文の構文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ROW SHARE MODEおよびROW EXCLUSIVE MODEでロックする場合

共有(ROW SHARE MODE)表ロック、および排他(ROW EXCLUSIVE MODE)表ロックは最も高い同時実効性を提供します。次のような場合に使用します。

- トランザクション内で表を更新する前に、別のトランザクションが共有表ロック、行共有表ロックまたは排他表ロックを割り込んで取得しないようにする必要がある場合。
別のトランザクションが共有表ロック、行共有表ロックまたは排他表ロックを割り込んで取得した場合、他のどのトランザクションも、そのロックしているトランザクションがコミットまたはロールバックされるまで、表を更新できません。

- トランザクションで表を変更できるようになるまで、表の変更または削除を防止する必要がある場合。

SHARE MODEでロックする場合

SHARE MODE表ロックは非常に制限の多いデータ・ロックです。次のような場合に使用します。

- トランザクションが表を問い合せるのみで、そのトランザクションの存続中一貫した一連の表データを必要とする場合。

- 表に対してSHARE MODEロックを保持するすべてのトランザクションがコミットまたはロールバックするまで、ロックされている表を更新しようとする他のトランザクションを阻止できる場合。

- 他のトランザクションが、ロックされている表に対して同時にSHARE MODE表ロックを取得でき、またトランザクション・レベルの読取り一貫性のオプションを使用できる場合。

注意:
同じトランザクション内で、後から表を更新しないこともあります。ただし、複数のトランザクションが同じ表に対して共有表ロックを同時に保持している場合は(SELECT FOR UPDATE文の結果によって行ロックが保持されている場合でも)、どのトランザクションも表を更新できません。したがって、同じ表に対する同時共有表ロックがよく発生する場合は、更新処理を継続できず、デッドロックがよく発生することになります。このような場合には、かわりに共有行排他ロックまたは排他表ロックを使用してください。

シナリオ: 表employeesおよびbudget_tabは、第3の表departmentsの一貫した一連のデータを必要とします。特定の部門番号に関して、employeesおよびbudget_tabの情報を更新し、この2つのトランザクションの間にメンバーが部門に追加されないように保証するものとします。

解決方法: 例2-1のようにdepartments表をSHARE MODEでロックします。departments表の更新はまれなため、ロックしても他の多くのトランザクションの待機時間が長くなることはありません。

例2-1 SHARE MODEでのLOCK TABLE

-- Create and populate table:

DROP TABLE budget_tab;
CREATE TABLE budget_tab (
sal     NUMBER(8,2),
deptno  NUMBER(4)
);

INSERT INTO budget_tab (sal, deptno)
SELECT salary, department_id
FROM employees;

-- Lock departments and update employees and budget_tab:

LOCK TABLE departments IN SHARE MODE;

UPDATE employees
SET salary = salary * 1.1
WHERE department_id IN
(SELECT department_id FROM departments WHERE location_id = 1700);

UPDATE budget_tab
SET sal = sal * 1.1
WHERE deptno IN
(SELECT department_id FROM departments WHERE location_id = 1700);

COMMIT;  -- COMMIT releases lock

SHARE ROW EXCLUSIVE MODEでロックする場合

共有(SHARE ROW EXCLUSIVE MODE)表ロックは、次のような場合に使用します。

- トランザクションで、特定の表についてトランザクション・レベルの読取り一貫性があり、かつ、ロックされている表が更新可能であることが必要な場合。

- 他のトランザクションによる(SELECT FOR UPDATEを使用した)明示的な行ロックの可能性を考慮していない場合。ロック中のトランザクション内のUPDATEおよびINSERT文が待機させられ、デッドロックが発生する可能性があります。

- このように動作するトランザクションが1つのみ必要な場合。

EXCLUSIVE MODEでロックする場合

排他(EXCLUSIVE MODE)表ロックは、次のような場合に使用します。

- トランザクションが、ロックされている表にすぐに更新アクセスをする必要がある場合。トランザクションが排他表ロックを保持していると、他のトランザクションはロックされた表の中の特定の行をロックできません。

- トランザクションがコミットまたはロールバックされるまで、ロックされた表に対してトランザクション・レベルの読取り一貫性が保持される場合。

- 低レベルのデータ同時実行性を意識する必要がなく、排他表ロックを要求するトランザクションを順次待機させて表を順番に更新させる場合。

Oracle Databaseによる表ロック制御

Oracle Databaseに表ロック制御を任せると、アプリケーションに必要なプログラム・ロジックが少なくて済みます。ただし、表ロックを自分で管理する場合より制御範囲が小さくなります。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE文またはALTER SESSION ISOLATION LEVEL SERIALIZABLE文を発行すると、基礎となるロック・プロトコルを変更しなくても、ANSIのシリアライズ可能性を維持できます。この手法によって、ANSIのシリアライズ可能性を維持しながら表へ同時アクセスできます。表をロックすることによって、同時実行性が大幅に減少します。

参照:

- SET TRANSACTION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- ALTER SESSION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

これらのパラメータの設定変更は、インスタンスの停止時にのみ行ってください。複数インスタンスが単一データベースにアクセスする場合は、すべてのインスタンスでこれらのパラメータの設定を同じにする必要があります。

明示的な行ロック

FOR UPDATE句を含むSELECT文を使用すると、デフォルト・ロックをオーバーライドできます。この文は、選択されている行がその後の文で更新されることを想定し、(UPDATE文のように)選択された行に対する明示的な行ロックを取得します。

SELECT FOR UPDATE文を使用すると、実際にその行を変更せずに行をロックできます。たとえば、『Oracle Database PL/SQL言語リファレンス』では、いくつかのトリガーで参照整合性を実装する方法を示しています。EMP_DEPT_CHECKトリガーでは、参照される親キー値を含む行が、トランザクションの存続中は同じ値のままであることを保証するためにロックされます。親キーが更新または削除された場合、参照整合性違反になります。

SELECT FOR UPDATE文は、ユーザーが1行以上の特定行のフィールドを変更できるような対話型プログラムでよく使用されます(時間がかかることがあります)。行を更新している対話型プログラム・ユーザーが常に1ユーザーのみであるように、行がロックされます。

カーソル定義にSELECT FOR UPDATE文が使用される場合は、カーソルがオープンされるとき(最初のフェッチの前)に結果セット内の行がロックされます。行は、カーソルからフェッチされるときに、個別にロックされるわけではありません。カーソルをオープンしたトランザクションがコミットまたはロールバックされたときにのみ、ロックが解除されます。カーソルがクローズされるときには、ロックは解除されません。

SELECT FOR UPDATE文の結果セット内の各行は個別にロックされます。SELECT FOR UPDATE文は、競合している行ロックを他のトランザクションが解除するまで待機します。したがって、SELECT FOR UPDATE文が表の行を多数ロックし、表に対して非常に多くの更新アクティビティが発生する場合は、EXCLUSIVE表ロックを取得する方がパフォーマンスが改善する場合があります。

注意:
問合せの実行中に、SELECT FOR UPDATE文に対する結果セットが変化する場合があります。たとえば、問合せ開始後に問合せで選択された列が更新されたり、行が削除された場合です。このような場合、SELECT FOR UPDATEは変更されなかった行でロックを取得し、このロックを使用して表の読取り一貫性スナップショットを取得してから、残りのロックを取得するために問合せを再起動します。
アプリケーションでSELECT FOR UPDATE文を使用する場合に、競合するロック・リクエストによってユーザーが原因のデッドロックが発生しないことを保証できない場合は(たとえば、表の同時実行DML文がSELECT FOR UPDATE文の問合せの結果セットに影響を与えないことを確認することによって)、このようなデッドロック(ORA-00060)をアプリケーションが常に適切に処理するようにコーディングします。

デフォルトでは、要求された行ロックが取得されるまでSELECT FOR UPDATE文は待機します。この動作を変更するには、SELECT FOR UPDATE文でNOWAIT、WAIT、またはSKIP LOCKED句を使用します。このような句の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

明示的なロックにおける同時実行性の例

表2-3に、LOCK TABLE文およびFOR UPDATE句を含むSELECT文が使用された場合に、データの同時実行性、整合性および一貫性がOracle Databaseでどのように維持されるかを示します。簡略にするため、ORA-00054のメッセージ・テキスト(「リソース・ビジー、NOWAITが指定されていました。)は記載していません。ユーザーが入力するテキストは太字で表示しています。

注意:
ハイブリッド列圧縮(HCC)で圧縮された表では、DML文によって行ではなく圧縮単位がロックされます。特定のOracleストレージ・システムの機能であるHCCの詳細は、『Oracle Database概要』を参照してください。

表2-3 明示的なロックにおける同時実行性の例

トランザクション1

タイム・ポイント

トランザクション2

LOCK TABLE hr.departments
IN ROW SHARE MODE;

Statement processed.

1

2

DROP TABLE hr.departments;

DROP TABLE hr.departments
*
ORA-00054

(トランザクション1によって表がロックされているため、排他DDLロックを取得できません。)

3

LOCK TABLE hr.departments
IN EXCLUSIVE MODE
NOWAIT;

ORA-00054

4

SELECT location_id
FROM hr.departments
WHERE department_id = 20
FOR UPDATE OF location_id;

LOCATION_ID
-----------
DALLAS

1 row selected.

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 20;

(トランザクション2によって同じ行がロックされているため待機します。)

5

6

ROLLBACK;

(行ロックを解放します。)

1 row processed.

ROLLBACK;

7

LOCK TABLE hr.departments
IN ROW EXCLUSIVE MODE;

Statement processed.

8

9

LOCK TABLE hr.departments
IN EXCLUSIVE MODE
NOWAIT;

ORA-00054

10

LOCK TABLE hr.departments
IN SHARE ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

11

LOCK TABLE hr.departments
IN SHARE ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

12

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 20;

1 row processed.

13

ROLLBACK;

SELECT location_id
FROM hr.departments
WHERE department_id = 20
FOR UPDATE OF location_id;

LOCATION_ID
-----------
DALLAS

1 row selected.

14

15

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 20;

1 row processed.

(トランザクション1によって同じ行がロックされているため待機します。)

ROLLBACK;

16

17

1 row processed.

(競合するロックが解放されました。)

ROLLBACK;

LOCK TABLE hr.departments
IN ROW SHARE MODE

Statement processed.

18

19

LOCK TABLE hr.departments
IN EXCLUSIVE MODE
NOWAIT;

ORA-00054

20

LOCK TABLE hr.departments
IN SHARE ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

21

LOCK TABLE hr.departments
IN SHARE MODE;

Statement processed.

22

SELECT location_id
FROM hr.departments
WHERE department_id = 20;

LOCATION_ID
-----------
DALLAS

1 row selected.

23

SELECT location_id
FROM hr.departments
WHERE department_id = 20
FOR UPDATE OF location_id;

LOCATION_ID
-----------
DALLAS

1 row selected.

24

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 20;

(トランザクション1に競合する表ロックがあるため待機します。)

ROLLBACK;

25

26

1 row processed.

(競合する表ロックが解放されました。)

ROLLBACK;

LOCK TABLE hr.departments
IN SHARE ROW EXCLUSIVE MODE;

Statement processed.

27

28

LOCK TABLE hr.departments
IN EXCLUSIVE MODE
NOWAIT;

ORA-00054

29

LOCK TABLE hr.departments
IN SHARE ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

30

LOCK TABLE hr.departments
IN SHARE MODE
NOWAIT;

ORA-00054

31

LOCK TABLE hr.departments
IN ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

32

LOCK TABLE hr.departments
IN SHARE MODE
NOWAIT;

ORA-00054

33

SELECT location_id
FROM hr.departments
WHERE department_id = 20;

LOCATION_ID
-----------
DALLAS

1 row selected.

34

SELECT location_id
FROM hr.departments
WHERE department_id = 20
FOR UPDATE OF location_id;

LOCATION_ID
-----------
DALLAS

1 row selected.

35

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 20;

(トランザクション1に競合する表ロックがあるため待機します。)

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 20;

(トランザクション2によって同じ行がロックされているため待機します。)

36

(デッドロックが発生します。)

Cancel operation.

ROLLBACK;

37

38

1 row processed.

LOCK TABLE hr.departments
IN EXCLUSIVE MODE;

39

40

LOCK TABLE hr.departments
IN EXCLUSIVE MODE;

ORA-00054

41

LOCK TABLE hr.departments
IN ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

42

LOCK TABLE hr.departments
IN SHARE MODE;

ORA-00054

43

LOCK TABLE hr.departments
IN ROW EXCLUSIVE MODE
NOWAIT;

ORA-00054

44

LOCK TABLE hr.departments
IN ROW SHARE MODE
NOWAIT;

ORA-00054

45

SELECT location_id
FROM hr.departments
WHERE department_id = 20;

LOCATION_ID
-----------
DALLAS

1 row selected.

46

SELECT location_id
FROM hr.departments
WHERE department_id = 20
FOR UPDATE OF location_id;

(トランザクション1に競合する表ロックがあるため待機します。)

UPDATE hr.departments
SET department_id = 30
WHERE department_id = 20;

1 row processed.

47

COMMIT;

48

49

0 rows selected.

(トランザクション1の競合するロックが解放されました。)

SET TRANSACTION READ ONLY;

50

SELECT location_id
FROM hr.departments
WHERE department_id = 10;

LOCATION_ID
-----------
BOSTON

51

52

UPDATE hr.departments
SET location_id = 'NEW YORK'
WHERE department_id = 10;

1 row processed.

SELECT location_id
FROM hr.departments
WHERE department_id = 10;

LOCATION_ID
-----------
BOSTON

(トランザクション1には、未コミット・データが表示されません。)

53

54

COMMIT;

SELECT location_id
FROM hr.departments
WHERE department_id = 10;

LOCATION_ID
-----------
BOSTON

(トランザクション2がコミットした後でも同じ結果になります。)

55

COMMIT;

56

SELECT location_id
FROM hr.departments
WHERE department_id = 10;

LOCATION_ID
-----------
NEW YORK

(コミット済データが表示されます。)

57

Oracle Lock Managementサービス(ユーザー・ロック)の使用

DBMS_LOCKパッケージのサブプログラムを起動することで、アプリケーションはOracle Lock Managementサービス(ユーザー・ロック)を使用できます。アプリケーションは、特定のモードのロックを要求し、同一または別のインスタンスの別のサブプログラムで認識できる一意の名前を付け、ロック・モードを変更し、解除できます。確保されるユーザー・ロックはOracle Databaseロックであるため、デッドロックの検出などのデータベース・ロックのすべての機能を持っています。分散トランザクションで使用されるユーザー・ロックは、COMMITと同時に解除されるようになっていることを確認してください。解除されないと、検出されないデッドロックが発生する可能性があります。

参照:
DBMS_LOCKパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

内容は次のとおりです。

- ユーザー・ロックを使用する場合

- ロックの表示および監視

ユーザー・ロックを使用する場合

次のような場合、ユーザー・ロックが役立ちます。

- 端末などの装置に対して排他的アクセスを可能にする場合

- アプリケーション・レベルの読込みロックを適用する場合

- ロックの解除を検出し、アプリケーションの終了後にクリーンアップする場合

- アプリケーションを同期化して、順次処理を実行する場合

例2-2は、複数のユーザーが1つのデバイスにアクセスする必要がある場合に、競合が発生しないように保証するためのPro*COBOLプリコンパイラでのロックの使用方法を示しています。

例2-2 Pro*COBOLプリコンパイラによるロックの使用方法

******************************************************************
* Print Check                                                    *
* Any cashier may issue a refund to a customer returning goods.  *
* Refunds under $50 are given in cash, more than $50 by check.   *
* This code prints the check. One printer is opened by all       *
* the cashiers to avoid the overhead of opening and closing it   *
* for every check, meaning that lines of output from multiple    *
* cashiers can become interleaved if you do not ensure exclusive *
* access to the printer. The DBMS_LOCK package is used to        *
* ensure exclusive access.                                       *
******************************************************************
CHECK-PRINT
*    Get the lock "handle" for the printer lock.
MOVE "CHECKPRINT" TO LOCKNAME-ARR.
MOVE 10 TO LOCKNAME-LEN.
EXEC SQL EXECUTE
BEGIN DBMS_LOCK.ALLOCATE_UNIQUE ( :LOCKNAME, :LOCKHANDLE );
END; END-EXEC.
*   Lock the printer in exclusive mode (default mode).
EXEC SQL EXECUTE
BEGIN DBMS_LOCK.REQUEST ( :LOCKHANDLE );
END; END-EXEC.
*   You now have exclusive use of the printer, print the check.
...
*   Unlock the printer so other people can use it
EXEC SQL EXECUTE
BEGIN DBMS_LOCK.RELEASE ( :LOCKHANDLE );
END; END-EXEC.

ロックの表示および監視

表2-4では、インスタンスで処理中のトランザクションのロック情報を表示する、Oracle Databaseの機能について説明しています。

表2-4 ロック情報の表示方法

ツール

説明

Oracle Enterprise Manager Database Control

データベース・ロックページで、別のユーザーまたはアプリケーションからブロックされているユーザー・ロック、すべてのデータベース・ロックを表示します。詳細は、『Oracle Database 2日でReal Application Clustersガイド』を参照してください。

パフォーマンス監視データ・ディクショナリ・ビュー

『Oracle Database管理者ガイド』を参照してください。

UTLLOCKT.SQL

UTLLOCKT.SQLスクリプトは、ツリー構造の簡単なロック待機グラフを表示します。スクリプトの実行にSQLツール(SQL*Plusなど)を使用し、システム内のロック待機中のセッション、およびそれに対応するブロッキング・ロックを出力します。このスクリプト・ファイルの位置は、オペレーティング・システムによって異なります。(UTLLOCKT.SQLを使用する前に、CATBLOCK.SQLスクリプトを実行する必要があります。)

シリアライズ可能トランザクションを使用した同時実行性の制御

Oracle Databaseは、デフォルトでは、同時に実行されるトランザクションの同じ表および同じデータ・ブロック内での行の修正、追加または削除を許可しています。トランザクションAが表を変更すると、トランザクションAがコミットされるまで、同時に実行しているトランザクションでは参照できません。トランザクションAが、(DML文またはSELECT FOR UPDATE文を使用して)別のトランザクションBによってロックされている行を更新または削除しようとすると、トランザクションAのDML文は、トランザクションBがコミットまたはロールバックされるまでブロックされます。この同時実行性モデルは、より高度な同時実行性が提供されて、パフォーマンスが改善されるため、ほとんどのアプリケーションに適しています。

ただし、まれにシリアライズ可能なトランザクションが必要な場合もあります。シリアライズ可能トランザクションは、シリアル・モードで同時に実行します。シリアル・モードでは、同時トランザクションは、それらのトランザクションが順次(つまり一度に1つずつ)実行された場合に可能となるデータベースの変更のみが可能です。シリアライズ可能トランザクションの開始以降に、別のトランザクションにより変更されたデータを変更しようとすると、ORA-08177が発生します。

シリアライズ可能トランザクションがORA-08177で失敗した場合、アプリケーションは次のいずれかで対処できます。

- そのポイントまで実行された作業をコミットします。

- その他の様々な文を、トランザクション内の直前のセーブポイントまでロールバックした後に実行します。

- トランザクションをロールバックし再度実行します。
トランザクションがトランザクション・スナップショットを取得するため、操作が成功する可能性が高くなります。

ヒント:
トランザクションのロールバックおよび再実行によるパフォーマンスのオーバーヘッドを最小化するには、他の同時トランザクションと競合する可能性のあるDML文は、できるだけトランザクションの始めの方に置くようにしてください。

注意:
シリアライズ可能トランザクションは遅延セグメント作成または時間隔パーティション化とともに動作しません。セグメントが作成されていない空の表、またはセグメントがまだない時間隔パーティション化された表のパーティションにデータを挿入しようとすると、エラーが発生します。

内容は次のとおりです。

- トランザクションの相互作用と分離レベル

- 分離レベルの設定

- シリアライズ可能トランザクションおよび参照整合性

- READ COMMITTEDおよびSERIALIZABLE分離レベル

トランザクションの相互作用と分離レベル

ANSI/ISO SQL標準は3種類のトランザクションの相互作用を定義しています。

トランザクションの相互作用

定義

内容を保証しない読込み

トランザクションAはトランザクションBによるコミットされていない変更を読み込みます。

反復不能な読込み

トランザクションAはデータを読み込み、トランザクションBがデータを変更して変更をコミットし、トランザクションAがデータを再度読み込み、変更を確認します。

仮読込み

トランザクションAが問合せを実行し、トランザクションBが新しい行を挿入して変更をコミットし、トランザクションAが問合せを繰り返して新しい行を確認します。

トランザクションが可能な相互作用の種類は分離レベルによって決まります。ANSI/ISO SQL標準は4レベルの分離を定義しています。表2-5に、各分離レベルで可能な相互作用の種類を示します。

表2-5 ANSI/ISO SQL分離ラベルおよび可能なトランザクションの相互作用

分離レベル

内容を保証しない読込み

反復不能な読込み

仮読込み

READ UNCOMMITTED

可能性あり

可能性あり

可能性あり

READ COMMITTED

可能性なし

可能性あり

可能性あり

REPEATABLE READ

可能性なし

可能性なし

可能性あり

SERIALIZABLE

可能性なし

可能性なし

可能性なし

表2-6に、Oracle Databaseで用意されるANSI/ISO SQLトランザクション分離レベルを示します。

表2-6 Oracle Databaseで用意されるANSI/ISO SQL分離レベル

分離レベル

Oracle Databaseで用意される

READ UNCOMMITTED

いいえ、Oracle Databaseでは「内容を保証しない読込み」は許可されません。他のデータベース製品の中には、スループットの改善のために、この方法を使用するものもありますが、スループットの高いOracle Databaseでは不要です。

READ COMMITTED

はい(デフォルト)。Oracle Databaseでは、問合せの始め(スナップショット時)にコミット済のデータのみを参照するため、READ COMMITTED分離についてANSI/ISO SQL標準以上の整合性を提供します。

REPEATABLE READ

はい、トランザクション分離レベルをSERIALIZABLEに設定する場合。

SERIALIZABLE

はい、トランザクション分離レベルをSERIALIZABLEに設定する場合。

図2-1に、任意のトランザクション(SERIALIZABLEまたはREAD COMMITTEDのいずれか)とシリアライズ可能トランザクションとの相互作用を示します。

図2-1 シリアライズ可能トランザクションと別のトランザクションの相互作用

分離レベルの設定

トランザクション分離レベルをセッション全体のトランザクションに設定するには、ALTER SESSION文を使用します。『Oracle Database SQL言語リファレンス』を参照してください。

トランザクション分離レベルを特定のトランザクションに設定するには、SET TRANSACTION文のISOLATION LEVEL句を使用します。SET TRANSACTION文は『Oracle Database SQL言語リファレンス』で説明しているように、トランザクションの最初の文である必要があります。

注意:
トランザクション分離レベルをSERIALIZABLEに設定する場合は、ALTER TABLE文を使用して、INITRANSパラメータを3以上に設定する必要があります。多数のトランザクションが同じブロックを更新する表では、この値を大きくします。INITRANSの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

シリアライズ可能トランザクションおよび参照整合性

Oracle Databaseは、SERIALIZABLEトランザクション内であっても読込みロックを使用しないため、あるトランザクションによって読み込まれたデータは、別のトランザクションでオーバーライドできます。そのため、アプリケーション・レベルでデータベースの整合性チェックを実行するトランザクションでは、読み込んだデータはトランザクション中には変更されないと考えないでください(そのような変更がトランザクションからはわからない場合も)。SERIALIZABLEトランザクションを使用した場合でも、アプリケーション・レベルの整合性チェックのコードを十分注意して作成してください。

図2-2に、2つの表の間の参照整合性の親子関係を保持するために、アプリケーション・レベルでチェックを実行するトランザクションAとB (READ COMMITTEDまたはSERIALIZABLEのいずれか)を示します。トランザクションAは、親表に問い合せて特定の主キー値を持つ行が存在するかどうかをチェックした後、対応する子行を子表に挿入します。トランザクションBは、子表に問い合せて特定の主キー値を持つ子行が存在しないことをチェックした後、親表から対応する親行を削除します。この場合、両方のトランザクションが読み込んだデータは、そのトランザクションが完了する前には変更されないものと想定しています(確認はしません)。

図2-2 参照整合性チェック

トランザクションAが実行した問合せのために、トランザクションBが親行を削除できなくなることはありません。トランザクションBが実行した問合せのために、トランザクションAが子行を挿入できなくなることもありません。したがって、次のことが起こる可能性があります。

1. トランザクションAは親表に問い合せて、指定した親行を確認します。

2. トランザクションBは子表に問い合せて、指定した親行が子行を持たないことを確認します。

3. 指定した親行を確認して、トランザクションAは対応する子行を子表に挿入します。

4. 指定した親行が子行を持たないことを確認して、トランザクションBは指定した親行を親表から削除します。
これで、トランザクションAが手順3で挿入した子行には親行がなくなりました。

このような結果は、AおよびBの両方がSERIALIZABLEトランザクションであったとしても発生する可能性があります。どちらのトランザクションも、整合性チェックのために読み込んだデータに対する変更を他方が妨げないからです。

あるトランザクションが問い合せたデータが別のトランザクションにより同時に変更または削除されないようにするには、ANSI/ISO SQL標準のSERIALIZABLE分離レベルが提供するよりも高いレベルのトランザクション分離が必要です。ただしOracle Databaseでは、次のことが可能です。

- トランザクションAはSELECT FOR UPDATE文を使用して、親行を問い合せてロックし、トランザクションBがその行を削除しないようにします。
SELECT文のFOR UPDATE句の詳細は、 『Oracle Database SQL言語リファレンス』を参照してください。

- トランザクションBは、処理手順を逆にして、トランザクションAが親行を見つけられないようにします(その結果、子行を挿入できなくなります)。つまりトランザクションBは次のことができます。

1. 親行を削除します。

2. 子表を問い合わせます。

3. 削除した親行に、子表内の子行がある場合は、親行の削除をロールバックします。

または、トリガーを使用して参照整合性を施行することもできます。トランザクションAが親表を問い合せるかわりに、子表で次を行う行レベルBEFORE INSERTトリガーを定義します。

- SELECT FOR UPDATE文を使用して親表を問い合わせ、親行が存在するかどうかを確認することで、子行を挿入するトランザクションの処理中に、親行がデータベース内に残るようにします。

- 親行が存在しない場合、子行の挿入は拒否されます。

参照:
トリガーを使用した親表と子表の間の参照整合性の維持の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

トリガーによって発行されたSQL文は、そのトリガーを起動した文のコンテキスト内で実行されます(トリガー起動文とトリガー起動された文は同じデータベース状態を参照します)。そのため、READ COMMITTEDトランザクションがトリガー起動文を実行する場合、トリガー起動された文は、トリガー起動文の実行開始時点のデータベースを参照します。SERIALIZABLEトランザクションがトリガー起動文を実行する場合、トリガー起動された文は、そのトランザクションの開始時点のデータベースを参照します。いずれの場合も、トリガーで SELECT FOR UPDATEを使用すると、参照整合性が正しく施行されます。

READ COMMITTEDおよびSERIALIZABLE分離レベル

Oracle Databaseでは、READ COMMITTEDおよびSERIALIZABLEという2つのトランザクション分離レベルが用意されています。どちらのレベルも高度な一貫性および同時実行性を提供し、競合を軽減し、実社会でのアプリケーション用に設計されています。この項では、2つの分離レベルを比較し、その選択方法を説明します。

内容は次のとおりです。

- トランザクション集合の整合性の違い

- トランザクション分離レベルの選択

トランザクション集合の整合性の違い

どの読込みにおいても、同じコミット済トランザクション集合によって書き込まれたデータが戻される場合、操作(問合せまたはトランザクション)は、「トランザクション集合整合である」といいます。トランザクション集合整合でない操作では、ある集合のトランザクションの変更が反映される読込みと、他のトランザクションによって行われた変更が反映される読込みが存在します。そのような操作では、そのデータベースは、コミットされたトランザクション集合が反映されていない状態のデータベースのように見えます。

内容は次のとおりです。

- Oracle Database

- 他のデータベース・システム

Oracle Database

READ COMMITTED分離レベルでのOracle Databaseトランザクションは、問合せによって読み込まれたすべての行が、その問合せが始まる前にコミットされている必要があるため、文単位でのトランザクション集合整合です。

SERIALIZABLE分離レベルでのOracle Databaseトランザクションは、SERIALIZABLEトランザクション内のすべての文が、トランザクション開始時点のデータベースのイメージに対して実行されるため、トランザクション単位でのトランザクション集合整合です。

他のデータベース・システム

他のデータベース・システムでは、READ UNCOMMITTED分離レベルでの1回の問合せは、トランザクション集合整合ではありません。別のトランザクションによって行われた変更のサブセットしか見えないからです。たとえば、ディテール表とマスター表を結合すると、別のトランザクションによって挿入されたマスター・レコードを見ることはできますが、そのトランザクションによって挿入された対応するディテールは見えません(その逆も同じです)。READ COMMITTED分離レベルではこのような問題は回避されるため、読込みロック・システムより高い整合性が得られます。

読込みロック・システムでは、同時更新ができないようにするかわりに、REPEATABLE READ分離レベルによって、トランザクション・レベルではなく、文レベルでトランザクション集合の整合性が提供されます。仮読込み保護がないため、同一のトランザクションによる2つの問合せが、トランザクションの別の集合によってコミットされたデータを参照できます。これらのシステムでは、スループットに制限がありデッドロックされやすいSERIALIZABLE分離レベルの場合のみ、トランザクション・レベルでのトランザクション集合の整合性が提供されます。

トランザクション分離レベルの選択

トランザクション分離レベルの選択は、パフォーマンスと整合性の必要性、およびアプリケーション・コーディング要件により異なります。同時実行性(トランザクションのスループット)と整合性はトレードオフの関係にあります。トランザクションの分離レベルの選択では、アプリケーションと作業負荷を考慮します。異なるトランザクションにはそれぞれ個別の分離レベルを選択できます。

多数のユーザーが、トランザクションを同時に次々に送る環境の場合、予期されるトランザクション到着頻度、応答時間要件、および必要な整合性の程度を考慮します。

READ COMMITTED分離レベルでは、一部のトランザクションについては(仮読込みおよび反復不能な読込みからの)一貫性のない結果が生成される可能性は多少高くなりますが、かなり高い同時実行性を提供できます。

SERIALIZABLE分離レベルの場合は、仮読込みおよび反復不能な読込みから保護されているため、より高い整合性が提供され、読込み/書込みトランザクションが問合せを2回以上実行する場合にはこの分離レベルは重要です。ただし、SERIALIZABLE分離レベルでは、アプリケーションが「このトランザクションのアクセスをシリアル化できません」というエラーの有無を確認する必要があり、多数の同時トランザクションが更新のために同じデータにアクセスする環境では、スループットはかなり低下する可能性があります。

「シリアライズ可能トランザクションと参照整合性」で説明したように、READ COMMITTEDまたはSERIALIZABLEトランザクションのいずれでも読込みは書込みをブロックしません。

表2-7に、READ COMMITTEDトランザクションとSERIALIZABLEトランザクションの類似点および相違点の概要を示します。

表2-7 READ COMMITTEDトランザクションとSERIALIZABLEトランザクションの比較

操作

READ COMMITTED

SERIALIZABLE

内容を保証しない書込み

可能性なし

可能性なし

内容を保証しない読込み

可能性なし

可能性なし

反復不能な読込み

可能性あり

可能性なし

仮読込み

可能性あり

可能性なし

ANSI/ISO SQL 92への準拠

あり

あり

スナップショット読込み時間

文

トランザクション

トランザクション集合の整合性

文レベル

トランザクション・レベル

行レベル・ロック

あり

あり

読込みが書込みをブロック

なし

なし

書込みが読込みをブロック

なし

なし

異なる行の書込みが書込みをブロック

なし

なし

同じ行の書込みが書込みをブロック

あり

あり

阻止しているトランザクションの待機

あり

あり

エラー「このトランザクションのアクセスをシリアル化できません」の発生する可能性

なし

あり

阻止しているトランザクションの終了後のエラー

なし

なし

阻止しているトランザクションのコミット後のエラー

なし

あり

自律型トランザクション

自律型トランザクション(AT)は、別のトランザクション(メイン・トランザクション(MT))によって開始される独立したトランザクションです。自律型トランザクションを使用すると、メイン・トランザクションを停止して、SQL操作を実行し、そのSQL操作をコミットまたはロールバックした後でメイン・トランザクションを再開できます。

たとえば、株式売買トランザクションでは、売買が成功するかどうかに関係なく、顧客情報のコミットが必要な場合があります。または、トランザクションがロールバックされた場合でも、エラー・メッセージをデバッグ表にログする必要がある場合もあります。自律型トランザクションを使用すると、これらのタスクを実行できます。

自律型トランザクションは自律型スコープ内、つまり、自律型ルーチン(AUTONOMOUS_TRANSACTIONプラグマでマークされるルーチン)の範囲内で実行されます。この場合のルーチンの定義の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

図2-3に、メイン・トランザクション(MT)と自律型トランザクション(AT)との間の制御フローを示します。図からわかるように、自律型トランザクションでは、制御がメイン・トランザクションに戻る前に複数のトランザクション(AT1およびAT2)をコミットできます。

図2-3 トランザクション制御フロー

自律型トランザクションの実行可能セクションに入ると、メイン・トランザクションが停止します。自律型トランザクションを終了すると、メイン・トランザクションが再開します。COMMITおよびROLLBACKによって、アクティブな自律型トランザクションは終了しますが、自律型トランザクションは終了しません。図2-3に示すとおり、1つのトランザクションが終了すると、次のSQL文が別のトランザクションを開始します。

自律型トランザクションの特長をさらに示します。

- 自律型トランザクションが加える変更は、メイン・トランザクションの状態または最終的な処理には依存しません。次に例を示します。

- 自律型トランザクションは、メイン・トランザクションによって加えられた変更を認識しません。

- 自律型トランザクションがコミットまたはロールバックしても、メイン・トランザクションの結果には影響しません。

- 自律型トランザクションが加える変更は、そのトランザクションがコミットした直後に他のトランザクションで参照できます。このため、メイン・トランザクションがコミットするまで待機しなくても、ユーザーは更新された情報にアクセスできます。

- 自律型トランザクションは他の自律型トランザクションを開始できます。

図2-4に、自律型トランザクションが従う実行順序の例を示します。

図2-4 自律型トランザクションの順序

内容は次のとおりです。

- 自律型トランザクションの例

- 自律型トランザクションの定義

参照:
自律型トランザクションの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

自律型トランザクションの例

- 商品の注文

- 銀行口座からの出金処理

例に示すとおり、自律型トランザクションおよびメイン・トランザクションを使用する場合は、4種類の結果が考えられます(表2-8を参照)。自律型トランザクションの結果とメイン・トランザクションの結果の間に依存性はありません。

表2-8 トランザクションの結果

自律型トランザクション

メイン・トランザクション

コミット

コミット

コミット

ロールバック

ロールバック

コミット

ロールバック

ロールバック

商品の注文

図2-5に、顧客がある商品を注文する例を示します。購買契約が成立しなくても、その顧客の情報(名前、住所、電話番号など)は顧客情報表にコミットされます。

図2-5 例: 購買指示

銀行口座からの出金処理

この例では、顧客は銀行口座から払戻しを実行しようとします。この処理で、メイン・トランザクションは2つの自律型トランザクション・スコープ(ATスコープ1またはATスコープ2)のいずれかを起動します。

このトランザクションで考えられる使用例を次に示します。

- 使用例1: 十分な預金残高がある場合

- 使用例2: 貸越し保護があり預金残高が不十分な場合

- 使用例3: 貸越し保護がなく預金残高が不十分な場合

使用例1: 十分な預金残高がある場合

払戻しに十分な預金残高があり、銀行が払戻しに応じます。(図2-6を参照)。

図2-6 預金払戻し - 十分な預金残高がある場合

使用例2: 貸越し保護があり預金残高が不十分な場合

払戻しに十分な預金残高はありませんが、この顧客には貸越し保護があるため、銀行が払戻しに応じます(図2-7を参照)。

図2-7 預金払戻し - 貸越し保護があり預金残高が不十分な場合

使用例3: 貸越し保護がなく預金残高が不十分な場合

払戻しに十分な預金残高はなく、この顧客には貸越し保護もありません。したがって、銀行は払戻しを差し止めます(図2-8を参照)。

図2-8 預金払戻し - 貸越し保護がなく預金残高が不十分な場合

自律型トランザクションの定義

自律型トランザクションを定義するには、PRAGMA AUTONOMOUS_TRANSACTIONを使用します。これは、PL/SQLコンパイラに対して、サブプログラムを自律型としてマークするように指示します。

例2-3では、ファンクションbalanceが自律型です。

例2-3 パッケージ・サブプログラムの自律型としてのマーク

-- Create table for package to use:

DROP TABLE accounts;
CREATE TABLE accounts (account INTEGER, balance REAL);

-- Create package:

CREATE OR REPLACE PACKAGE banking AS
FUNCTION balance (acct_id INTEGER) RETURN REAL;
-- Additional functions and packages
END banking;
/
CREATE OR REPLACE PACKAGE BODY banking AS
FUNCTION balance (acct_id INTEGER) RETURN REAL IS
PRAGMA AUTONOMOUS_TRANSACTION;
my_bal  REAL;
BEGIN
SELECT balance INTO my_bal FROM accounts WHERE account=acct_id;
RETURN my_bal;
END;
-- Additional functions and packages
END banking;
/

参照:
PRAGMA AUTONOMOUS_TRANSACTIONの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

記憶域割当てエラー後の実行の再開

長時間にわたって実行されるトランザクションが記憶域割当てエラー状態によって中断されたときに、アプリケーションによって問題が発生した文を一時停止し、問題を修正した後でその文を再開することが可能です。この機能を、再開可能記憶域割当てといいます。この機能によって、時間がかかるロールバックを回避できます。また、操作を小さく分割したり、処理過程を追跡するコードを作成する必要がなくなります。

参照:
再開可能領域割当ての詳細は、『Oracle Database管理者ガイド』を参照してください。

内容は次のとおりです。

- 再開可能記憶域割当てを含む操作

- 一時停止された記憶域割当ての処理

再開可能記憶域割当てを含む操作

問合せ、DML操作および特定のDDL操作には、次のエラーの後で再開可能な記憶域割当てが含まれます。

- ORA-01653などの領域不足エラー。

- ORA-01628などの領域制限エラー。

- ORA-01536などの領域割当てエラー。

再開可能記憶域割当ては、操作がSQL文によって直接実行されているか、またはSQL*Loader、ストアド・サブプログラム、無名PL/SQLブロック、OCIStmtExecuteなどのOCIコール内で実行されている場合に適用されます。

ディクショナリ管理された表領域では、ロールバック・セグメントの上限に達するか、エクステントの最大数に達した場合、索引または表の作成操作を再開できません。ローカル管理表領域および自動UNDO管理を、再開可能記憶域割当てと組み合せて使用してください。

一時停止された記憶域割当ての処理

記憶域割当てエラーのためにアプリケーション内の文が一時停止された場合、アプリケーションはエラー・コードを受信しません。このため、アプリケーションでAFTER SUSPENDトリガーを使用するか、またはDBAが一時停止された文を定期的に確認する必要があります。

問題が(通常DBAによって)修正されると、一時停止された文は自動的に実行を再開します。タイムアウト周期が終了するまでに問題が修正されなかった場合は、その文によってSERVERERROR例外が発生します。

内容は次のとおりです。

- アプリケーションのAFTER SUSPENDトリガーの使用

- 一時停止された文の確認

アプリケーションのAFTER SUSPENDトリガーの使用

アプリケーションで、AFTER SUSPENDトリガーはDBMS_RESUMABLEパッケージ内のサブプログラムを起動して、問題に関する情報を取得できます(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)。次にトリガーはオペレータに電子メールなどを使用して情報を送信できます。

トリガー自体の中で領域不足エラーが発生する可能性を減らすには、トリガーを自律型トランザクションとして宣言します。自立型トランザクションとして、トリガーはSYSTEM表領域内のロールバック・セグメントを使用します。一時停止された文が保持するロックによってトリガーにデッドロック状態が発生した場合、そのトリガーは終了され、アプリケーションは文の一時停止が発生しなかった場合の本来のエラー状態を受信します。トリガーによって領域不足状態が発生した場合、そのトリガーおよび一時停止された文は両方ともロールバックされます。ロールバックを回避するには、トリガー内の例外ハンドラを使用し、文が再開されるまで待ちます。

トリガーの一般的な情報は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

例2-4のトリガーは、データベース内の記憶域エラーを処理します。いくつかのエラーでは、このトリガーは文を終了し、エラーに関する警告を電子メールを使用してDBAに通知します。他の一時的なエラーでは、8時間以内に記憶域の問題が解決していることを想定して、8時間後に文を再開するように指定しています。この例を実行するには、SYSDBAとしてデータベースに接続する必要があります。

例2-4 AFTER SUSPENDトリガーによる一時停止された記憶域割当ての処理

-- Create table used by trigger body

DROP TABLE rbs_error;
CREATE TABLE rbs_error (
SQL_TEXT VARCHAR2(64),
ERROR_MSG VARCHAR2(64),
SUSPEND_TIME VARCHAR2(64)
);

-- Resumable Storage Allocation

CREATE OR REPLACE TRIGGER suspend_example
AFTER SUSPEND
ON DATABASE
DECLARE
cur_sid           NUMBER;
cur_inst          NUMBER;
err_type          VARCHAR2(64);
object_owner      VARCHAR2(64);
object_type       VARCHAR2(64);
table_space_name  VARCHAR2(64);
object_name       VARCHAR2(64);
sub_object_name   VARCHAR2(64);
msg_body          VARCHAR2(64);
ret_value         BOOLEAN;
error_txt         VARCHAR2(64);
mail_conn         UTL_SMTP.CONNECTION;
BEGIN
SELECT DISTINCT(SID) INTO cur_sid FROM V$MYSTAT;
cur_inst := USERENV('instance');
ret_value := DBMS_RESUMABLE.SPACE_ERROR_INFO
(err_type,
object_owner,
object_type,
table_space_name,
object_name,
sub_object_name);
IF object_type = 'ROLLBACK SEGMENT' THEN
INSERT INTO rbs_error
(SELECT SQL_TEXT, ERROR_MSG, SUSPEND_TIME
FROM DBA_RESUMABLE
WHERE SESSION_ID = cur_sid
AND INSTANCE_ID = cur_inst);

SELECT ERROR_MSG INTO error_txt
FROM DBA_RESUMABLE
WHERE SESSION_ID = cur_sid
AND INSTANCE_ID = cur_inst;

msg_body :=
'Space error occurred: Space limit reached for rollback segment '
|| object_name || ' on ' || to_char(SYSDATE, 'Month dd, YYYY, HH:MIam')
|| '. Error message was: ' || error_txt;

mail_conn := UTL_SMTP.OPEN_CONNECTION('localhost', 25);
UTL_SMTP.HELO(mail_conn, 'localhost');
UTL_SMTP.MAIL(mail_conn, 'sender@localhost');
UTL_SMTP.RCPT(mail_conn, 'recipient@localhost');
UTL_SMTP.DATA(mail_conn, msg_body);
UTL_SMTP.QUIT(mail_conn);
DBMS_RESUMABLE.ABORT(cur_sid);
ELSE
DBMS_RESUMABLE.SET_TIMEOUT(3600*8);
END IF;
COMMIT;
END;
/

一時停止された文の確認

アプリケーションがAFTER SUSPENDトリガーを使用しない場合、DBAは静的データ・ディクショナリ・ビューDBA_RESUMABLE(『Oracle Databaseリファレンス』を参照)を使用して、一時停止された文を定期的に確認する必要があります。

DBAは動的パフォーマンス・ビューV$_SESSION_WAIT(『Oracle Databaseリファレンス』参照)から追加の情報を取得することができます。

3 データベース・アプリケーションでの正規表現の使用

この章では、正規表現と、データベース・アプリケーションにおけるその使用方法について説明します。

内容は次のとおりです。

- 正規表現の概要

- Oracle SQLの正規表現のサポート

- Oracle SQLおよびPOSIX正規表現標準

- Oracle SQL正規表現内の演算子

- SQL文での正規表現の使用: 例

参照:

- 多言語環境でのSQL正規表現関数の使用方法の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

- O'Reilly & Associates社発行、Jonathan Gennick著、『Oracle Regular Expressions Pocket Reference』

- O'Reilly & Associates社発行、Jeffrey E. F. Friedl著、『Mastering Regular Expressions』

正規表現の概要

正規表現は、メタキャラクタ(演算子または演算子に属する)および文字リテラルを使用する検索パターンを指定します(『Oracle Database SQL言語リファレンス』を参照)。

検索パターンは複雑なものが可能です。たとえば、次の正規表現では、fまたはhtで始まり、次にtp、オプションでそれに続くs、最後にコロン(:)で終わる文字列に一致します。

(f|ht)tps?:

前述の例でのメタキャラクタ(演算子とも言います)はカッコ、パイプ記号(|)、疑問符(?)です。文字リテラルは、f、ht、tp、sおよびコロン(:)です。

カッコは複数のパターン要素を1つの要素にグループ化します。パイプ記号(|)は両側の要素であるfとhtの間での選択を示します。疑問符(?)は、直前の要素であるsがオプションであることを示します。したがって、前述の正規表現は次の文字列に一致します。

- http:

- https:

- ftp:

- ftps:

正規表現は、PERLやJavaのようなプログラミング言語の強力なテキスト処理コンポーネントです。たとえば、PERLスクリプトでは、ディレクトリ内の各HTMLファイルの内容を1つの文字列変数に読み取り、正規表現を使用して文字列内のURLを検索できます。多くのアプリケーション開発者がPERLを使用する理由の1つは、この堅牢なパターン・マッチング機能にあります。

Oracle SQLの正規表現のサポート

Oracle SQLは正規表現をサポートしているため、開発者はデータベースに複雑なパターン一致ロジックを実装できます。この手法は、次のような理由で有用です。

- パターン一致ロジックをデータベース内に集中化させることで、中間層アプリケーションがSQL結果セットの文字列処理に集中するのを回避できます。
たとえば、ライフサイエンス分野のユーザーは、通常、DNAとタンパク質の大規模データベースに格納されている生命情報データのパターン分析にPERLを使用しています。従来、[AG].{4}GK[ST]のようなタンパク質配列の一致検索は中間層で処理されていました。SQL正規表現機能は、処理ロジックをデータに近づけることで、より有効なソリューションを提供します。

- サーバー側の正規表現を使用して制約を規定すると、検証ロジックを複数のクライアントで複製するのを回避できます。

Oracle SQLは、表3-1で概要を示すパターン一致条件および関数の正規表現をサポートします。各パターン・マッチャーは指定したパターン(正規表現を使用して記述)を含む文字列を検索し、そこでは表3-2に示すパターン一致オプションが指定されます。関数には追加のオプション(パターンを含む文字列の検索開始位置など)があります。詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

表3-1 Oracle SQL パターン一致条件および関数

名前

説明

REGEXP_LIKE

条件を問合せのWHERE句で使用すると、特定パターンと一致する行が戻されます。

例: 次のWHERE句では、StevenまたはStephenという名前を持つ従業員が識別されます。

WHERE REGEXP_LIKE((hr.employees.first_name, '^Ste(v|ph)en$')

REGEXP_COUNT

関数では、指定した文字列での特定パターンの出現回数が戻されます。

例: 次の関数呼出しでは、文字列'Albert Einstein'における開始位置7からのe(Eではない)の出現回数が戻されます。

REGEXP_COUNT('Albert Einstein', 'e', 7, 'c')

(cオプションは大/小文字を区別する一致を指定するので戻される値は1です。)

REGEXP_INSTR

関数では、指定した文字列での特定パターンの開始位置を示す整数が戻されます。または、パターンの直後の位置を示す整数を戻すこともできます。

例: 次の関数呼出しでは、hr.employees.email列で最初に有効な電子メール・アドレスの開始位置が戻されます。

REGEXP_INSTR(hr.employees.email, '\w+@\w+(\.\w+)+')

戻された値がゼロよりも大きい場合、列には有効な電子メール・アドレスが含まれています。

REGEXP_REPLACE

関数では、指定した文字列での特定パターンの出現を、置換文字列で置き換えた結果の文字列を戻します。

例: 次の関数呼び出しでは、hr.countries.country_name列の各文字の後に空白が1つ挿入されます。

REGEXP_REPLACE(hr.countries.country_name, '(.)', '\1 ')

REGEXP_SUBSTR

関数は、REGEXP_INSTRと似ていますが、文字列での特定パターンの開始位置を戻すかわりに、一致したサブストリング自体を戻します。

例: 次の関数呼び出しでは、xオプションによりパターン内の空白が無視されるので、'Oracle'が戻されます。

REGEXP_SUBSTR('Oracle 2010', 'O r a c l e', 1, 1, 'x')

表3-2に、表3-1の各パターン・マッチャーで使用可能なパターン一致オプションを示します。

表3-2 Oracle SQL パターン一致条件および関数のパターン一致オプション

オプション

説明

例

i

大/小文字区別なしの一致を指定します。

次の関数呼び出しでは、3が戻されます。

REGEXP_COUNT('Albert Einstein', 'e', 'i')

c

大/小文字区別ありの一致を指定します。

次の関数呼び出しでは、2が戻されます。

REGEXP_COUNT('Albert Einstein', 'e', 'c')

n

ドット演算子(.)を改行文字と一致させることができますが、これはデフォルトではありません(表3-3を参照)。

次の関数呼び出しでは、nオプションが指定されているので、文字列および検索パターンに一致します。

REGEXP_SUBSTR('a'||CHR(10)||'d', 'a.d', 1, 1, 'n')

m

複数行モードを指定します。文字列内の改行文字で行が終了します。文字列に複数の行を含めることができます。

複数行モードはPOSIX演算子の行頭アンカー(^)および行末アンカー($)(表3-3を参照)に影響を与えますが、PERLの影響を受ける演算子\A、\Zおよび\z(表3-5を参照)には影響しません。

次の関数呼び出しでは、acが戻されます。

REGEXP_SUBSTR('ab'||CHR(10)||'ac', '^a.', 1, 2, 'm')

x

検索パターン内の空白文字が無視されます。デフォルトでは、空白文字はそれ自体に一致します。

次の関数呼び出しでは、abcdが戻されます。

REGEXP_SUBSTR('abcd', 'a b c d', 1, 1, 'x')

Oracle SQLおよびPOSIX正規表現標準

Oracle SQLの正規表現の実装は、次の標準に準拠しています。

- IEEEのPortable Operating System Interface(POSIX)標準ドラフト1003.2/D11.2
Oracle SQLは、ASCII(英語)データの照合に関してPOSIX標準に定義されている正規表現演算子の構文と一致セマンティクスに正確に準拠しています。POSIX標準のドラフトについては、次のURLを参照してください。

http://www.opengroup.org/onlinepubs/007908799/xbd/re.html

詳細は、「Oracle SQL正規表現内のPOSIX演算子」を参照してください。

- Unicode ConsortiumのUnicode正規表現ガイドライン

Oracle SQLでは、正規表現サポートがPOSIX標準を超えて次のように拡張されています。

- 多言語データの照合機能が拡張されています。
詳細は、「Oracle SQLのPOSIX標準に対する多言語拡張機能」を参照してください。

- POSIX標準には含まれていないが競合もしない(文字クラスのショートカットや最短一致修飾子(?)など)、よく使用されるPERL正規表現演算子をサポートします。
詳細は、「Oracle SQLのPOSIX標準に対するPERLの影響を受ける拡張機能」を参照してください。

Oracle SQL正規表現内の演算子

Oracle SQLは正規表現内で一連の共通演算子(メタキャラクタから構成)をサポートします。

注意:
メタキャラクタの解析は、正規表現をサポートするツールによって異なります。別の環境からOracle Databaseへ正規表現を移植する場合は、Oracle SQLにより正規表現の構文がサポートされ、予想どおりに解析されることを確認してください。

内容は次のとおりです。

- Oracle SQL正規表現内のPOSIX演算子

- Oracle SQLのPOSIX標準に対する多言語拡張機能

- Oracle SQLのPOSIX標準に対するPERLの影響を受ける拡張機能

Oracle SQL正規表現内のPOSIX演算子

表3-3に、POSIX標準拡張正規表現(ERE)構文に定義されたPOSIX演算子の概要を示します。Oracle SQLはASCII(英語)データの照合に関し、POSIX標準に定義されたこれらの演算子の構文と一致セマンティクスに完全に準拠します。Oracle SQLと POSIX標準でアクションが異なる場合は「説明」列に示されています。

表3-3 Oracle SQL正規表現内のPOSIX演算子

演算子構文

名前

説明

例

.

任意の文字

ドット

データベース・キャラクタ・セットの任意の1文字に一致します。n一致オプションが指定されている場合は、改行文字にも一致します(表3-2を参照)。

Linux、UNIXおよびWindowsプラットフォームでは、改行文字はラインフィード文字(\x0a)として認識されます。

Macintoshプラットフォームでは、改行文字はキャリッジ・リターン文字(\x0d)として認識されます。

注意: POSIX標準では、この演算子はNULLおよび改行文字以外の任意の英字に一致します。

正規表現a.bは、文字列abb、acbおよびadbに一致しますが、accには一致しません。

+

1つ以上

プラス数量子

直前の部分正規表現の1回以上の出現に一致します(最長一致脚注1)。

正規表現a+は文字列a、aaおよびaaaに一致しますが、baまたはabには一致しません。

*

ゼロ以上

星型数量子

直前の部分正規表現のゼロ回以上の出現に一致します(最長一致脚注1)。

正規表現ab*cは、文字列ac、abcおよびabbcに一致しますが、abbまたはbbcには一致しません。

?

ゼロまたは1つ

疑問符数量子

直前の部分正規表現のゼロまたは1回の出現に一致します(最長一致脚注1)。

正規表現ab?cは、文字列abcおよびacに一致しますが、abbcまたはadcには一致しません。

{m}

繰返し

特定数

直前の部分正規表現のm個の連続に一致します。

正規表現a{3}は、文字列aaaに一致しますが、aaには一致しません。

{m,}

繰返し

最小数

直前の部分正規表現のm回以上の出現に一致します(最長一致脚注1)。

正規表現a{3,}は、文字列aaaおよびaaaaに一致しますが、aaには一致しません。

{m,n}

繰返し

個数範囲

直前の部分正規表現のm回以上n回以下の出現に一致します(最長一致脚注1)。

正規表現a{3,5}は、文字列aaa、aaaaおよびaaaaaに一致しますが、aaまたはaaaaaaには一致しません。

[char...]

一致文字リスト

カッコで囲まれたリスト内の任意の1文字に一致します。リスト内では、次の演算子を除くすべての演算子はリテラルとして処理されます。

- 範囲演算子: -

- POSIX文字クラス: [: :]

- POSIX照合要素: [. .]

- POSIX文字等価クラス: [= =]

ハイフン(-)は、リストの先頭または最後にある場合はリテラルで、[#--]のように範囲正規表現にある場合は範囲終了ポイントです。右カッコ(])は、リストの先頭にある場合はリテラルとして扱われます。

注意: POSIX標準では、範囲には現行ロケールの言語定義による範囲の開始から終了までの照合要素がすべて含まれます。したがって、範囲はバイト値の範囲ではなく言語によるもので、範囲正規表現のセマンティクスはキャラクタ・セットに依存しません。Oracle Databaseでは、言語範囲はNLS_SORT初期化パラメータにより決定されます。

正規表現[abc]は、文字列all、billおよびcoldの先頭文字に一致しますが、dollのどの文字とも一致しません。

[^char...]

非一致文字リスト

カッコで囲まれたリストにない任意の1文字に一致します。

文字リストの演算子と範囲については、一致文字リストの演算子の説明を参照してください。

正規表現[^abc]defは、xdefに一致しますが、adef、bdefまたはcdefには一致しません。

正規表現[^a-i]xは、jxに一致しますが、ax、fxまたはixには一致しません。

[alt1 |alt2]

または

代替項目のいずれかを一致させます。

正規表現a|bは、文字aまたは文字bに一致します。

(expr)

部分正規表現

グループ化

カッコ内の正規表現が1単位として処理されます。部分正規表現は、文字列または演算子を含む複雑な正規表現にすることができます。

後方参照の部分正規表現を参照してください。

正規表現(abc)?defは、文字列abcdefおよびdefに一致しますが、abcdefgまたはxdefには一致しません。

\n

後方参照

直前のn番目の部分正規表現に一致します。nは、1から9の整数です。後方参照では、直前の各部分正規表現の開きカッコから右に向かって部分正規表現がカウントされます。\nの前に含まれている部分正規表現がn個より少ない場合、正規表現は無効です。

後方参照では、事前に実際の文字列がわからなくても、繰返し文字列を検索できます。

REGEXP_REPLACE関数では、Oracle SQLは正規表現パターンと置換文字列の両方の後方参照をサポートします。

正規表現(abc|def)xy\1は、文字列abcxyabcおよびdefxydefに一致しますが、abcxydefまたはabcxyには一致しません。

正規表現^(.*)\1$は、同じ文字列の2つの連続するインスタンスからなる1行に一致します。

\

エスケープ文字

後続の文字がリテラルとして処理されます。

円記号(\)を使用すると、通常はメタキャラクタとして処理される1文字を検索できます。二重円記号(\\)を使用すると、円記号リテラル自体に一致します。

正規表現abc\+defは、文字列abc+defに一致しますが、abcdefまたはabccdefには一致しません。

^

行頭アンカー

デフォルト・モード: 文字列の先頭に一致します。

複数行モード:脚注2 ソース文字列の任意の行の先頭に一致します。

正規表現^defは、文字列defghi内のdefに一致しますが、文字列abcdef内のdefには一致しません。

$

行末アンカー

デフォルト・モード: 文字列の末尾に一致します。

複数行モード:脚注2 ソース文字列の任意の行の末尾に一致します。

正規表現def$は、文字列abcdef内のdefに一致しますが、文字列defghi内のdefには一致しません。

[:class:]

POSIX文字クラス

指定したPOSIX文字クラスに属する任意の文字(大文字、数字、句読点文字など)に一致します。

注意: 英語による正規表現の場合、範囲正規表現は通常は文字クラスを示します。たとえば、[a-z]は任意の小文字を示します。この表記規則は多言語環境では無効であり、指定した文字クラスの最初の文字と最後の文字がすべての言語で同一であるとはかぎりません。

正規表現[:upper:]+では、1つ以上の連続する大文字が指定され、文字列abcDEFghi内の部分文字列DEFに一致しますが、部分文字列abcdefghiには一致しません。

[.element.]

POSIX照合要素演算子

現在のロケールに定義された照合要素を指定します。NLS_SORT初期化パラメータはサポートされる照合要素を決定します。

この構文を使用すると、他の方法では1文字しか許可されない場合にマルチキャラクタ照合要素を使用できます。たとえば、照合要素chが、スペイン語(トラディショナル)などのロケールで定義されている場合、文字の順序に依存する操作で1文字として処理されるようにすることができます。

正規表現[.ch.]では、照合要素chが指定され、文字列chabc内のchに一致しますが、cdefgには一致しません。

正規表現[a-[.ch.]]では、aからchの範囲が指定されます。

[=char=]

POSIX文字等価クラス

現行のロケールで指定された文字と同じPOSIX文字等価クラスに属するすべての文字に一致します。

この構文は文字リスト内に含まれる必要があるため、必ず文字リスト用の大カッコ内にネストされます。

文字等価はデータベース・ロケールに対する標準ルールの定義によって異なります。詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

正規表現[[=n=]]では、スペイン語ロケールでnと等価の文字が指定され、文字列El Niño内のNおよびñの両方に一致します。

脚注1最長一致演算子は、照合が続く限り、できるだけ多くの出現に一致します。演算子を最短一致にするには、最短一致修飾子(?)を後に付けます(表3-5を参照)。

脚注2パターン一致オプションmで複数行モードを指定します(表3-2を参照)。

Oracle SQLのPOSIX標準に対する多言語拡張機能

Oracle SQLのPOSIX演算子を多言語データに適用すると、POSIX標準に指定されている照合機能の範囲を超えて拡張されます。

表3-4に、各POSIX演算子に対し、POSIX標準で演算子の構文が定義されているか、Oracle SQLにより演算子のセマンティクスが多言語データの処理用に拡張されるかどうかを示します。POSIX標準は基本正規表現(BRE)および拡張正規表現(ERE)です。

表3-4 POSIX演算子と多言語演算子の関係

演算子

POSIX BRE構文

POSIX ERE構文

多言語拡張機能

\

あり

あり

--

*

あり

あり

--

+

--

あり

--

?

--

あり

--

|

--

あり

--

^

あり

あり

あり

$

あり

あり

あり

.

あり

あり

あり

[ ]

あり

あり

あり

( )

あり

あり

--

{m}

あり

あり

--

{m,}

あり

あり

--

{m,n}

あり

あり

--

\n

あり

あり

あり

[..]

あり

あり

あり

[::]

あり

あり

あり

[==]

あり

あり

あり

多言語データにはマルチバイト・キャラクタが含まれている可能性があります。Oracle Databaseでは、直接入力方法でマルチバイト・キャラクタを直接入力するか、関数を使用してマルチバイト・キャラクタを構成できます。\xxxx形式のUnicode 16進エンコーディング値は使用できません。Oracle Databaseでは、文字はグラフィカル表現ではなくエンコーディングに使用されるバイト値に基づいて評価されます。

Oracle SQLのPOSIX標準に対するPERLの影響を受ける拡張機能

Oracle SQLは、POSIX標準には含まれていないが競合もしない、よく使用されるPERL正規表現演算子をサポートします。

表3-5に、Oracle SQLがサポートするPERLの影響を受ける演算子の概要を示します。

注意:
PERLの文字クラス・マッチングはオペレーティング・システムのロケール・モデルに基づいていますが、Oracle SQLの正規表現はデータベースの言語固有のデータに基づいています。通常、ロケール・データを含む正規表現の場合、PERLとOracle SQLで同じ結果が生成されることは期待できません。

表3-5 Oracle SQL正規表現でPERLの影響を受ける演算子

演算子構文

説明

例

\d

数字1文字に一致します。

POSIX正規表現[[:digit:]]と等価です。

正規表現^\(\d{3}\) \d{3}-\d{4}$は、(650) 555-0100に一致しますが650-555-0100には一致しません。

\D

数字以外の1文字に一致します。

POSIX正規表現[^[:digit:]]と等価です。

正規表現\w\d\Dは、b2bおよびb2_に一致しますが、b22には一致しません。

\w

1文字(英数字またはアンダースコア(_)文字)と一致します。

POSIX正規表現[[:alnum:]_]と等価です。

正規表現\w+@\w+(\.\w+)+は、文字列jdoe@company.co.ukに一致しますが、文字列jdoe@companyには一致しません。

\W

英数字およびアンダースコア以外の1文字に一致します。

POSIX正規表現[^[:alnum:]_]と等価です。

正規表現\w+\W\s\w+は、文字列to: billに一致しますが、文字列to billには一致しません。

\s

空白文字1文字に一致します。

POSIX正規表現[[:space:]]と等価です。

正規表現\(\w\s\w\s\)は、文字列(a b )に一致しますが、(ab)または(a,b.)には一致しません。

\S

空白以外の1文字に一致します。

POSIX正規表現[^[:space:]]と等価です。

正規表現\(\w\S\w\S\)は、文字列(abde)および(a,b.)に一致しますが、(a b d e)には一致しません。

\A

単一行モードまたは複数行モードのいずれでも、文字列の先頭に一致します。

POSIX演算子^と等価ではありません。

正規表現\ALは、単一行モードまたは複数行モードのいずれでも、文字列Line1\nLine2\n(\nは改行文字)内の最初のL文字にのみ一致します。

\Z

単一行モードまたは複数行モードのいずれでも、文字列の最後に一致します。

POSIX演算子$と等価ではありません。

正規表現\s\Zは、単一行モードまたは複数行モードのいずれでも、文字列L i n e \n(\nは改行文字)内の最後の空白に一致します。

\z

単一行モードまたは複数行モードのいずれでも、文字列の最後に一致します。

POSIX演算子$と等価ではありません。

正規表現\s\zは、単一行モードまたは複数行モードのいずれでも、文字列L i n e \nの改行文字(\n)に一致します。

+?

直前の部分正規表現の1回以上の出現に一致します(最短一致脚注1)。

正規表現\w+?x\wは、文字列abxcxdのabxcに一致します(最長一致の正規表現\w+x\wはabxcxdに一致します)。

*?

直前の部分正規表現のゼロ回以上の出現に一致します(最短一致脚注1)。可能なかぎり空の文字列に一致します。

正規表現\w*?x\wは文字列xaxbxcのxaに一致します(最長一致の正規表現\w*x\wはxaxbxcに一致します)。

??

直前の部分正規表現のゼロまたは1回の出現に一致します(最短一致脚注1)。可能なかぎり空の文字列に一致します。

正規表現a??aaは文字列aaaaのaaに一致します(最長一致の正規表現a?aaはaaaに一致します)。

{m}?

直前の部分正規表現のm回の出現に一致します(最短一致脚注1)。

正規表現(a|aa){2}?は文字列aaaaのaaに一致します(最長一致の正規表現(a|aa){2}はaaaaに一致します)。

正規表現b{2}?および最長一致の正規表現b{2}はどちらも文字列bbbbのbbに一致します。

{m,}?

直前の部分正規表現のm回以上の出現に一致します(最短一致脚注1)。

正規表現a{2,}?は文字列aaaaaのaaに一致します(最長一致の正規表現a{2,}はaaaaaに一致します)。

{m,n}?

直前の部分正規表現のm回以上n回以下の出現に一致します(最短一致脚注1)。{0,n}?は可能な限り空の文字列に一致します。

正規表現a{2,4}?は文字列aaaaaのaaに一致します(最長一致の正規表現a{2,4}はaaaaに一致します)。

脚注1最短一致演算子は、照合が続く限り、できるだけ少ない出現に一致します。演算子を最長一致にするには、最短一致修飾子(?)を省略します。

SQL文での正規表現の使用: 例

シナリオ:

- 制約を使用した電話番号書式の規定

- 後方参照を使用した文字の再配置

制約を使用した電話番号書式の規定

正規表現は、制約を規定する際に役立つ方法です。たとえば、データベースに標準書式で電話番号を入力する必要があるとします。例3-1では、contacts表を作成し、p_number列にCHECK制約を追加して次の書式モデルを規定しています。

(XXX) XXX-XXXX

例3-1 正規表現を使用した電話番号書式の規定

DROP TABLE contacts;
CREATE TABLE contacts (
l_name    VARCHAR2(30),
p_number  VARCHAR2(30)
CONSTRAINT c_contacts_pnf
CHECK (REGEXP_LIKE (p_number, '^\(\d{3}\) \d{3}-\d{4}$'))
);

表3-6に、この正規表現の要素を示します。

表3-6 例3-1の正規表現要素の説明

正規表現要素

一致

^

文字列の先頭。

\(

左カッコ。円記号(\)は、直後の左カッコが部分正規表現のデリミタではなくリテラルであることを示すエスケープ文字です。

\d{3}

数字3文字。

\)

右カッコ。円記号(\)は、直後の右カッコが部分正規表現のデリミタではなくリテラルであることを示すエスケープ文字です。

空白文字

空白文字。

\d{3}

数字3文字。

-

ハイフン。

\d{4}

数字4文字。

$

文字列の終わり。

例3-2に、電話番号をcontacts表に挿入する正しい文および誤った文を示します。

例3-2 正しい書式と誤った書式での電話番号の挿入

正しい書式は次のとおりです。

INSERT INTO contacts (p_number) VALUES('(650) 555-0100');
INSERT INTO contacts (p_number) VALUES('(215) 555-0100');

次のコードは、CHECK制約エラーを生成します。

INSERT INTO contacts (p_number) VALUES('650 555-0100');
INSERT INTO contacts (p_number) VALUES('650 555 0100');
INSERT INTO contacts (p_number) VALUES('650-555-0100');
INSERT INTO contacts (p_number) VALUES('(650)555-0100');
INSERT INTO contacts (p_number) VALUES(' (650) 555-0100');

後方参照を使用した文字の再配置

後方参照(表3-3を参照)では参照する部分正規表現が一時バッファに格納されます。そのため後方参照を使用して文字を再配置できます(例3-3を参照)。例3-3の正規表現の要素の説明は、表3-7を参照してください。

例3-3 後方参照を使用した文字の再配置

表を作成して、様々な書式の氏名を移入します。

DROP TABLE famous_people;
CREATE TABLE famous_people (names VARCHAR2(20));
INSERT INTO famous_people (names) VALUES ('John Quincy Adams');
INSERT INTO famous_people (names) VALUES ('Harry S. Truman');
INSERT INTO famous_people (names) VALUES ('John Adams');
INSERT INTO famous_people (names) VALUES (' John Quincy Adams');
INSERT INTO famous_people (names) VALUES ('John_Quincy_Adams');

SQL*Plus書式設定コマンド:

COLUMN "names after regexp" FORMAT A20

書式が「ファースト・ネーム、ミドル・ネーム、ラスト・ネーム」の表の各氏名に後方参照を使用して文字を再配置し、書式が「ラスト・ネーム、ファースト・ネーム、ミドル・ネーム」になるようにします。

SELECT names "names",
REGEXP_REPLACE(names, '^(\S+)\s(\S+)\s(\S+)$', '\3, \1 \2')
AS "names after regexp"
FROM famous_people
ORDER BY "names";

結果:

names                names after regexp
-------------------- --------------------
John Quincy Adams    John Quincy Adams
Harry S. Truman      Truman, Harry S.
John Adams           John Adams
John Quincy Adams    Adams, John Quincy
John_Quincy_Adams    John_Quincy_Adams

5 rows selected.

表3-7に、この正規表現の要素を示します。

表3-7 例3-3の正規表現要素の説明

正規表現要素

説明

^

文字列の先頭に一致します。

$

文字列の終わりに一致します。

(\S+)

空白以外の1文字以上に一致します。カッコはエスケープされていないため、グループ化表現として機能します。

\s

空白文字1文字に一致します。

\1

最初の部分正規表現、つまり、一致パターンに含まれるカッコの第1グループを置き換えます。

\2

第2の部分正規表現、つまり、一致パターンに含まれるカッコの第2グループを置き換えます。

\3

第3の部分正規表現、つまり、一致パターンに含まれるカッコの第3グループを置き換えます。

,

カンマを挿入します。

4 データベース・アプリケーションでの索引の使用

索引は表およびクラスタと関連付けられているオプション構造で、これによりSQL問合せをより迅速に実行することができます。このドキュメントで、索引の使用により、索引がない場合よりも高速に情報を検索できるように、Oracle Databaseの索引は、表データへのより高速なアクセス・パスを提供します。索引は問合せをリライトすることなく使用できます。結果は同じですが、より高速に得られます。

この章は、次の情報を補足します。

- 『Oracle Database概要』の索引と索引構成表の説明

- 『Oracle Database管理者ガイド』の索引の管理に関する情報

- 『Oracle Databaseパフォーマンス・チューニング・ガイド』の索引およびクラスタのパフォーマンス向上または低下方法の説明

内容は次のとおりです。

- 索引の管理のガイドライン

- 索引の管理

- ドメイン索引を使用する場合

- ファンクション索引を使用する場合

索引の管理のガイドライン

ここでは、索引の管理のガイドラインの概要を説明します。詳細は、『Oracle Database管理者ガイド』を参照してください。

- 表データの挿入後の索引の作成

- 正しい表および列の索引付け

- パフォーマンスのための索引列の順序付け

- 表当たりの索引数の制限

- 不要な索引の削除

- 遅延セグメント作成の理解

- 索引サイズの見積りと記憶域パラメータの設定

- 索引ごとの表領域の指定

- 索引作成の並列化の検討

- NOLOGGINGを使用する索引の作成の検討

- 使用禁止または非表示の索引をいつ使用するかの理解

- 索引の結合または再構築のコストとメリットの検討

- 制約を使用禁止または削除する前のコストの検討

索引の管理

『Oracle Database管理者ガイド』には、索引の管理に関する情報が含まれています。

- 索引の作成

- 索引の変更

- 索引の使用領域の監視

- 索引の削除

- 索引の情報を表示するデータ・ディクショナリ・ビュー

参照:
「制約で使用する索引の作成」

ドメイン索引を使用する場合

ドメイン索引(アプリケーション・ドメイン索引とも呼ばれます)はデータ・カートリッジ(検索エンジンまたは地理情報システムなど)を使用して実装されたアプリケーションに特有のカスタマイズされた索引です。ドメイン索引の詳細は、『Oracle Database概要』を参照してください。

参照:
ドメイン索引をいつ構築するかを決定するための概念的背景については、『Oracle Databaseデータ・カートリッジ開発者ガイド』を参照してください。

ファンクション索引を使用する場合

ファンクション索引は1つまたは複数の列を含む式の値を計算し、それを索引に格納します。索引式は、算術式、あるいはSQL関数、PL/SQLファンクション、パッケージ・ファンクションまたはCコールアウトを含む式のいずれかです。ファンクション索引は、照合キーに基づく言語ソート、SQL文の効率的な言語依存照合、および大/小文字を区別しないソートもサポートします。

ファンクション索引は索引式を使用する問合せのパフォーマンスを向上させます(特に式が計算集中型な場合)。ただし、

- データベースは索引を使用しない文の処理でも索引式を評価する必要があります。

- 頻繁に変更する列に対してファンクション索引を使用すると、データベースの維持にコストがかかります。

オプティマイザはファンクション索引をコストベースの最適化のためだけに使用できます。一方、列の索引はコストベースの最適化およびルールベースの最適化の両方のために使用できます。

注意:

- ファンクション索引にはNULL値を含めることはできません。そのため、列にNULLを含む可能性のある索引式が含まれていないことを確認するか、または索引式にNVL関数を使用してNULLを他の値に置き換えてください(NVLの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。)

- Oracle Databaseでは降順索引をファンクション索引のように扱います(詳細は、『Oracle Database SQL言語リファレンス』を参照してください)。

内容は次のとおりです。

- ファンクション索引のメリット

- ファンクション索引のデメリット

- ファンクション索引の例

参照:

- ファンクション索引のその他の概念は、『Oracle Database概要』を参照してください。

- ファンクション索引の作成の詳細は、『Oracle Database管理者ガイド』を参照してください。

- ファンクション索引の言語の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

- オプティマイザのファンクション索引の使用方法の詳細は、『Oracle Database概要』を参照してください。

- パフォーマンスのためのファンクション索引の使用方法の詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

ファンクション索引のメリット

ファンクション索引には次のようなメリットがあります。

- ファンクション索引により、データベースが全索引スキャン(『Oracle Database概要』を参照)のかわりに索引範囲スキャン(『Oracle Database概要』を参照)を実行できる機会が増加します。
WHERE句によって大きな表の15%未満の行が選択された場合、索引範囲スキャンでは通常応答時間が短くなります。式がファンクション索引に実体化されていると、オプティマイザは式で選択される行数をより正確に見積もることができます。

Oracle Databaseでは索引式が仮想列として表されるので、ANALYZE文(『Oracle Database SQL言語リファレンス』を参照)でヒストグラムを作成できます。

- ファンクション索引は事前計算を行い、式の値を格納します。
問合せは式の値を計算するかわりに索引から得ることができます。値を必要とする問合せ、および計算集中型の索引式が増えれば増えるほど、索引によりアプリケーションのパフォーマンスは向上します(例4-1を参照)。

- ファンクション索引はオブジェクト列またはREF列に対して作成できます。
索引式はオブジェクト・タイプを戻すメソッドを起動することができます。詳細は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください(例4-2および『Oracle Database SQL言語リファレンス』の例を参照)。

- ファンクション索引により、より強力なソートを実行できます。
索引式には、大/小文字を区別しないソートのためのSQL関数UPPERおよびLOWER(例4-3を参照)、言語ベースのソートのためのSQL関数NLSSORT(例4-4を参照)を含めることができます。

ファンクション索引のデメリット

ファンクション索引には次のようなデメリットがあります。

- オプティマイザはファンクション索引をコストベースの最適化のためだけに使用できます。ルールベースの最適化には使用できません。
コストベースの最適化はディクショナリに格納された統計情報を使用します。ファンクション索引の統計情報を収集するには、DBMS_STATS.GATHER_TABLE_STATS(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)またはDBMS_STATS.GATHER_SCHEMA_STATS(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)のいずれかを起動します。

- ファンクション索引は、索引自体と索引が定義される表が分析されるまで、使用されません。
索引と索引が定義される表を分析するにはDBMS_STATS.GATHER_TABLE_STATSまたはDBMS_STATS.GATHER_SCHEMA_STATSを起動します。

- ファンクション索引は、OR拡張が実行された場合、使用されません。

- 索引式が呼び出すすべてのスキーマ・レベルまたはパッケージ・レベルPL/SQLファンクションが、DETERMINISTICである(同じ入力に対して常に同じ結果を戻す)ことを確認する必要があります。
ファンクションはDETERMINISTICとして宣言する必要がありますが、Oracle Databaseはこのアサーションをチェックしないので、ファンクションが実際にDETERMINISTICであることを確認する必要があります。

DETERMINISTICファンクションのセマンティックを変更し、再コンパイルすると、依存するファンクション索引およびマテリアライズド・ビューを手動で再作成する必要があります。それ以外の場合は、旧バージョンのファンクションの結果がレポートされます。

- 索引式がファンクション起動の場合、ファンクションの戻り型は制約付きにできません。
ファンクションの戻り型をNOT NULLで制約できないため、索引を使用する問合せがNULL値をフェッチできないことを保証する必要があります。そうしないと、データベースは全表スキャンを実行します。

- 索引式は集計関数を呼び出すことができません(『Oracle Database SQL言語リファレンス』を参照)。

- ビットマップ済のファンクション索引は、降順索引にはできません(『Oracle Database SQL言語リファレンス』を参照)。

- 索引式のデータ型は、VARCHAR2、RAW、LONGRAW、または長さが不明のPL/SQLデータ型にはできません。
つまり、長さが不明な式には索引付けできません。ただし、そのような式の既知の長さのサブストリングには索引付けできます。次に例を示します。

CREATE OR REPLACE FUNCTION initials (
name  IN VARCHAR2
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
RETURN('A. J.');
END;
/

/* Invoke SUBSTR both when creating index and when referencing
function in queries. */

CREATE INDEX func_substr_index ON
EMPLOYEES(SUBSTR(initials(FIRST_NAME),1,10));

SELECT SUBSTR(initials(FIRST_NAME),1,10) FROM EMPLOYEES;

参照:

- ファンクション索引の注意点については、『Oracle Database SQL言語リファレンス』を参照してください。

- ファンクション索引の制限事項については、『Oracle Database SQL言語リファレンス』を参照してください。

- 制限事項を含むCREATE FUNCTION文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

ファンクション索引の例

例:

- 例4-1「算術式の事前計算用のファンクション索引」

- 例4-2「オブジェクト列でのファンクション索引」

- 例4-3「大/小文字を区別しないより高速の検索用のファンクション索引」

- 例4-4「言語依存ソート用のファンクション索引」

注意:
例4-1および例4-2はコンポジット索引(複数の表の列に対する索引)を使用します。詳細は『Oracle Database概要』を参照してください。

例4-1は列a、bおよびcのある表を作成し、表に索引を作成し、表に問合せを実行します。索引は式a+b*(c-1)を表す仮想列、列aおよび列bの3つの列に対するコンポジット索引です。問合せはそのWHERE句に索引付けされた式を使用します。そのため、全索引スキャンのかわりに索引範囲スキャンを使用できます。

例4-1 算術式の事前計算用のファンクション索引

索引を作成する表を作成します。

DROP TABLE Fbi_tab;
CREATE TABLE Fbi_tab (
a INTEGER,
b INTEGER,
c INTEGER
);

索引を作成します。

CREATE INDEX Idx ON Fbi_tab (a+b*(c-1), a, b);

この問合せは全索引スキャンのかわりに索引範囲スキャンを使用できます。

SELECT a FROM Fbi_tab WHERE a+b*(c-1) < 100;

参照:
高速全索引スキャンの詳細は、『Oracle Database概要』を参照してください。

例4-2では、オブジェクト・タイプReg_objが定義され、そこに都市に関する情報が格納されると仮定します。例では、最初の列にタイプReg_objを含む表、パラメータにタイプReg_objを指定したDETERMINISTICファンクション、ファンクションを起動する2つのファンクション索引を作成します。最初の問合せは最初の索引を使用して赤道から1000マイル以上離れた都市を迅速に検索します。2番目の問合せは2番目の索引(コンポジット索引)を使用して、気温の差が20未満で最高気温が75よりも高い都市を迅速に検索します(表は例が移入されていないので問合せで行は戻りません )。

例4-2 オブジェクト列でのファンクション索引

オブジェクト列を含む表を作成します。

DROP TABLE Weatherdata_tab;
CREATE TABLE Weatherdata_tab (
Reg_obj INTEGER,
Maxtemp INTEGER,
Mintemp INTEGER
);

パラメータにタイプReg_objを指定したDETERMINISTICファンクションを作成します。

CREATE OR REPLACE FUNCTION Distance_from_equator (
Reg_obj IN INTEGER
) RETURN INTEGER
DETERMINISTIC
IS
BEGIN
RETURN(3000);
END;
/

最初のファンクション索引を作成します。

CREATE INDEX Distance_index
ON Weatherdata_tab (Distance_from_equator (Reg_obj));

問合せで索引式を使用します。

SELECT * FROM Weatherdata_tab
WHERE (Distance_from_equator (Reg_Obj)) > '1000';

結果:

no rows selected

2番目のファンクション(コンポジット)索引を作成します。

CREATE INDEX Compare_index
ON Weatherdata_tab ((Maxtemp - Mintemp) DESC, Maxtemp);

問合せで索引式および索引付けされた列を使用します。

SELECT * FROM Weatherdata_tab
WHERE ((Maxtemp - Mintemp) < '20' AND Maxtemp > '75');

結果:

no rows selected

例4-3では、EMPLOYEES表でより高速な大/小文字を区別しない検索ができる索引を作成してから、問合せで索引式を使用します。

例4-3 大/小文字を区別しないより高速の検索用のファンクション索引

索引を作成します。

CREATE INDEX emp_lastname ON EMPLOYEES (UPPER(LAST_NAME));

問合せで索引式を使用します。

SELECT first_name, last_name
FROM EMPLOYEES
WHERE UPPER(LAST_NAME) LIKE 'J%S_N';

結果:

FIRST_NAME           LAST_NAME
-------------------- -------------------------
Charles              Johnson

1 row selected.

例4-4では、1つの列NAMEを含む表、照合順序GERMANを使用して列をソートするファンクション索引を作成してから、表のすべての列を選択し、NAMEにより順序付けします。問合せは索引を使用できるのでより高速です(問合せはドイツ語セッションで実行され、NLS_SORTはGERMANに、NLS_COMPはANSIに設定されていると仮定します。そうでない場合、問合せでこれらのグローバリゼーション・サポートのパラメータの値を指定する必要があります)。

例4-4 言語依存ソート用のファンクション索引

索引を作成する表を作成します。

DROP TABLE nls_tab;
CREATE TABLE nls_tab (NAME VARCHAR2(80));

索引を作成します。

CREATE INDEX nls_index
ON nls_tab (NLSSORT(NAME, 'NLS_SORT = GERMAN'));

表のすべての列を選択し、NAMEによって順序付けします。

SELECT * FROM nls_tab
WHERE NAME IS NOT NULL
ORDER BY NAME;

5 データベース・アプリケーションにおけるデータ整合性のメンテナンス

データベース・アプリケーションでは、データ整合性のメンテナンスは、アプリケーションで操作される表のデータが適切なビジネス・ルールに準拠する必要があることを意味します。ビジネス・ルールは、常に真または偽になる必要がある条件および関連を指定します。たとえば、従業員の給与が$100,000を超えないようにするビジネス・ルールや、EMPLOYEES表のすべての従業員がDEPARTMENTS表の部門に所属する必要があるビジネス・ルールなどがあります。各企業では、給与、従業員番号、在庫追跡などに関して独自のポリシーを定義しているため、企業ごとにビジネス・ルールが異なります。

『Oracle Database概要』で説明しているように、データ整合性を確認するには複数の方法があり、その1つは、可能なかぎり整合性制約(制約)を使用する方法です。

この章は、次の情報を補足します。

- 『Oracle Database概要』のデータ整合性および制約の説明

- 『Oracle Database管理者ガイド』の制約の管理に関する情報

- 『Oracle Database SQL言語リファレンス』の制約に関する構文およびセマンティクスの情報

注意:
この章は、表に対する制約のみに適用されます。ビューに対する制約では、データ整合性をメンテナンスしたり、関連する索引を持つことはできません。これらは、ビューを伴う問合せをリライトできるため、マテリアライズド・ビューおよびその他のデータ・ウェアハウス機能を使用した場合のパフォーマンスが向上します。
ビューに対する制約の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

データ・ウェアハウスでの制約の使用方法の詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。

内容は次のとおりです。

- 制約を使用したビジネス・ルールの施行

- 制約とアプリケーション・コードの両方を使用したビジネス・ルールの施行

- 制約で使用する索引の作成

- NOT NULL制約を使用する場合

- デフォルトの列値を使用する場合

- 表の主キーの選択(PRIMARY KEY制約)

- UNIQUE制約を使用する場合

- FOREIGN KEY制約を使用した参照整合性の施行

- 制約に対応付けられた索引の領域と時間のオーバーヘッドの最小化

- 外部キーを索引付けするためのガイドライン

- 分散データベース内の参照整合性

- CHECK制約を使用する場合

- 制約の定義の例

- 制約の使用可能および使用禁止

- 制約の変更

- 制約名の変更

- 制約の削除

- FOREIGN KEY制約の管理

- 制約に関する情報の表示

制約を使用したビジネス・ルールの施行

ビジネス・ルールは、可能なかぎり制約を使用して施行します。『Oracle Database概要』で説明されている利点に加えて、制約では高速という利点があります。Oracle Databaseでは、表の中のすべてのデータが制約に従っているかどうかをアプリケーション・コードよりも速くチェックできます。

例5-1では、部門表および従業員表を作成し、部門表のすべての値が一意であるというルールを施行する制約、および各従業員が有効な部門に所属する必要があるというルールを施行する制約を作成します。

例5-1 制約を使用したビジネス・ルールの施行

部門表を作成します。

DROP TABLE dept_tab;
CREATE TABLE dept_tab (
deptname VARCHAR2(20),
deptno   INTEGER
);

従業員表を作成します。

DROP TABLE emp_tab;
CREATE TABLE emp_tab (
empname VARCHAR2(80),
empno   INTEGER,
deptno  INTEGER
);

部門表のすべての値が一意であるというルールを施行する制約を作成します。

ALTER TABLE dept_tab ADD PRIMARY KEY (deptno);

各従業員が有効な部門に所属する必要があるというルールを施行する制約を作成します。

ALTER TABLE emp_tab ADD FOREIGN KEY (deptno) REFERENCES dept_tab(deptno);

これで、emp_tabに従業員レコードを挿入すると、そのdeptnoの値がdept_tabに存在するかどうかがOracle Databaseによって確認されます。

各従業員が有効な部門に所属する必要があるというルールを施行する制約を使用せずに、dept_tabを問い合せるトリガーを使用して、emp_tabに挿入する従業員レコードのdeptnoの値が含まれていることを確認するとします。問合せでは読取り一貫性(CR)が使用されるため、他のトランザクションからのコミットされていない変更を見落とす場合があります。トリガーを使用したビジネス・ルールの施行の詳細は、『Oracle Database概要』を参照してください。

参照:
制約に関する構文およびセマンティクスの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

制約とアプリケーション・コードの両方を使用したビジネス・ルールの施行

データ値が無効であることを表を問い合せずにアプリケーション・コードで判断できる場合は、制約とアプリケーション・コードの両方を使用してビジネス・ルールを施行することをお薦めします。アプリケーション・コードには、無効なデータを表に挿入できないようにすることで、ユーザーに即座にフィードバックして負担を減らすことができます。

例5-2では、例5-1が実行され、この列が表emp_tabに追加されたことを前提としています。

empgender VARCHAR2(1)

empgenderで有効な唯一の値は'M'および'F'です。あるユーザーが行をemp_tabに挿入またはemp_tab.empgenderの値を更新しようとした場合は、emp_tab.empgenderの新しい値が有効かどうかを、表を問い合せずにアプリケーション・コードで判断できます。値が無効の場合は、例5-2のように、無効な値を挿入することなく、アプリケーション・コードでユーザーに通知できます。

例5-2 制約とアプリケーション・コードの両方を使用したビジネス・ルールの施行

CREATE OR REPLACE PROCEDURE add_employee (
e_name   emp_tab.empname%TYPE,
e_gender emp_tab.empgender%TYPE,
e_number emp_tab.empno%TYPE,
e_dept   emp_tab.deptno%TYPE
) AUTHID DEFINER IS
BEGIN
IF UPPER(e_gender) IN ('M','F') THEN
INSERT INTO emp_tab VALUES (e_name, e_gender, e_number, e_dept);
ELSE
DBMS_OUTPUT.PUT_LINE('Gender must be M or F.');
END IF;
END;
/

BEGIN
add_employee ('Smith', 'H', 356, 20);
END;
/

結果:

Gender must be M or F.

制約で使用する索引の作成

一意キー制約または主キー制約が有効な場合は、Oracle Databaseによって索引が自動的に作成されますが、これらの索引を明示的に作成することをお薦めします。外部キー制約で索引を使用する場合は、索引を明示的に作成する必要があります。索引を明示的に作成する方法の詳細は、『Oracle Database管理者ガイド』または『Oracle Database SQL言語リファレンス』を参照してください。

制約で既存の索引を使用できる場合、その制約の索引はOracle Databaseでは作成されません。次のことに注意してください。

- 一意キー制約または主キー制約では、一意索引、一意でない索引全体、または一意でない索引の最初の数個の列のいずれかを使用できます。

- 一意キー制約または主キー制約で、一意でない索引を使用している場合は、その他の一意キー制約または主キー制約では、一意でないその索引を使用できません。

- 制約の列順序と索引は一致する必要がありません。

- 一意キー制約または主キー制約が使用している索引のオブジェクト番号は、その制約のCDEF$.ENABLEDに格納されています。この情報は、静的データ・ディクショナリ・ビューまたは動的なパフォーマンス・ビューには表示されません。
有効な一意キー制約または主キー制約が索引を使用している場合は、索引のみを削除することはできません。索引を削除するには、制約自身を削除するか、その制約を無効にしてから索引を削除する必要があります。制約の無効化および削除の詳細は、『Oracle Database管理者ガイド』を参照してください。

参照:

- 制約に関連付けられている索引の詳細は、『Oracle Database管理者ガイド』を参照してください。

- 第4章「データベース・アプリケーションでの索引の使用」

NOT NULL制約を使用する場合

デフォルトでは、列にNULL値を含むことができます。列にNULL値が含まれていないことを確認するには、NOT NULL制約を使用します(『Oracle Database SQL言語リファレンス』を参照)。

NOT NULL制約は、次の状況の両方で使用します。

- 列に非NULL値を含める必要がある場合。
たとえば、表HR.EMPLOYEESでは、各従業員に従業員IDが必要です。したがって、列HR.EMPLOYEES.EMPLOYEE_IDにはNOT NULL制約が含まれるため、EMPLOYEE_IDに非NULL値を指定せずに、新しい従業員レコードをHR.EMPLOYEESに挿入することはできません。給与を指定せずに、新しい従業員レコードをHR.EMPLOYEESに挿入できるため、列HR.EMPLOYEES.SALARYには、NOT NULL制約は含まれません。

- 表の索引スキャンを実行したり、すべての行の索引付けが必要な操作を実行できるようにする場合。
Oracle Databaseの索引には、値がすべてNULLのキーは格納されません。したがって、前述の種類の操作の場合は、1つ以上の索引列にNOT NULL制約が必要です。

例5-3は、SQL*PlusコマンドDESCRIBEを使用して、DEPARTMENTS表のどの列にNOT NULL制約があるか、NOT NULL制約がある列にNULL値を挿入しようとするとどうなるかを示します。

例5-3 NOT NULL制約がある列へのNULL値の挿入

DESCRIBE DEPARTMENTS;

結果:

Name                                      Null?    Type
----------------------------------------- -------- ------------

DEPARTMENT_ID                             NOT NULL NUMBER(4)
DEPARTMENT_NAME                           NOT NULL VARCHAR2(30)
MANAGER_ID                                         NUMBER(6)
LOCATION_ID                                        NUMBER(4)

DEPARTMENT_ID列にNULLを挿入してみましょう。

INSERT INTO DEPARTMENTS (
DEPARTMENT_ID, DEPARTMENT_NAME, MANAGER_ID, LOCATION_ID
)
VALUES (NULL, 'Sales', 200, 1700);

結果:

VALUES (NULL, 'Sales', 200, 1700)
*
ERROR at line 4:
ORA-01400: cannot insert NULL into ("HR"."DEPARTMENTS"."DEPARTMENT_ID")

NULLにできない列の値を省略することは、その列に値NULLを割り当てることと同じです。

INSERT INTO DEPARTMENTS (
DEPARTMENT_NAME, MANAGER_ID, LOCATION_ID
)
VALUES ('Sales', 200, 1700);

結果:

INSERT INTO DEPARTMENTS (
*
ERROR at line 1:
ORA-01400: cannot insert NULL into ("HR"."DEPARTMENTS"."DEPARTMENT_ID")

DEPARTMENT_IDに非NULLのデフォルト値を指定することで、前述のエラーを回避できます。詳細は、「デフォルトの列値を使用する場合」を参照してください。

NOT NULL制約を他の制約と組み合せて、特定の列で可能な値をさらに制限できます。たとえば、NOT NULLと一意制約を組み合せると、一意キーに必ず値が入力され、新しい行のデータと既存の行のデータが競合する可能性がなくなります。詳細は、「外部キーにUNIQUE制約およびNOT NULL制約がある場合」を参照してください。

デフォルトの列値を使用する場合

INSERT文(『Oracle Database SQL言語リファレンス』を参照)で特定の列の値を指定しない場合、その列はデフォルト値を受け取ります。デフォルトでは、そのデフォルト値はNULLです。列を定義する(CREATE TABLE文を使用、『Oracle Database SQL言語リファレンス』を参照)場合または列を変更する(ALTER TABLE文を使用、『Oracle Database SQL言語リファレンス』を参照)場合は、デフォルト値を変更できます。

注意:
列に非NULLのデフォルト値を指定しても、NOT NULL制約のように、列の値にNULL値が含まれないようにすることはできません。NOT NULL制約の詳細は、「NOT NULL制約を使用する場合」を参照してください。

デフォルトの列値は、次の状況で使用します。

- 列にNOT NULL制約がある場合。
列に非NULLのデフォルト値を指定すると、列に値を指定せずに行を挿入した場合に発生するエラーを防止できます。

- 列に最も一般的な値がある場合。
たとえば、社内のほとんどの部門がニューヨークにある場合は、列DEPARTMENTS.LOCATIONのデフォルト値を'NEW YORK'に設定します。

- エントリなしを示す非NULL値がある場合。
たとえば、列EMPLOYEES.SALARYの値ゼロが、給与がまだ決定されていないことを意味する場合は、その列のデフォルト値をゼロに設定します。

エントリなしを示すデフォルトの列値ではテストを簡単にできます。たとえば、次のテストを変更できます。

IF (employees.salary IS NOT NULL) AND (employees.salary < 50000)

変更後のテスト:

IF employees.salary < 50000

- 表を変更するユーザーの名前を自動的に記録する場合。
たとえば、ビューを介してユーザーが行を表に挿入できるようにするとします。inserter列(ビューの定義に含める必要のない列)を実表に指定し、行を挿入したユーザーの名前を格納します。ユーザー名を自動的に記録するには、USER関数を起動するデフォルト値を定義します。次に例を示します。

CREATE TABLE audit_trail (
value1   NUMBER,
value2   VARCHAR2(32),
inserter VARCHAR2(30) DEFAULT USER);

表の主キーの選択(PRIMARY KEY制約)

表の主キーは各行を一意に識別し、行の重複も回避できます(通常はこの目的のみ)。したがって、主キーの値をNULLにすることはできません。

表に含めることができる主キーは最大で1つですが、複数の列を含めることができます(複合キーが可能)。主キーを指定するには、主キー制約を使用します。

実用的なものとしては、値が順次生成される単一列を主キーとして選択します。順序の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

主キーとして選択するもので、次に最適なのは、値が次のすべてに該当する単一列です。

- 一意

- 変更なし

- 非NULL

- 短い数値(入力が簡単)

値が長く順次生成できない複合主キーの使用については、最小限にします。

参照:

- 主キー制約の詳細は、『Oracle Database概要』を参照してください。

- 制限などの主キー制約の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

UNIQUE制約を使用する場合

非NULL値の重複が許可されていない1つの列または複数の列の組合せ(主キーを除く)では、一意制約を使用します。次に例を示します。

一意キー

主キー

従業員の社会保障番号

従業員番号

トラックのナンバープレートの番号

トラック番号

顧客の電話番号(国コード列、市外局番列、市内局番列)

顧客番号

部門名列および拠点列

部門番号

図5-1は、一意制約を使用した表、制約に違反している行、および制約を満たしている行を示しています。

図5-1 UNIQUE制約に違反およびUNIQUE制約を満たす行

参照:

- 一意制約の詳細は、『Oracle Database概要』を参照してください。

- 制限などの一意制約の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

FOREIGN KEY制約を使用した参照整合性の施行

2つの表に1つ以上の共通の列が含まれる場合、外部キー制約を使用して、参照整合性(両方の表で共通の列に常に同じ値が含まれるようにする)を施行できます。

注意:
外部キー制約は参照整合性制約とも呼ばれ、静的データ・ディクショナリ・ビュー*_CONSTRAINTSでは、そのCONSTRAINT_TYPEは、Rになります。

一方の表を参照表または親表として指定し、もう一方の表を依存または子表として指定します。親表では、共通する列に主キー制約または一意制約を定義します。子表では、共通する列に外部キー制約を定義します。これで、共通する列は外部キーで構成されます。外部キーに追加の制約を定義すると、親と子の関連に影響があります(詳細は、「親表と子表との関連の定義」を参照)。

図5-2に、部門番号に定義された外部キーを示します。この外部キーは、この列の値がそれぞれ部門表の主キーの値と一致することを保証します。制約によって、間違った部門番号が従業員表に入力される可能性を回避できます。

図5-2は、1つの列を共有する親表と子表、外部キー制約に違反している行、およびその制約を満たしている行を示しています。

図5-2 FOREIGN KEY制約に違反および外部キー制約を満たす行

内容は次のとおりです。

- FOREIGN KEY制約およびNULL値

- 親表と子表との関連の定義

- 複数のFOREIGN KEY制約に関する規則

- 制約チェックの遅延

参照:

- 外部キー制約の詳細は、『Oracle Database概要』を参照してください。

- 制限などの外部キー制約の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

FOREIGN KEY制約およびNULL値

外部キーには、一致する主キーまたは一意キーがない場合でも、すべてのNULLのキー値を使用できます。

- デフォルトでは(NOT NULL句またはCHECK句を指定しない場合)、外部キー制約は、ANSI/ISO規格の複合外部キーに対して不一致規則を施行します。

- 複合外部キーのNULL値に対する完全一致規則(キーのすべての構成要素がNULLまたは非NULLであることを要求する)を施行するには、すべての複合外部キーがNULLまたは非NULLであることのみを許可するCHECK制約を定義します。たとえば、列A、B、Cで構成される複合キーを次のとおり指定できます。

CHECK ((A IS NULL AND B IS NULL AND C IS NULL) OR
(A IS NOT NULL AND B IS NOT NULL AND C IS NOT NULL))

- 一般に、宣言型参照整合性を使用して、複合外部キーのNULL値に対する 部分一致規則(キーの非NULL部分が、参照表の主キーまたは一意キー列の対応する部分にあることを要求する)を施行することはできません。この場合、『Oracle Database PL/SQL言語リファレンス』で説明するように、トリガーを使用して処理できることがよくあります。

親表と子表との関連の定義

親表と子表との関連のいくつかは、子表の外部キーで定義されている他のタイプの制約によって判断できます。

外部キーに他の制約がない場合 外部キーについて他の制約が定義されていない場合は、子表の行は何行でも同一の親キー値を参照できます。このモデルでは外部キーにNULLが許可されます。

このモデルは、外部キーに未定の値(NULL)を許可する親キーと外部キーとの間に1対多関連を確立します。employee(従業員)表とdepartment(部門)表の間のこのような関連の例を、図5-2に示します。各部門(親キー)には多数の従業員(外部キー)が所属しますが、一部の従業員は、部門に所属していない場合があります(外部キーでNULL)。

外部キーにNOT NULL制約がある場合 外部キーでNULLが許可されていない場合は、子表の各行は親キーの値を明示的に参照する必要があります。

子表の行は何行でも同一の親キー値を参照できるため、このモデルは、親キーと外部キーとの1対1関連を確立します。ただし、子表の各行は、必ず親キー値に対する参照を持っている必要があり、外部キーに値の欠如(NULL)があってはいけません。前述の項の例で、この関連を説明できます。ただし、このモデルでは、従業員は必ず特定の部門への参照を持つ必要があります。

外部キーに一意制約がある場合 外部キーで一意制約が定義されている場合は、子表の1つの行のみが指定された親キーの値を参照できます。このモデルでは外部キーにNULLが許可されます。

このモデルは、外部キーに未定の値(NULL)を許可する親キーと外部キーとの間に1対1関連を確立します。たとえば、従業員表に、企業の保険計画の従業員の会員番号を参照するMEMBERNOという名前の列があると想定します。また、INSURANCEという表には、MEMBERNOという主キーがあり、その他の列は保険証書に関連した各従業員の情報を保持しているとします。次の理由によって、従業員表のMEMBERNOは、外部キーかつ一意キーである必要があります。

- EMP_TAB表およびINSURANCE表の参照整合性規則を施行するため(FOREIGN KEY制約)

- 各従業員の会員番号を一意にするため(一意キー制約)

外部キーに一意制約およびNOT NULL制約がある場合 外部キーで一意制約およびNOT NULL制約が定義されている場合は、子表の1つの行のみが指定された親キーの値を参照できます。また、外部キーにNULL値が許可されないため、子表の各行は親キーの値を明示的に参照する必要があります。

このモデルは、外部キーに未定の値(NULL)を許可しない親キーと外部キーとの間に1対1関連を確立します。前述の例を拡張して、各従業員が一意の会員番号を持つように保証するとともに、従業員表のMEMBERNO列にNOT NULL制約を追加することで、従業員表のMEMBERNO列に未定義の値(NULL)が許可されないようにできます。

複数のFOREIGN KEY制約に関する規則

Oracle Databaseでは、1つの列を複数の外部キー制約で参照できます。依存キーの数に制限はありません。ある列が2つの異なる複合外部キーの一部になっている場合に、この状況が発生する可能性があります。

制約チェックの遅延

Oracle Databaseが制約を確認する場合に、制約が満たされないときは、エラーが表示されます。現行のトランザクションが終了するまで制約のチェックを遅延するには、SET CONSTRAINTS文を使用します。

注意:
SET CONSTRAINTS文は、トリガー内では使用できません。

制約のチェックを遅延するには次のようにします。

- データを適切に選択します。
データに次のいずれかの特性がある場合、一意キーおよび外部キーの制約チェックを遅延する必要があります。

- 表がスナップショットの場合。

- 別のアプリケーションで処理される大量のデータを含む表であり、同じ順序でデータが戻されるかどうかわからない場合。

- 外部キーに対するカスケード操作を更新します。

- 制約が遅延可能かどうかを確認します。
適切な表を指定した後、表の外部キー、一意キーおよび主キーがDEFERRABLEとして作成されているかどうかを確認します。

- データを処理するアプリケーション内で、任意のデータを処理する前に、次のようにすべての制約に遅延を設定します。

SET CONSTRAINTS ALL DEFERRED;

- (オプション)トランザクションをコミットする直前に制約違反をチェックします。
COMMIT文の直前に、SET CONSTRAINTS ALL IMMEDIATE文を実行します。制約に問題があった場合、この文は失敗し、エラーの原因になった制約が識別されます。制約が違反しているときにコミットした場合、トランザクションはロールバックされ、エラー・メッセージが表示されます。

例5-4では、表empの主キーと 外部キーがDEFERRABLEとして作成され、遅延されます。

例5-4 制約チェックの遅延

DROP TABLE dept;
CREATE TABLE dept (
deptno NUMBER PRIMARY KEY,
dname  VARCHAR2 (30)
);

DROP TABLE emp;
CREATE TABLE emp (
empno  NUMBER,
ename  VARCHAR2(30),
deptno NUMBER,
CONSTRAINT pk_emp_empno PRIMARY KEY (empno) DEFERRABLE,
CONSTRAINT fk_emp_deptno FOREIGN KEY (deptno) REFERENCES dept(deptno) DEFERRABLE
);

INSERT INTO dept (deptno, dname) VALUES (10, 'Accounting');
INSERT INTO dept (deptno, dname) VALUES (20, 'SALES');

INSERT INTO emp (empno, ename, deptno) VALUES (1, 'Corleone', 10);
INSERT INTO emp (empno, ename, deptno) VALUES (2, 'Costanza', 20);
COMMIT;

SET CONSTRAINTS ALL DEFERRED;

UPDATE dept
SET deptno = deptno + 10
WHERE deptno = 20;

問合せ:

SELECT * from dept
ORDER BY deptno;

結果:

DEPTNO DNAME
---------- ------------------------------
10 Accounting
30 SALES

2 rows selected.

更新:

UPDATE emp
SET deptno = deptno + 10
WHERE deptno = 20;

結果:

1 row updated.

問合せ:

SELECT * from emp
ORDER BY deptno;

結果:

EMPNO ENAME                              DEPTNO
---------- ------------------------------ ----------
1 Corleone                               10
2 Costanza                               30

2 rows selected.

SET CONSTRAINTSは現行のトランザクションのみに適用されます。設定が継続するのは、そのトランザクションの間、または次のSET CONSTRAINTS文によってモードがリセットされるまでです。ALTER SESSION SET CONSTRAINTS文は、現行セッションにのみ適用されます。制約の作成時に指定したデフォルト値は、制約の存在中は維持されます。

参照:
SET CONSTRAINTS文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

制約に対応付けられた索引の領域と時間のオーバーヘッドの最小化

一意キーまたは主キーを作成すると、Oracle Databaseは、既存の索引が制約の一意性を強制するかどうかを確認します。既存の索引がない場合、データベースは索引を作成します。

Oracle Databaseが一意索引を使用して制約を施行し、それに対応付けられた制約が削除または使用禁止にされる場合、索引は削除されます。索引に関連付けられた統計を保持する場合(再作成には時間がかかる)は、DROP CONSTRAINT文にKEEP INDEX句を指定します。

使用可能な外部キーが主キーまたは一意キーを参照している間は、主キー制約または一意キー制約、または索引を使用禁止にしたり削除することはできません。

注意:
遅延可能制約を使用した一意キーおよび主キーには、非一意索引を使用してください。

一意キー制約および主キー制約の作成時に既存の索引を使用するには、CONSTRAINT句にUSING INDEXを含めます。詳細と例は、『Oracle Database SQL言語リファレンス』を参照してください。

外部キーを索引付けするためのガイドライン

一致する一意キーまたは主キーが決して更新または削除されない場合にかぎり、外部キーに索引を付けます。

参照:
外部キーの索引付けの詳細は、『Oracle Database概要』を参照してください。

分散データベース内の参照整合性

参照制約の宣言では、リモート表の主キーまたは一意キーを参照する外部キーを指定できません。

ただし、トリガーを使用すると、複数のノードにまたがる親子の表の関連をメンテナンスできます。

参照:
参照整合性を施行するトリガーの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

注意:
トリガーを使用して分散データベースの複数のノードにまたがる参照整合性を定義する場合、ネットワーク障害が親表および子表へのアクセスを制限する可能性があることに注意してください。
たとえば、子表がSALESデータベースに存在し、親表がHQデータベースに存在すると想定します。

2つのデータベース間のネットワーク接続に障害が発生すると、参照整合性トリガーがHQデータベース内の親表へアクセスする必要があるため、子表に対するデータ操作言語(DML)文が処理(行を挿入したり、外部キーの値を更新するような処理)を進めることができない場合があります。

CHECK制約を使用する場合

比較などの論理式をベースとした整合性規則を施行する必要がある場合、CHECK制約を使用します。その他のタイプの制約で必要なチェックができる場合には、CHECK制約は使用しないでください。

参照:
「CHECKおよびNOT NULL制約の選択」

CHECK制約の例を次に示します。

- 給与の値が10000を超えないように、従業員の給与にCHECK制約を定義します。

- 「BOSTON」、「NEW YORK」および「DALLAS」のみが許可されるように、部門の所在地にCHECK制約を定義します。

- コミッションの額が給与より多くならないように、給与およびコミッションの列にCHECK制約を定義します。

CHECK制約の制限

CHECK制約では、条件は表のすべての行に対して真または不明である必要があります。条件が偽であると評価された場合、その文はロールバックされます。CHECK制約の条件には、次のような制限があります。

- 条件は、挿入または更新が行われている行の値を使用して評価できるブール式である必要があります。

- 条件に副問合せまたは順序を含めることはできません。

- 条件にSQL関数SYSDATE、UID、USERまたはUSERENVを含めることはできません。

- 条件に疑似列LEVELまたはROWNUMを含めることはできません。

- 条件にPRIOR演算子を含めることはできません。

- 条件にユーザー定義関数を含めることはできません。

参照:

- LEVEL擬似列の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- ROWNUM擬似列の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- PRIOR演算子(階層問合せで使用)の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

CHECK制約の設計

CHECK制約は、条件が偽であると評価される場合にのみCHECK制約に違反します。真および不明(NULLと比較して)はチェック条件には違反しません。したがって、定義するCHECK制約が、規則を施行するために十分明確であることを確認してください。

たとえば、次のCHECK制約について考えます。

CHECK (Sal > 0 OR Comm >= 0)

この規則は、「従業員の給与が0(ゼロ)より大きい場合、または従業員のコミッションが0(ゼロ)以上の場合は、従業員表の行を許可しない」と解釈されます。ただし、給与にNULLの値を持つ行は、チェック条件全体が不明であると評価されるため、そのコミッションの値の評価にかかわらず、CHECK制約に違反しません。このような場合には、SAL列とCOMM列の両方にNOT NULL制約を設定することによって、このような違反を回避できます。

注意:
どのような場合にNULL条件の結果が不明な値となるかについては、『Oracle Database SQL言語リファレンス』の論理条件の真理値表を参照してください。

複数のCHECK制約に関する規則

1つの列に、その定義で列を参照する複数のCHECK制約を指定できます。定義できるCHECK制約の数に制限はありません。

制約が評価される順序は定義されません。そのため、順序に依存したり、互いに競合するような複数の制約を定義しないでください。

CHECKおよびNOT NULL制約の選択

ANSI/ISO規格によると、NOT NULL制約はCHECK制約の1つであり、その条件は次のとおりです。

CHECK (column_name IS NOT NULL)

このため、NOT NULL制約またはCHECK制約のいずれかを使用して、単一列に対するNOT NULL制約を記述できます。NOT NULL制約は、CHECK制約よりも簡単に使用できます。

複合キーがすべてNULLまたはすべて値を持つ場合は、CHECK制約を使用する必要があります。たとえば、次のCHECK制約を指定すると、列C1およびC2を構成する複合キーのキー値が、すべてNULLまたはすべて値を持つことができます。

CHECK ((C1 IS NULL AND C2 IS NULL) OR (C1 IS NOT NULL AND C2 IS NOT NULL))

制約の定義の例

例5-5および例5-6に、データベース設計のプロトタイプ・フェーズでの簡単な制約の作成方法を示します。これらの例では各制約に名前が付いています。制約に名前を付けると、データ定義言語(DDL)が複数回実行された場合に、システムが生成した異なる名前で、データベースが同じ制約の複数のコピーを作成することを回避できます。

例5-5では、CREATE TABLE文を使用して表と制約を同時に作成します。

例5-5 CREATE TABLE文を使用した制約の定義

DROP TABLE DeptTab;
CREATE TABLE DeptTab (
Deptno  NUMBER(3) CONSTRAINT pk_DeptTab_Deptno PRIMARY KEY,
Dname   VARCHAR2(15),
Loc     VARCHAR2(15),
CONSTRAINT u_DeptTab_Dname_Loc UNIQUE (Dname, Loc),
CONSTRAINT c_DeptTab_Loc
CHECK (Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')));

DROP TABLE EmpTab;
CREATE TABLE EmpTab (
Empno    NUMBER(5) CONSTRAINT pk_EmpTab_Empno PRIMARY KEY,
Ename    VARCHAR2(15) NOT NULL,
Job      VARCHAR2(10),
Mgr      NUMBER(5) CONSTRAINT r_EmpTab_Mgr REFERENCES EmpTab,
Hiredate DATE,
Sal      NUMBER(7,2),
Comm     NUMBER(5,2),
Deptno   NUMBER(3) NOT NULL
CONSTRAINT r_EmpTab_DeptTab REFERENCES DeptTab ON DELETE CASCADE);

例5-6では、ALTER TABLE文を使用して既存の表に制約を作成します。

制約に違反する行が表に存在している場合、VALIDATED状態の制約は作成できません。

例5-6 ALTER TABLE文を使用した制約の定義

-- Create tables without constraints:

DROP TABLE DeptTab;
CREATE TABLE DeptTab (
Deptno  NUMBER(3),
Dname   VARCHAR2(15),
Loc     VARCHAR2(15)
);

DROP TABLE EmpTab;
CREATE TABLE EmpTab (
Empno    NUMBER(5),
Ename    VARCHAR2(15),
Job      VARCHAR2(10),
Mgr      NUMBER(5),
Hiredate DATE,
Sal      NUMBER(7,2),
Comm     NUMBER(5,2),
Deptno   NUMBER(3)
);

--Define constraints with the ALTER TABLE statement:

ALTER TABLE DeptTab
ADD CONSTRAINT pk_DeptTab_Deptno PRIMARY KEY (Deptno);

ALTER TABLE EmpTab
ADD CONSTRAINT fk_DeptTab_Deptno
FOREIGN KEY (Deptno) REFERENCES DeptTab;

ALTER TABLE EmpTab MODIFY (Ename VARCHAR2(15) NOT NULL);

参照:
大規模な本番データベースに対する制約の作成方法およびメンテナンス方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

制約の定義に必要な権限

CREATE TABLEまたはCREATE ANY TABLEシステム権限がある場合、作成する表の制約を定義できます。

ALTER ANY TABLEシステム権限ある場合は、既存のすべての表に制約を定義できます。

特定の表のALTERオブジェクト権限がある場合は、その表に制約を定義できます。

一意キーおよび主キー制約では、表の所有者に、UNLIMITED TABLESPACEシステム権限、または対応する索引を含む表領域の割当て制限が必要です。

外部キー制約を定義できるのは、親表またはビューが自分のスキーマ内にある場合、または親表またはビューの参照キー列に対するREFERENCES権限を持っている場合です。詳細は、「FOREIGN KEY制約の作成に必要な権限」を参照してください。

制約のネーミング

NOT NULL、一意キー、主キー、外部キーおよびCHECKの各制約に対して、制約句のCONSTRAINTオプションを使用して名前を割り当ててください。この名前は、そのユーザーが所有している他の制約名に対して一意である必要があります。制約名を指定しない場合、Oracle Databaseが名前を自動的に生成して割り当てます。

独自の名前を指定すると、制約違反のエラー・メッセージがよりわかりやすくなります。また、SQL文が複数回実行された場合に、異なる名前で重複した制約が作成されることを回避できます。

制約句のCONSTRAINTオプションの例として、前述のCREATE TABLE文およびALTER TABLE文の例を参照してください。データ・ディクショナリでは、各制約名が制約に関する他の情報に含まれます。

参照:
静的データ・ディクショナリ・ビューの例は、「制約に関する情報の表示」を参照してください。

制約の使用可能および使用禁止

この項では、制約をユーザー自身で使用可能および使用禁止にするしくみ、および手順について説明します。

使用可能にされた制約。制約が使用可能な場合、対応する規則が対応付けられた列のデータ値に施行されます。制約の定義は、データ・ディクショナリ内に格納されます。

使用禁止にされた制約。制約が使用禁止の場合、それに対応する規則は施行されません。制約の定義は、データ・ディクショナリ内に格納されたままです。

整合性制約は、データベース内のデータに関するアサーションを表します。このアサーションは、制約を使用可能にすると必ず真になります。制約を使用禁止にすると、整合性制約に違反するデータがデータベース内に存在する可能性があるため、アサーションは真でない場合もあります。

内容は次のとおりです。

- 制約を使用禁止にする理由

- 制約を使用可能にする(デフォルト)

- 制約を使用禁止にする

- 既存の制約を使用可能にする

- 既存の制約を使用禁止にする

- キー制約の使用可能および使用禁止に関するガイドライン

- 制約の例外の修正

制約を使用禁止にする理由

日常の操作では、制約を使用可能な状態にしておきます。特定の状況においては、パフォーマンス上の理由から、表の制約を一時的に使用禁止にする必要がある場合があります。次に例を示します。

- SQL*Loaderを使用して、表に大量のデータをロードする場合

- 表に対して大規模な変更を行うバッチ作業を実施する場合(たとえば、既存の番号に1000を加えてすべての従業員番号を変更する場合)

- 表を1つずつインポートまたはエクスポートする場合

制約を一時的に使用禁止にすると、これらの操作が高速になります。

制約を使用可能にする(デフォルト)

整合性制約を定義すると(CREATE TABLEまたはALTER TABLEを使用)、Oracle Databaseではデフォルトで制約が使用可能になります。コードをわかりやすくするために、例5-7のように、制約の定義にENABLE句を含めて制約を明示的に使用可能にできます。

例5-7 制約を使用可能にする

/* Use CREATE TABLE statement to create enabled constraint
(ENABLE keyword is optional): */

DROP TABLE t1;
CREATE TABLE t1 (Empno NUMBER(5) PRIMARY KEY ENABLE);

/* Create table without constraint
and then use ALTER TABLE statement to add enabled constraint
(ENABLE keyword is optional): */

DROP TABLE t2;
CREATE TABLE t2 (Empno NUMBER(5));

ALTER TABLE t2 ADD PRIMARY KEY (Empno) ENABLE;

個々のトランザクションによって一度に1つずつ行が移入される表の制約を定義する場合は、ENABLE句を指定します。こうすることで、データが常に一貫性を保つことが保証され、各DML文のパフォーマンス・オーバーヘッドが少なくなります。

整合性制約を使用可能にするALTER TABLE文は、表の既存の行がその整合性制約に違反するとエラーになります。文はロールバックされ、制約定義は格納されず使用可能にもなりません。

参照:
制約に違反する行の詳細は、「制約の例外の修正」を参照してください。

制約を使用禁止にする

整合性制約を定義(CREATE TABLEまたはALTER TABLEを使用)して使用禁止にするには、例5-8のように定義にDISABLE句を指定します。

例5-8 制約を使用禁止にする

/* Use CREATE TABLE statement to create disabled constraint */

DROP TABLE t1;
CREATE TABLE t1 (Empno NUMBER(5) PRIMARY KEY DISABLE);

/* Create table without constraint
and then use ALTER TABLE statement to add disabled constraint */

DROP TABLE t2;
CREATE TABLE t2 (Empno NUMBER(5));

ALTER TABLE t2 ADD PRIMARY KEY (Empno) DISABLE;

ユーザーがアクセスする前に大容量のデータが挿入される表の制約を定義するときは、DISABLE句を指定します。特に、データの挿入後にデータをクリーン・アップしたり、空の列に順序番号または親子関係を入力する必要がある場合です。

制約を定義して使用禁止にするALTER TABLE文は、その規則が施行されていないため、エラーとなることはありません。

既存の制約を使用可能にする

データをクリーン・アップし、空の列に値を入力した後で、データの挿入中に使用禁止にしていた制約を使用可能にできます。

既存の制約を使用可能にするには、例5-9のようにALTER TABLE文をENABLE句とともに使用します。

例5-9 既存の制約を使用可能にする

-- Create table with disabled constraints:

DROP TABLE DeptTab;
CREATE TABLE DeptTab (
Deptno  NUMBER(3) PRIMARY KEY DISABLE,
Dname   VARCHAR2(15),
Loc     VARCHAR2(15),
CONSTRAINT uk_DeptTab_Dname_Loc UNIQUE (Dname, Loc) DISABLE,
CONSTRAINT c_DeptTab_Loc
CHECK (Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')) DISABLE
);

-- Enable constraints:

ALTER TABLE DeptTab
ENABLE PRIMARY KEY
ENABLE CONSTRAINT uk_DeptTab_Dname_Loc
ENABLE CONSTRAINT c_DeptTab_Loc;

整合性制約を使用可能にするALTER TABLE文は、表の行がその整合性制約に違反するとエラーになります。この場合、文はロールバックされ、制約は使用可能になりません。

参照:
制約に違反する行の詳細は、「制約の例外の修正」を参照してください。

既存の制約を使用禁止にする

データが含まれている表に対して、大規模な挿入または更新を実行する必要がある場合は、整合性制約を一時的に使用禁止にして、バルク操作のパフォーマンスを向上させることができます。

既存の制約を使用禁止にするには、例5-10のようにALTER TABLE文をDISABLE句とともに使用します。

例5-10 既存の制約を使用禁止にする

-- Create table with enabled constraints:

DROP TABLE DeptTab;
CREATE TABLE DeptTab (
Deptno  NUMBER(3) PRIMARY KEY ENABLE,
Dname   VARCHAR2(15),
Loc     VARCHAR2(15),
CONSTRAINT uk_DeptTab_Dname_Loc UNIQUE (Dname, Loc) ENABLE,
CONSTRAINT c_DeptTab_Loc
CHECK (Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')) ENABLE
);

-- Disable constraints:

ALTER TABLE DeptTab
DISABLE PRIMARY KEY
DISABLE CONSTRAINT uk_DeptTab_Dname_Loc
DISABLE CONSTRAINT c_DeptTab_Loc;

キー制約の使用可能および使用禁止に関するガイドライン

一意キー、主キーおよび外部キーの各制約を使用可能または使用禁止にする場合は、いくつかの重要な問題および前提条件を認識してください。一意キー制約および主キー制約は、通常、データベース管理者が管理します。

参照:
『Oracle Database管理者ガイド』および「FOREIGN KEY制約の管理」

制約の例外の修正

表の行が整合性制約に違反する場合、この行は制約違反になり、制約に対する例外とされます。例外が存在する場合、制約を使用可能にはできません。制約に違反する行は、制約を使用可能にする前に更新または削除する必要があります。

制約を使用可能にするときに、特定の整合性制約に対する例外を指定できます。

参照:
この手順の詳細は、「制約の例外の修正」を参照してください。

制約を作成または使用可能にするときに、整合性制約の例外があるために文が正常に実行されなかった場合、文はロールバックされます。この場合、すべての例外が更新または削除されるまで制約を使用可能にできません。整合性制約に違反している行を判断するには、CREATE TABLE文またはALTER TABLE文のENABLE句にEXCEPTIONSオプションを指定します。

参照:
制約の例外に応答する場合は、『Oracle Database管理者ガイド』を参照してください。

制約の変更

Oracle8i以降では、例5-11のようにMODIFY CONSTRAINT句を使用して既存の制約状態を変更することができます。

参照:
変更するパラメータの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

例5-11 制約の変更

/* Create & then modify a CHECK constraint: */

DROP TABLE X1Tab;
CREATE TABLE X1Tab (
a1 NUMBER
CONSTRAINT c_X1Tab_a1 CHECK (a1>3)
DEFERRABLE DISABLE
);

ALTER TABLE X1Tab
MODIFY CONSTRAINT c_X1Tab_a1 ENABLE;

ALTER TABLE X1Tab
MODIFY CONSTRAINT c_X1Tab_a1 RELY;

ALTER TABLE X1Tab
MODIFY CONSTRAINT c_X1Tab_a1 INITIALLY DEFERRED;

ALTER TABLE X1Tab
MODIFY CONSTRAINT c_X1Tab_a1 ENABLE NOVALIDATE;

/* Create & then modify a PRIMARY KEY constraint: */

DROP TABLE t1;
CREATE TABLE t1 (a1 INT, b1 INT);

ALTER TABLE t1
ADD CONSTRAINT pk_t1_a1 PRIMARY KEY(a1) DISABLE;

ALTER TABLE t1
MODIFY PRIMARY KEY INITIALLY IMMEDIATE
USING INDEX PCTFREE = 30 ENABLE NOVALIDATE;

ALTER TABLE t1
MODIFY PRIMARY KEY ENABLE NOVALIDATE;

制約名の変更

変更可能な制約のプロパティの1つは名前です。制約の名前を変更する状況には次のようなものがあります。

- 表と制約を複製する場合。
制約名は、複数のスキーマに対しても一意であることが必要です。このため、複製された表の制約を、元の表の制約と同じ名前にすることができません。

- 制約をデフォルトのシステム生成名で作成したが、使用可能または使用禁止の設定が容易になるように、覚えやすい制約名が必要な場合。

例5-12に、制約のシステム生成名を検索して変更する方法を示します。

例5-12 制約名の変更

DROP TABLE T;
CREATE TABLE T (
C1 NUMBER PRIMARY KEY,
C2 NUMBER
);

問合せ:

SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'T'
AND CONSTRAINT_TYPE = 'P';

結果(システムにより生成される制約名は様々です):

CONSTRAINT_NAME
------------------------------
SYS_C0013059

1 row selected.

この問合せで報告された制約名をT_C1_PKに変更します。

ALTER TABLE T
RENAME CONSTRAINT SYS_C0013059
TO T_C1_PK;

問合せ:

SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'T'
AND CONSTRAINT_TYPE = 'P';

結果:

CONSTRAINT_NAME
------------------------------
T_C1_PK

1 row selected.

制約の削除

制約を削除するには、ALTER TABLE文のDROP句を使用します。制約を削除する状況には次のようなものがあります。

- 制約で施行されるルールが適切でなくなった場合。

- 制約が不要になった場合。

1つの制約と、その制約が依存している他のすべての整合性制約を削除するには、CASCADEを指定します。

例5-13 制約の削除

-- Create table with constraints:

DROP TABLE DeptTab;
CREATE TABLE DeptTab (
Deptno  NUMBER(3) PRIMARY KEY,
Dname   VARCHAR2(15),
Loc     VARCHAR2(15),
CONSTRAINT uk_DeptTab_Dname_Loc UNIQUE (Dname, Loc),
CONSTRAINT c_DeptTab_Loc
CHECK (Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO'))
);

-- Drop constraints:

ALTER TABLE DeptTab
DROP PRIMARY KEY
DROP CONSTRAINT uk_DeptTab_Dname_Loc
DROP CONSTRAINT c_DeptTab_Loc;

一意キー、主キーおよび外部キーの各制約を削除する場合は、いくつかの重要な問題および前提条件を認識してください。一意キー制約および主キー制約は、通常、データベース管理者が管理します。

参照:

- ALTER TABLE文のDROP句の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 制約の削除の詳細は、『Oracle Database管理者ガイド』を参照してください。

- DROP TABLE文のCASCADE CONSTRAINTS句の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。この方法では、削除される表の主キーと一意キーを参照するすべての参照整合性制約が削除されます。

FOREIGN KEY制約の管理

外部キー制約は、異なる表の列同士の関連を規定します。したがって、参照中の主キーまたは一意キーの制約が存在していないか、または使用可能になっていない場合は、制約を使用可能にできません。

外部キー列のデータ型および名前

依存する側の表と参照される側の表の対応する列は、同じデータ型である必要があります。列名が一致する必要はありません。

複合外部キーにおける列の制限

外部キーは、親表の主キーまたは一意キーを参照し、主キー制約および一意キー制約は索引を使用して施行されるため、複合外部キーは32列以内に制限されています。

デフォルトでの外部キーの主キー参照

外部キー制約(単一列または複合列)を定義するときに、REFERENCESオプションに列リストが指定されていないと、Oracle Databaseは、指定した表の主キーが参照されるものとみなします。または、カッコの中に親表で参照する列を明示的に指定できます。この列リストが親表の主キーまたは一意キーを参照するかどうかは、Oracle Databaseによって自動的に確認されます。参照していない場合は、エラー情報が戻されます。

FOREIGN KEY制約の作成に必要な権限

外部キー制約を作成するには、制約の作成者に親表および子表に対するアクセス権限が必要です。

- 親表 参照整合性制約の作成者は、親表を所有するか、または親表の親キーを構成する列に対するREFERENCESオブジェクト権限が必要です。

- 子表 参照整合性制約の作成者は、表を作成する権限(CREATE TABLEまたはCREATE ANY TABLEシステム権限)または子表を変更する権限(子表のALTERオブジェクト権限またはALTER ANY TABLEシステム権限)が必要です。

どちらの場合も、必要な権限をロールを介して取得することはできません。権限は、明示的に制約の作成者に付与する必要があります。

これらの制限によって、次のことが可能となります。

- 子表の所有者は、施行される制約の種類、または制約を作成できる他のユーザーを、明示的に決定できます。

- 親表の所有者は、外部キーが所有者自身の表の主キーおよび一意キーに依存可能であるかどうかを明示的に決定できます。

外部キーによる参照整合性の施行方法の選択

Oracle Databaseでは、外部キー制約の定義の指定どおりに、異なるタイプの参照整合性アクションを施行できます。

- 親キーの削除または更新の回避 このデフォルト設定を指定すると、キーを参照する行が子表内にある場合、親キーが削除または更新されることはありません。次に例を示します。

CREATE TABLE Emp_tab (
FOREIGN KEY (Deptno) REFERENCES Dept_tab);

- 親キー削除時の子である行の削除 ON DELETE CASCADEアクションを指定すると、子表が参照する親キーのデータを削除できます。ただし、更新はできません。親キー内のデータが削除されると、削除された親キー値に依存する子表のすべての行も削除されます。この参照アクションを指定するには、外部キー制約の定義にON DELETE CASCADEオプションを指定します。次に例を示します。

CREATE TABLE Emp_tab (
FOREIGN KEY (Deptno) REFERENCES Dept_tab
ON DELETE CASCADE);

- 親キー削除時の外部キーへのNULL設定 ON DELETE SET NULLアクションを指定すると、親キーを参照するデータを削除できます。ただし、更新はできません。親キー内の参照データが削除されると、削除された親キー値に依存する子表内のすべての行の外部キーがNULLに設定されます。この参照アクションを指定するには、外部キー制約の定義にON DELETE SET NULLオプションを指定します。次に例を示します。

CREATE TABLE Emp_tab (
FOREIGN KEY (Deptno) REFERENCES Dept_tab
ON DELETE SET NULL);

制約に関する情報の表示

制約の名前、影響がある列および制約の管理に有効な他の情報を検索するには、例5-14のように静的データ・ディクショナリ・ビュー*_CONSTRAINTSおよび*_CONS_COLUMNSに問い合せます。

参照:
*_CONSTRAINTSおよび*_CONS_COLUMNSの詳細は、『Oracle Databaseリファレンス』を参照してください。

例5-14 制約に関する情報の表示

DROP TABLE DeptTab;
CREATE TABLE DeptTab (
Deptno  NUMBER(3) PRIMARY KEY,
Dname   VARCHAR2(15),
Loc     VARCHAR2(15),
CONSTRAINT uk_DeptTab_Dname_Loc UNIQUE (Dname, Loc),
CONSTRAINT c_DeptTab_Loc
CHECK (Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO'))
);

DROP TABLE EmpTab;
CREATE TABLE EmpTab (
Empno    NUMBER(5) PRIMARY KEY,
Ename    VARCHAR2(15) NOT NULL,
Job      VARCHAR2(10),
Mgr      NUMBER(5) CONSTRAINT r_EmpTab_Mgr
REFERENCES EmpTab ON DELETE CASCADE,
Hiredate DATE,
Sal      NUMBER(7,2),
Comm     NUMBER(5,2),
Deptno   NUMBER(3) NOT NULL
CONSTRAINT r_EmpTab_Deptno REFERENCES DeptTab
);

-- Format columns (optional):

COLUMN CONSTRAINT_NAME   FORMAT A20;
COLUMN CONSTRAINT_TYPE   FORMAT A4 HEADING 'TYPE';
COLUMN TABLE_NAME        FORMAT A10;
COLUMN R_CONSTRAINT_NAME FORMAT A17;
COLUMN SEARCH_CONDITION  FORMAT A40;
COLUMN COLUMN_NAME       FORMAT A12;

DeptTabおよびEmpTabでアクセス可能な制約をリスト:

SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME, R_CONSTRAINT_NAME
FROM USER_CONSTRAINTS
WHERE (TABLE_NAME = 'DEPTTAB' OR TABLE_NAME = 'EMPTAB')
ORDER BY CONSTRAINT_NAME;

結果:

CONSTRAINT_NAME      TYPE TABLE_NAME R_CONSTRAINT_NAME
-------------------- ---- ---------- -----------------
C_DEPTTAB_LOC        C    DEPTTAB
R_EMPTAB_DEPTNO      R    EMPTAB     SYS_C006286
R_EMPTAB_MGR         R    EMPTAB     SYS_C006290
SYS_C006286          P    DEPTTAB
SYS_C006288          C    EMPTAB
SYS_C006289          C    EMPTAB
SYS_C006290          P    EMPTAB
UK_DEPTTAB_DNAME_LOC U    DEPTTAB

8 rows selected.

DeptTabおよびEmpTabで、制約NOT NULLとCHECKを区別:

SELECT CONSTRAINT_NAME, SEARCH_CONDITION
FROM USER_CONSTRAINTS
WHERE (TABLE_NAME = 'DEPTTAB' OR TABLE_NAME = 'EMPTAB')
AND CONSTRAINT_TYPE = 'C'
ORDER BY CONSTRAINT_NAME;

結果:

CONSTRAINT_NAME      SEARCH_CONDITION
-------------------- ----------------------------------------
C_DEPTTAB_LOC        Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO')
SYS_C006288          "ENAME" IS NOT NULL
SYS_C006289          "DEPTNO" IS NOT NULL

3 rows selected.

DeptTabおよびEmpTabで、制約を構成する列をリスト:

SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME
FROM USER_CONS_COLUMNS
WHERE (TABLE_NAME = 'DEPTTAB' OR TABLE_NAME = 'EMPTAB')
ORDER BY CONSTRAINT_NAME;

結果:

CONSTRAINT_NAME      TABLE_NAME COLUMN_NAME
-------------------- ---------- ------------
C_DEPTTAB_LOC        DEPTTAB    LOC
R_EMPTAB_DEPTNO      EMPTAB     DEPTNO
R_EMPTAB_MGR         EMPTAB     MGR
SYS_C006286          DEPTTAB    DEPTNO
SYS_C006288          EMPTAB     ENAME
SYS_C006289          EMPTAB     DEPTNO
SYS_C006290          EMPTAB     EMPNO
UK_DEPTTAB_DNAME_LOC DEPTTAB    LOC
UK_DEPTTAB_DNAME_LOC DEPTTAB    DNAME

9 rows selected.

次のことに注意してください。

- 制約名には、ユーザー指定(たとえば、UK_DEPTTAB_DNAME_LOC)のものと、システム指定(たとえば、SYS_C006290)のものがあります。

- 各制約タイプは、CONSTRAINT_TYPE列に別々の文字で表示されます。次の表に、各制約タイプに対応する文字を示します。

制約タイプ

文字

主キー

P

UNIQUEキー

U

外部キー

R

CHECK、NOT NULL

C

注意:
その他の制約タイプで、CONSTRAINT_TYPE列に「V」の文字で表示されるものがあります。この制約タイプは、ビューに対するWITH CHECK OPTIONを使用して作成された制約に対応しています。

次の制約は、SEARCH_CONDITION列に明示的にリストされます。

- NOT NULL制約

- ユーザー定義CHECK制約の条件

第II部

アプリケーション開発者用のPL/SQL

ここでは、アプリケーション開発者が必要とする、SQLの手続き型拡張言語であるOracleのPL/SQLについて説明します。

章:

- 第6章「PL/SQLサブプログラムおよびパッケージのコード化」

- 第7章「PL/Scopeの使用」

- 第8章「PL/SQL階層プロファイラの使用」

- 第9章「PL/SQL Webアプリケーションの開発」

- 第10章「PL/SQL Server Pages(PSP)の開発」

- 第11章「連続問合せ通知(CQN)の使用」

参照:
PL/SQLの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

6 PL/SQLサブプログラムおよびパッケージのコード化

ここでは、Oracle Databaseがアプリケーション開発用に提供するプロシージャ機能のいくつかを説明します。

内容は次のとおりです。

- PL/SQLユニットの概要

- ネイティブ実行のためのPL/SQLサブプログラムのコンパイル

- カーソル変数

- PL/SQLコンパイル時のエラー処理

- PL/SQLのランタイム・エラー処理

- ストアド・サブプログラムのデバッグ

- ストアド・サブプログラムの起動

- リモート・サブプログラムの起動

- SQL文からのストアドPL/SQLファンクションの起動

- ファンクションからの大量のデータの戻し

- 独自の集計関数のコード化

参照:

- PL/SQLサブプログラムの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- PL/SQLパッケージの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- PL/SQLコードの問題を発見する手助けとなるアプリケーションのトレース・ツールの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

PL/SQLユニットの概要

PL/SQLは、現代的なブロック構造化プログラミング言語です。この言語が持ついくつかの機能を使用すると、高性能のデータベース・アプリケーションを容易に作成できます。たとえば、PL/SQLは、ループ文や条件文など標準SQLにはないプロシージャ構造を提供します。

PL/SQLブロック内部でSQLデータ操作言語(DML)の文を直接入力できます。また、Oracleが提供するサブプログラムを使用して、データ定義言語(DDL)の文を実行できます。

PL/SQLコードはサーバー上で実行されるため、PL/SQLを使用するとデータベース・アプリケーションのかなりの部分を集中化でき、メンテナンス性およびセキュリティが強化されます。また、クライアント/サーバー・アプリケーションでは、ネットワークのオーバーヘッドも大幅に削減できます。

注意:
Oracle Formsなど、Oracleの一部のツール製品にはPL/SQLエンジンが組み込まれ、ローカルでPL/SQLを実行できます。

また、一部のデータベース・アプリケーションでは、埋込みSQLまたはOracle Call Interface(OCI)を使用する3GLプログラムのかわりにPL/SQLを使用できます。

PL/SQLユニットには、次のものが含まれます。

- 無名ブロック

- ストアドPL/SQLユニット

- トリガー

参照:

- PL/SQLパッケージの構文と操作の例は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- Oracle Databaseに付属するPL/SQLパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- ストアドPL/SQLユニット間の依存性の詳細は、「ローカル・データベース・プロシージャとリモート・データベース・プロシージャの間の依存性」を参照してください。

無名ブロック

無名ブロックとは、名前のないPL/SQLユニットのことです。無名ブロックは、オプションの宣言部分、実行可能部分および1つまたは複数のオプションの例外ハンドラで構成されます。

宣言部にはPL/SQLの変数、例外およびカーソルを宣言します。実行可能部分にはPL/SQLコードおよびSQL文を含むネストされたブロックを含めることができます。

例外ハンドラには、例外状況が発生したときに、事前定義のPL/SQL例外(NO_DATA_FOUNDまたはZERO_DIVIDE)として、またはユーザー定義の例外として起動されるコードが含まれています。

無名ブロックは、通常、SQL*Plusなどのツール製品から対話形式で使用するか、プリコンパイラ、OCIまたはSQL*Moduleアプリケーションで使用します。通常、ストアド・サブプログラムを起動するか、カーソル変数をオープンするために使用します。

例6-1の無名ブロックは、DBMS_OUTPUTパッケージを使用してHR.EMPLOYEES表の部門20のすべての従業員の名前を表示します。

例6-1 無名ブロック

DECLARE
last_name  VARCHAR2(10);
cursor     c1 IS
SELECT LAST_NAME
FROM EMPLOYEES
WHERE DEPARTMENT_ID = 20
ORDER BY LAST_NAME;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO last_name;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(last_name);
END LOOP;
END;
/

結果:

Fay
Hartstein

例外を使用すると、PL/SQLプログラム・ロジック内のOracle Databaseエラー条件を処理し、使用中のアプリケーションで、クライアント・アプリケーションを異常終了させるようなエラーをサーバーが発行しないようにすることができます。例6-2の無名ブロックは、事前定義されたOracle Database例外NO_DATA_FOUNDを処理します(この例外が処理されない場合は、ORA-01403が発生します)。

例6-2 事前定義されたエラーの例外ハンドラを持つ無名ブロック

DECLARE
Emp_number  INTEGER := 9999
Emp_name    VARCHAR2(10);
BEGIN
SELECT LAST_NAME INTO Emp_name
FROM EMPLOYEES
WHERE EMPLOYEE_ID = Emp_number;
DBMS_OUTPUT.PUT_LINE('Employee name is ' || Emp_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No such employee: ' || Emp_number);
END;
/

結果:

No such employee: 9999

また、独自の例外を定義することもできます。つまり、例6-3に示すように、ブロックの宣言部に宣言し、それをブロックの例外部分に指定できます。

例6-3 ユーザー定義例外の例外ハンドラを持つ無名ブロック

DECLARE
Emp_name            VARCHAR2(10);
Emp_number          INTEGER;
Empno_out_of_range  EXCEPTION;
BEGIN
Emp_number := 10001;
IF Emp_number > 9999 OR Emp_number < 1000 THEN
RAISE Empno_out_of_range;
ELSE
SELECT LAST_NAME INTO Emp_name
FROM EMPLOYEES
WHERE EMPLOYEE_ID = Emp_number;
DBMS_OUTPUT.PUT_LINE('Employee name is ' || Emp_name);
END IF;
EXCEPTION
WHEN Empno_out_of_range THEN
DBMS_OUTPUT.PUT_LINE('Employee number ' || Emp_number ||
' is out of range.');
END;
/

結果:

Employee number 10001 is out of range.

参照:

- DBMS_OUTPUTパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- 『Oracle Database PL/SQL言語リファレンス』および「PL/SQLのランタイム・エラー処理」

- 「カーソル変数」

ストアドPL/SQLユニット

ストアドPL/SQLユニットは、次のような特徴を持つサブプログラム(プロシージャまたはファンクション)またはパッケージです。

- 固有の名前を持っています。

- パラメータをとり、値を戻すことができます。

- データ・ディクショナリに格納されます。

- 多数のユーザーが起動できます。

パッケージに属しているサブプログラムをパッケージ・サブプログラム、そうでないサブプログラムをスタンドアロン・サブプログラムといいます。

内容は次のとおりです。

- サブプログラムのネーミング

- サブプログラムのパラメータ

- サブプログラムの作成

- サブプログラムの変更

- サブプログラムおよびパッケージの削除

- 外部サブプログラム

- PL/SQLファンクション結果キャッシュ

- PL/SQLパッケージ

- PL/SQLオブジェクト・サイズの制限

- パッケージの作成

- パッケージおよびパッケージ・オブジェクトのネーミング

- パッケージの無効化とセッションの状態

- Oracle Databaseが提供するパッケージ

- バルク・バインドの概要

- バルク・バインドを使用する場合

サブプログラムのネーミング

サブプログラムは、データベース内に格納されるため、名前を付ける必要があります。これによって、他のストアド・サブプログラムと区別され、アプリケーションで起動できます。パブリックで参照できるスキーマ内の各サブプログラムは、一意の名前を持つ必要があり、その名前は、有効なPL/SQL識別子である必要があります。

注意:
SQL*Moduleによって生成されたスタブを使用してストアド・サブプログラムを起動する場合、ストアド・サブプログラム名は、起動側ホストの3GL言語(AdaやCなど)の有効な識別子である必要もあります。

サブプログラムのパラメータ

ストアド・サブプログラムには、パラメータを指定できます。例6-4のプロシージャでは、部門番号が入力パラメータになっており、パラメータ化されたカーソルc1のオープン時に使用されます。

例6-4 パラメータを使用するストアド・プロシージャ

CREATE OR REPLACE PROCEDURE get_emp_names (
dept_num IN NUMBER
)
IS
emp_name  VARCHAR2(10);
CURSOR    c1 (dept_num NUMBER) IS
SELECT LAST_NAME FROM EMPLOYEES
WHERE DEPARTMENT_ID = dept_num;
BEGIN
OPEN c1(dept_num);
LOOP
FETCH c1 INTO emp_name;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_name);
END LOOP;
CLOSE c1;
END;
/

サブプログラムの仮パラメータには、表6-1に示す3つの主要な属性があります。

表6-1 サブプログラム・パラメータの属性

パラメータ属性

説明

名前

名前は、有効なPL/SQL識別子である必要があります。

モード

入力のみのパラメータ(IN)、出力のみのパラメータ(OUT)、入力と出力の両方のパラメータ(IN OUT)のどれであるかを示します。モードを指定しないと、INが想定されます。

データ型

パラメータのデータ型は、標準PL/SQLデータ型です。

内容は次のとおりです。

- パラメータ・モード

- パラメータ・データ型

- %TYPE属性および%ROWTYPE属性

- パラメータとしてのコンポジット変数の受渡し

- パラメータの初期値

パラメータ・モード

パラメータ・モードは、仮パラメータの動作を定義します。サブプログラムには、IN(デフォルト)、OUT、IN OUTという3つのパラメータ・モードを使用できます。ファンクションには、OUTモードおよびIN OUTモードは使用しないでください。実際のプログラミングでは、ファンクションにより単一の値が戻され、かつサブプログラムに対してローカルでない変数の値が変更されないことが求められます。

参照:
パラメータ・モードの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

パラメータ・データ型

仮パラメータのデータ型は、次のいずれかで構成されています。

- NUMBERやVARCHAR2などの無制約の型名

- %TYPE属性や%ROWTYPE属性を使用して制約される型

注意:
NUMBER(2)または VARCHAR2(20)などの数値が制約される型は、パラメータ・リストでは使用できません。

%TYPE属性および%ROWTYPE属性

型属性%TYPEおよび%ROWTYPEは、パラメータを制約するために使用します。たとえば、例6-4のプロシージャ・ヘッダーは次のように記述することができます。

PROCEDURE get_emp_names(dept_num IN EMPLOYEES.DEPARTMENT_ID%TYPE)

このようにすると、dept_numパラメータのデータ型がEMPLOYEES表のDEPARTMENT_ID列と同じになります。%TYPE(または%ROWTYPE)を使用した宣言を作成する場合は、列および表が使用可能である必要があります。

表の列の型が変更されてもアプリケーション・コードを変更する必要がないため、%TYPEの使用をお薦めします。

get_emp_namesプロシージャがパッケージの一部である場合は、前に宣言したパブリック(パッケージ)変数を使用して、パラメータのデータ型を制約できます。次に例を示します。

dept_number  NUMBER(2);
...
PROCEDURE get_emp_names(dept_num IN dept_number%TYPE);

%ROWTYPE属性は、指定された表のすべての列を含むレコードを作成するために使用します。例6-5のプロシージャは、指定された従業員IDに関するPL/SQLレコード内のEMPLOYEES表のすべての列を返します。

例6-5 %TYPEおよび%ROWTYPE属性

CREATE OR REPLACE PROCEDURE get_emp_rec (
emp_number  IN  EMPLOYEES.EMPLOYEE_ID%TYPE,
emp_info    OUT EMPLOYEES%ROWTYPE
)
IS
BEGIN
SELECT * INTO emp_info
FROM EMPLOYEES
WHERE EMPLOYEE_ID = emp_number;
END;
/

PL/SQLブロックからプロシージャを起動します。

DECLARE
emp_row  EMPLOYEES%ROWTYPE;
BEGIN
get_emp_rec(206, emp_row);
DBMS_OUTPUT.PUT('EMPLOYEE_ID: ' || emp_row.EMPLOYEE_ID);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('FIRST_NAME: ' || emp_row.FIRST_NAME);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('LAST_NAME: ' || emp_row.LAST_NAME);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('EMAIL: ' || emp_row.EMAIL);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('PHONE_NUMBER: ' || emp_row.PHONE_NUMBER);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('HIRE_DATE: ' || emp_row.HIRE_DATE);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('JOB_ID: ' || emp_row.JOB_ID);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('SALARY: ' || emp_row.SALARY);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('COMMISSION_PCT: ' || emp_row.COMMISSION_PCT);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('MANAGER_ID: ' || emp_row.MANAGER_ID);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT('DEPARTMENT_ID: ' || emp_row.DEPARTMENT_ID);
DBMS_OUTPUT.NEW_LINE;
END;
/

結果:

EMPLOYEE_ID: 206
FIRST_NAME: William
LAST_NAME: Gietz
EMAIL: WGIETZ
PHONE_NUMBER: 515.123.8181
HIRE_DATE: 07-JUN-02
JOB_ID: AC_ACCOUNT
SALARY: 8300
COMMISSION_PCT:
MANAGER_ID: 205
DEPARTMENT_ID: 110

ストアド・ファンクションは、%ROWTYPEを使用して宣言される値を戻すことができます。次に例を示します。

FUNCTION get_emp_rec (dept_num IN EMPLOYEES.DEPARTMENT_ID%TYPE)
RETURN EMPLOYEES%ROWTYPE IS ...

パラメータとしてのコンポジット変数の受渡し

PL/SQLコンポジット変数(コレクションおよびレコード)をパラメータとしてストアド・サブプログラムに渡すことができます。

サブプログラムがリモートである場合は、冗長なループバックDBLINKを作成する必要があります。これにより、リモート・サブプログラムがコンパイルされたときに、ソースを検証するタイプ・チェッカが、実行者の使用しているものと同じユーザー定義のコンポジット変数型定義を使用するようになります。

パラメータの初期値

パラメータには、初期値を設定できます。パラメータに初期値を設定するには、代入演算子、またはDEFAULTキーワードを使用します。たとえば、次の2つは同じ設定です。

PROCEDURE Get_emp_names (Dept_num IN NUMBER := 20) IS ...
PROCEDURE Get_emp_names (Dept_num IN NUMBER DEFAULT 20) IS ...

パラメータに初期値を使用する場合は、サブプログラムの起動時に実パラメータ・リストからそのパラメータを省略できます。起動時に初期値を指定すると、デフォルト値がオーバーライドされます。

注意:
無名PL/SQLブロック内とは異なり、ストアド・サブプログラム内では、変数、カーソルおよび例外の宣言の前にキーワードDECLAREを使用しないでください。使用するとエラーが発生します。

サブプログラムの作成

サブプログラムを作成するには、テキスト・エディタを使用します。その後、SQL*Plusなどの対話形式のツール製品を使用して次の文を入力し、プロシージャを含むテキスト・ファイルをロードします。

@get_emp

プロシージャが、get_emp.sqlファイル(sqlは、デフォルトのファイル拡張子)から現行のスキーマにロードされます。コードの末尾にあるスラッシュ(/)はコードの一部ではなく、プロシージャのロードをアクティブにするためのものです。

注意:
サブプログラムを作成する場合、通常はCREATE OR REPLACE PROCEDURE文またはCREATE OR REPLACE FUNCTION文を使用することをお薦めします。この文は、同一スキーマ内の前のバージョンのサブプログラムを新しいバージョンに置き換えますが、警告なしで実行されます。

サブプログラム・パラメータ・リストの後にキーワードISまたはASを使用できます。

参照:

- CREATE FUNCTION文の構文は、『Oracle Database SQL言語リファレンス』を参照してください。

- CREATE PROCEDURE文の構文は、『Oracle Database SQL言語リファレンス』を参照してください。

必要な権限

サブプログラム、パッケージ仕様部またはパッケージ本体を作成するには、次の前提条件を満たす必要があります。

- スキーマにサブプログラムまたはパッケージを作成するには、CREATE PROCEDUREシステム権限が必要で、他のユーザーのスキーマにサブプログラムまたはパッケージを作成するには、CREATE ANY PROCEDUREシステム権限が必要です。いずれの場合も、パッケージ本体をパッケージと同じスキーマに作成する必要があります。

注意:
エラーなしで作成する(サブプログラムまたはパッケージを正常にコンパイルする)には、さらに次の権限が必要です。

- サブプログラムまたはパッケージの所有者は、コード本体内で参照されるすべてのオブジェクトに必要なオブジェクト権限を明示的に付与されている必要があります。

- 所有者は、ロールを使用して必要な権限を取得することはできません。

サブプログラムまたはパッケージの所有者の権限が変更された場合、実行前にそのサブプログラムを再認証する必要があります。参照オブジェクトに必要な権限が、そのサブプログラムまたはパッケージの所有者から取り消されている場合、そのサブプログラムは実行できません。

サブプログラムのEXECUTE権限があれば、他のユーザーが所有するサブプログラムを実行できます。権限が付与されたユーザーは、そのサブプログラムの所有者のセキュリティ・ドメインでサブプログラムを実行します。このため、ユーザーは、サブプログラムが参照するオブジェクトの権限を得る必要はありません。これによって、データベース・アプリケーションおよびそのユーザーによるさらに統制のとれた効率的なセキュリティ計画が可能になります。また、すべてのサブプログラムおよびパッケージが(SYSTEM表領域内の)データ・ディクショナリに格納されます。サブプログラムおよびパッケージを作成するユーザーが使用できる領域の容量は、割当て制限によっては制御されません。

サブプログラムの変更

サブプログラムを変更するには、最初にDROP PROCEDURE文またはDROP FUNCTION文を使用して、そのサブプログラムを削除し、CREATE PROCEDURE文またはCREATE FUNCTION文を使用して、そのサブプログラムを再作成する必要があります。または、CREATE OR REPLACE PROCEDURE文またはCREATE OR REPLACE FUNCTION文を使用します(この文は、サブプログラムがすでに存在する場合、最初にそれを削除してから、指定どおりに再作成します)。

注意:
サブプログラムが削除される際、警告は表示されません。

サブプログラムおよびパッケージの削除

SQL文のDROP PROCEDURE、DROP FUNCTION、DROP PACKAGE BODY、DROP PACKAGEを使用して、スタンドアロン・サブプログラム、スタンドアロン・ファンクション、パッケージ本体またはパッケージ全体をそれぞれ削除できます。DROP PACKAGE文は、パッケージの仕様部と本体の両方を削除します。

次の文は、スキーマ内にあるOld_sal_raiseプロシージャを削除します。

DROP PROCEDURE Old_sal_raise;

必要な権限

サブプログラムまたはパッケージを削除するには、それらが自スキーマ内にあるか、またはDROP ANY PROCEDURE権限が必要です。パッケージ内の個々のサブプログラムは削除できないため、これらを削除せずに、パッケージ仕様部および本体を再作成する必要があります。

外部サブプログラム

Oracle Databaseのインスタンス上で実行するPL/SQLサブプログラムは、第三世代言語(3GL)で作成された外部サブプログラムを起動できます。3GLサブプログラムは、データベースのアドレス空間とは別のアドレス空間で実行されます。

参照:
外部サブプログラムの詳細は、第14章「複数のプログラミング言語を使用したアプリケーションの開発」を参照してください。

PL/SQLファンクション結果キャッシュ

PL/SQLファンクション結果キャッシュを使用すると、領域と時間を大幅に節約できます。結果キャッシュPL/SQLファンクションを、異なるパラメータ値を使用して起動するたびに、それらのパラメータおよびその結果がキャッシュに格納されます。それ以降、同じパラメータ値を使用して同じファンクションを起動すると、その結果は再計算されるのではなく、キャッシュから取得されます。キャッシュは共有グローバル領域(SGA)に格納されるため、アプリケーションが実行されるすべてのセッションで使用可能です。

キャッシュ結果を計算する際に使用したデータベース・オブジェクトが更新されると、そのキャッシュ結果は無効になり、再計算が必要になります。

結果キャッシュの対象として最適のファンクションは、起動される頻度が高く、かつほとんど変更されない情報に依存するものです。

PL/SQLファンクション結果キャッシュの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

PL/SQLパッケージ

パッケージとは、データベース内に1つの単位として格納されている関連プログラム・オブジェクト(サブプログラム、変数、定数、カーソル、例外など)のコレクションです。

パッケージは、サブプログラムをスタンドアロンのスキーマ・オブジェクトとして作成するかわりに使用します。パッケージには、スタンドアロンのサブプログラムに比べて、多数のメリットがあります。たとえば、次のことができます。

- アプリケーション開発をより効率的に行えます。

- 権限をより効率的に付与できます。

- 依存スキーマ・オブジェクトを再コンパイルせずにパッケージ・オブジェクトを変更できます。

- Oracle Databaseで複数のパッケージ・オブジェクトを一度にメモリー内に読み込めます。

- パッケージ内のすべてのサブプログラムが使用できるグローバル変数およびグローバル・カーソルを、そのパッケージ内に含めることができます。

- サブプログラムをオーバーロードします。サブプログラムのオーバーロードとは、同一パッケージ内に同じ名前のサブプログラムを複数作成することで、それぞれのサブプログラムには異なる数またはデータ型の引数が指定されます。

参照:
サブプログラムの名前のオーバーロードの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

パッケージ仕様部は、パッケージの有効範囲外で参照できるパブリック型、変数、定数およびサブプログラムを宣言します。パッケージ本体は、パッケージ外のアプリケーションが参照できないプライベート・オブジェクトのみでなく、仕様部で宣言されているオブジェクトも定義します。

例6-6は、1つのストアド・ファンクションおよび2つのストアド・プロシージャを含むパッケージを作成し、プロシージャの1つを起動します。

例6-6 PL/SQLパッケージの作成とパッケージ・サブプログラムの起動

-- Sequence that package function needs:

CREATE SEQUENCE emp_sequence
START WITH 8000
INCREMENT BY 10;

-- Package specification:

CREATE or REPLACE PACKAGE employee_management IS
FUNCTION hire_emp (
firstname  VARCHAR2,
lastname   VARCHAR2,
email      VARCHAR2,
phone      VARCHAR2,
hiredate   DATE,
job        VARCHAR2,
sal        NUMBER,
comm       NUMBER,
mgr        NUMBER,
deptno     NUMBER
) RETURN NUMBER;

PROCEDURE fire_emp(
emp_id IN NUMBER
);

PROCEDURE sal_raise (
emp_id IN NUMBER,
sal_incr IN NUMBER
);
END employee_management;
/

-- Package body:

CREATE or REPLACE PACKAGE BODY employee_management IS
FUNCTION hire_emp (
firstname  VARCHAR2,
lastname   VARCHAR2,
email      VARCHAR2,
phone      VARCHAR2,
hiredate   DATE,
job        VARCHAR2,
sal        NUMBER,
comm       NUMBER,
mgr        NUMBER,
deptno     NUMBER
) RETURN NUMBER
IS
new_empno  NUMBER(10);
BEGIN
new_empno := emp_sequence.NEXTVAL;

INSERT INTO EMPLOYEES (
employee_id,
first_name,
last_name,
email,
phone_number,
hire_date,
job_id,
salary,
commission_pct,
manager_id,
department_id
)
VALUES (
new_empno,
firstname,
lastname,
email,
phone,
hiredate,
job,
sal,
comm,
mgr,
deptno
);

RETURN (new_empno);
END hire_emp;

PROCEDURE fire_emp (
emp_id IN NUMBER
) IS
BEGIN
DELETE FROM EMPLOYEES
WHERE EMPLOYEE_ID = emp_id;

IF SQL%NOTFOUND THEN
raise_application_error(
-20011,
'Invalid Employee Number: ' || TO_CHAR(Emp_id)
);
END IF;
END fire_emp;

PROCEDURE sal_raise (
emp_id IN NUMBER,
sal_incr IN NUMBER
) IS
BEGIN
UPDATE EMPLOYEES
SET SALARY = SALARY + sal_incr
WHERE EMPLOYEE_ID = emp_id;

IF SQL%NOTFOUND THEN
raise_application_error(
-20011,
'Invalid Employee Number: ' || TO_CHAR(Emp_id)
);
END IF;
END sal_raise;
END employee_management;
/

パッケージ・プロシージャを起動します。

DECLARE
empno  NUMBER(6);
sal    NUMBER(6);
temp   NUMBER(6);
BEGIN
empno := employee_management.hire_emp(
'John',
'Doe',
'john.doe@company.com',
'555-0100',
'20-SEP-07',
'ST_CLERK',
2500,
0,
100,
20);

DBMS_OUTPUT.PUT_LINE('New employee ID is ' || TO_CHAR(empno));
END;
/

PL/SQLオブジェクト・サイズの制限

サブプログラム、トリガー、パッケージなどのPL/SQLストアド・データベース・オブジェクトのサイズは、共有プール内のDescriptive Intermediate Attributed Notation for Ada(DIANA)コードのサイズ(バイト単位)に制限されています。フラット化されたDIANA/codeのサイズの制限は、LinuxやUNIXでは64KBですが、デスクトップ・プラットフォームでは32KBに制限されている場合があります。

ユーザーがアクセスできるもので最も密接に関連する数値は、静的データ・ディクショナリ・ビュー*_OBJECT_SIZEのPARSED_SIZEです。これには、SYS.IDL_xxx$表に格納されたDIANAのサイズがバイト単位で示されています。これは共有プールでのサイズではありません。(コンパイル中に使用される)PL/SQLコードのDIANA部分のサイズは、システム表内より共有プール内で非常に大きくなります。

パッケージの作成

パッケージの各部は、異なる文を使用して作成します。パッケージ仕様部は、CREATE PACKAGE文を使用して作成します。CREATE PACKAGE文でパブリック・パッケージ・オブジェクトを宣言します。

パッケージ本体を作成するには、CREATE PACKAGE BODY文を使用します。CREATE PACKAGE BODY文は、パッケージ仕様部で宣言されているパブリック・サブプログラムの手続き型コードを定義します。

パッケージ本体にはプライベート(またはローカル)・パッケージ・サブプログラムおよび変数も定義できます。これらのオブジェクトは、同一パッケージの本体内の他のサブプログラムでのみアクセスできます。外部ユーザーはどの権限を持っていても参照できません。

初めてアプリケーションを開発する場合、CREATE PACKAGE文またはCREATE PACKAGE BODY文にOR REPLACE句を追加すると便利な場合があります。このオプションの効果は、警告なしでパッケージまたはパッケージ本体が削除されることです。CREATE文は次のようになります。

CREATE OR REPLACE PACKAGE Package_name AS ...

および

CREATE OR REPLACE PACKAGE BODY Package_name AS ...

パッケージ・オブジェクトの作成

パッケージ本体には、次のものを含めることができます。

- パッケージ仕様部に宣言されているサブプログラム。

- パッケージ仕様部に宣言されているカーソルの定義。

- パッケージ仕様部に宣言されていないローカル・サブプログラム。

- ローカル変数。

パッケージ仕様部に宣言されているサブプログラム、カーソルおよび変数はグローバルです。これらを起動または使用できるのは、パッケージに対するEXECUTE権限を持つ外部ユーザーまたはEXECUTE ANY PROCEDURE権限を持つ外部ユーザーです。

パッケージ本体を作成する場合は、本体に定義する個々のサブプログラムが、パッケージ仕様部の宣言と同じパラメータ(名前、データ型およびモード)を持つようにする必要があります。パッケージ本体内のファンクションは、パラメータと戻り型が、名前およびデータ型について仕様部と一致する必要があります。

パッケージの作成または削除に必要な権限

パッケージ仕様部またはパッケージ本体を作成または削除するために必要な権限は、スタンドアロン・サブプログラムの作成または削除に必要な権限と同じです。「サブプログラムの作成」および「サブプログラムおよびパッケージの削除」を参照してください。

パッケージおよびパッケージ・オブジェクトのネーミング

パッケージおよびパッケージ内のすべてのパブリック・オブジェクトの名前は、所定のスキーマ内で一意である必要があります。パッケージ仕様部およびその本体は、同じ名前である必要があります。また、パッケージのメンバーの名前は、サブプログラム名の重複が必要な場合を除き、そのパッケージの有効範囲内で一意である必要があります。

パッケージの無効化とセッションの状態

パッケージ・オブジェクトを参照する各セッションには、対応するパッケージの独自のインスタンスがあり、この中には、パブリック変数、プライベート変数、カーソルおよび定数に対する持続状態が含まれます。セッションのインスタンス化されたパッケージ(仕様部または本体)のいずれかが無効化されると、そのセッションのすべてのパッケージ・インスタンスが無効になり、再コンパイルされます。これにより、そのセッションのすべてのパッケージ・インスタンスに関するセッション状態は失われます。

セッションのパッケージが無効である場合、セッションが無効なパッケージ・インスタンスのオブジェクトを最初に使用しようとしたときに、ORA-04068が戻されます。2度目にセッションがこのようなパッケージ・コールを行うと、エラーは発生せずに、パッケージはセッションに対して再インスタンス化されます。ただし、このエラーをアプリケーションで処理する場合は、次の点に注意してください。

- パフォーマンスを最適な状態に保つため、Oracle Databaseがこのエラー・メッセージを戻すのは、パッケージ状態が破棄されるとき1回のみです。あるパッケージ内のサブプログラムにより別のパッケージ内のサブプログラムが起動される場合、両方のパッケージに対するセッション状態が失われます。

- サーバー・セッションがORA-04068をトラップした場合、クライアント・セッションに対してORA-04068は発生しません。したがって、このクライアント・セッションがパッケージ内のオブジェクトを使用しようとすると、このパッケージは再インスタンス化されません。パッケージを再インスタンス化するには、クライアント・セッションをデータベースに再接続するか、またはクライアント・セッションでパッケージを再コンパイルする必要があります。

例6-7では、RAISE文により、処理中の例外ORA-06508の原因である現在の例外ORA-04068が呼び出されます。ORA-04068は検出されません。

例6-7 ORA-04068の呼び出し

PROCEDURE p IS
package_exception EXCEPTION;
PRAGMA EXCEPTION_INIT (package_exception, -6508);
BEGIN
...
EXCEPTION
WHEN package_exception THEN
RAISE;
END;
/

例6-8では、RAISE文により、ORA-06508に応えて、現在の例外ORA-04068ではなく、例外ORA-20001が呼び出されます。ORA-04068が検出されます。このような場合、ORA-04068エラーはマスクされ、これにより、パッケージの再インスタンス化が停止します。

例6-8 ORA-04068の検出

PROCEDURE p IS
package_exception EXCEPTION;
other_exception   EXCEPTION;
PRAGMA EXCEPTION_INIT (package_exception, -6508);
PRAGMA EXCEPTION_INIT (other_exception, -20001);
BEGIN
...
EXCEPTION
WHEN package_exception THEN
...
RAISE other_exception;
END;
/

本番環境の多くでは、パッケージが無効になるDDL操作は、通常、業務時間外に行われるため、エンドユーザー・アプリケーションでは、このような状況は問題にならない可能性もあります。しかし、パッケージが業務時間中に無効になることがよくある場合は、パッケージ・コールが行われたときにこのエラーを処理するように、アプリケーションを作成することが必要になります。

Oracle Databaseが提供するパッケージ

データベースの機能性を拡張できるように、またはPL/SQLでSQL機能を使用できるように、Oracle Databaseには多数のパッケージが組み込まれています。これらのパッケージは、アプリケーションから起動できます。

参照:
これらのOracle Databaseパッケージの概要は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

バルク・バインドの概要

Oracle Databaseは2つのエンジンを使用して、PL/SQLブロックおよびサブプログラムを実行します。PL/SQLエンジンは手続き型の文を実行し、SQLエンジンはSQL文を実行します。実行中は、すべてのSQL文がこの2つのエンジン間でコンテキストをスイッチングするため、パフォーマンスが低下します。

特定のブロックまたはサブプログラムの実行に必要なコンテキストのスイッチング回数を最小化すると、パフォーマンスを大幅に改善できます。バインド変数としてコレクション要素を使用するループ内でSQL文が実行される場合、ブロックが必要とする多数のコンテキストのスイッチングによってパフォーマンスが低下することがあります。コレクションには次のものが含まれます。

- VARRAY

- ネストした表

- 索引付き表

- ホスト配列

バインドとは、SQL文内のPL/SQL変数に対して値を代入することです。バルク・バインドとは、コレクション全体を一度にバインドすることです。バルク・バインドは1つの操作でコレクション全体を2つのエンジン間で受け渡すことができます。

通常、バルク・バインドの使用によって、4つ以上のデータベース行に影響するSQL文のパフォーマンスが改善されます。SQL文によって影響される行数が多いほど、バルク・バインドによるパフォーマンスの向上率は高くなります。

注意:
この項では、PL/SQLアプリケーション内でバルク・バインドを使用するかどうかを判断するために役立つ、バルク・バインドの概要を説明します。バルク・バインドを操作する場合の例外の処理方法を含むバルク・バインドの使用方法の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。
バルク・バインドを使用する場合、パラレルDML文は無効になります。

バルク・バインドを使用する場合

次について、パフォーマンスを高めるようなバルク・バインドの使用方法を示します。

- コレクションを参照するDML文

- コレクションを参照するSELECT文

- コレクションを参照しDMLを戻すFORループ

コレクションを参照するDML文

FORALLキーワードを使用するバルク・バインドによって、コレクション要素を参照するINSERT、UPDATEまたはDELETE文のパフォーマンスが向上します。

例6-9のPL/SQLブロックは、管理職のID番号が7902、7698または7839の従業員について昇給を行うものですが、バルク・バインドを使用する場合と使用しない場合があります。PL/SQLがバルク・バインドを使用しないで、更新する各従業員についてSQLエンジンにSQL文を送信すると、コンテキストのスイッチングによってパフォーマンスが低下します。

例6-9 コレクションを参照するDML文

DECLARE
TYPE numlist IS VARRAY (100) OF NUMBER;
id NUMLIST := NUMLIST(7902, 7698, 7839);
BEGIN
-- Efficient method, using bulk bind:

FORALL i IN id.FIRST..id.LAST
UPDATE EMPLOYEES
SET SALARY = 1.1 * SALARY
WHERE MANAGER_ID = id(i);

-- Slower method:

FOR i IN id.FIRST..id.LAST LOOP
UPDATE EMPLOYEES
SET SALARY = 1.1 * SALARY
WHERE MANAGER_ID = id(i);
END LOOP;
END;
/

コレクションを参照するSELECT文

BULK COLLECT INTO句によって、コレクションを参照する問合せのパフォーマンスを改善できます。スカラー値表または%TYPE値表にBULK COLLECT INTOを使用できます。

例6-10のPL/SQLブロックは、複数の値の問合せを行ってその値をPL/SQL表に格納するものですが、バルク・バインドを使用する場合と使用しない場合があります。PL/SQLがバルク・バインドを使用しないで、選択された各従業員についてSQLエンジンにSQL文を送信すると、コンテキストのスイッチングによってパフォーマンスが低下します。

例6-10 コレクションを参照するSELECT文

DECLARE
TYPE var_tab IS TABLE OF VARCHAR2(20)
INDEX BY PLS_INTEGER;

empno    VAR_TAB;
ename    VAR_TAB;
counter  NUMBER;

CURSOR c IS
SELECT EMPLOYEE_ID, LAST_NAME
FROM EMPLOYEES
WHERE MANAGER_ID = 7698;
BEGIN
-- Efficient method, using bulk bind:

SELECT EMPLOYEE_ID, LAST_NAME BULK COLLECT
INTO empno, ename
FROM EMPLOYEES
WHERE MANAGER_ID = 7698;

-- Slower method:

counter := 1;

FOR rec IN c LOOP
empno(counter) := rec.EMPLOYEE_ID;
ename(counter) := rec.LAST_NAME;
counter := counter + 1;
END LOOP;
END;
/

コレクションを参照しDMLを戻すFORループ

BULK COLLECT INTOキーワードとともにFORALLキーワードを使用すると、コレクションを参照しDMLを戻すFORループのパフォーマンスを改善できます。

例6-11のPL/SQLブロックは、従業員コレクションのボーナスを計算し、EMPLOYEES表を更新します。さらに、ボーナスをbonus_list_inst列に戻します。この操作をバルク・バインドを使用して実行し、また使用せずに実行します。PL/SQLがバルク・バインドを使用しないで、更新する各従業員についてSQLエンジンにSQL文を送信すると、コンテキストのスイッチングによってパフォーマンスが低下します。

例6-11 コレクションを参照しDMLを返すFORループ

DECLARE
TYPE emp_list IS VARRAY(100) OF EMPLOYEES.EMPLOYEE_ID%TYPE;
empids emp_list := emp_list(182, 187, 193, 200, 204, 206);

TYPE bonus_list IS TABLE OF EMPLOYEES.SALARY%TYPE;
bonus_list_inst  bonus_list;

BEGIN
-- Efficient method, using bulk bind:

FORALL i IN empids.FIRST..empids.LAST
UPDATE EMPLOYEES
SET SALARY = 0.1 * SALARY
WHERE EMPLOYEE_ID = empids(i)
RETURNING SALARY BULK COLLECT INTO bonus_list_inst;

-- Slower method:

FOR i IN empids.FIRST..empids.LAST LOOP
UPDATE EMPLOYEES
SET SALARY = 0.1 * SALARY
WHERE EMPLOYEE_ID = empids(i)
RETURNING SALARY INTO bonus_list_inst(i);
END LOOP;
END;
/

トリガー

トリガーは、特殊な種類の無名PL/SQLブロックです。文レベルで、または影響を受ける各行に対して、SQL文の前後で起動するようにトリガーを定義できます。INSTEAD OFトリガーまたはシステム・トリガー(DATABASEまたはSCHEMAに対するトリガー)も定義できます。

参照:
トリガーの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

ネイティブ実行のためのPL/SQLサブプログラムのコンパイル

共有ライブラリにあるネイティブ・コードにPL/SQLサブプログラムをコンパイルすると、PL/SQLサブプログラムの処理を高速化できます。

ネイティブ・コンパイルは、提供されるパッケージおよびユーザーが独自に作成したサブプログラムの両方に使用できます。この方法でコンパイルされたサブプログラムは、共有サーバー構成(従来のマルチ・スレッド・サーバー)やOracle Real Application Clusters(Oracle RAC)など、すべてのサーバー環境で動作します。

この方法では、サブプログラムから起動されたSQL文の処理は高速化されないため、SQL実行にあまり時間を必要としない計算集中型サブプログラムに使用するのが効果的です。

Javaの場合は、ncompツールを使用して独自のパッケージおよびクラスをコンパイルできます。

参照:

- PL/SQLネイティブ・コンパイルの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- Javaネイティブ・コンパイルの詳細は、『Oracle Database Java開発者ガイド』を参照してください。

カーソル変数

カーソルは静的オブジェクトであり、カーソル変数はカーソルへのポインタです。そのため、サブプログラムとの間でパラメータとして受け渡すことができます。カーソル変数は、その存続期間内に別のカーソルを参照することもできます。

カーソル変数には、その他にも次のような利点があります。

- カプセル化
カーソル変数をオープンするストアド・サブプログラムに問合せを集中化できます。

- メンテナンスの容易さ
カーソルの変更が必要な場合は、ストアド・サブプログラムの変更のみで済みます。各アプリケーションで変更を行う必要はありません。

- セキュリティの利便性
アプリケーションのユーザーは、アプリケーションがサーバーに接続したときに使用したユーザー名です。ユーザーには、カーソルをオープンするストアド・サブプログラムに対するEXECUTE権限が必要です。ただし、ユーザーには、問合せで使用される表に対するREAD権限は必要ありません。この機能を使用して、表の列へのアクセスおよび他のストアド・サブプログラムへのアクセスを制限できます。

参照:
カーソル変数の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

内容は次のとおりです。

- カーソル変数の宣言およびオープン

- カーソル変数の例

カーソル変数の宣言およびオープン

メモリーは、通常、適切なALLOCATE文を使用してクライアント・アプリケーションのカーソル変数に割り当てられます。Pro*Cでは、EXEC SQL ALLOCATE cursor_name文を使用します。OCIでは、カーソル・データ域を使用します。

また、1つのサーバー・セッションのみで実行するアプリケーションでも、カーソル変数を使用できます。PL/SQLサブプログラムでカーソル変数を宣言してオープンし、他のPL/SQLサブプログラムのパラメータとして使用できます。

カーソル変数の例

この項では、PL/SQLでのカーソル変数の使用例を示します。

- 例6-12 カーソル変数を使用するデータのフェッチ

- 例6-13 識別子を使用したカーソル変数

参照:
プログラム・インタフェースを使用するカーソル変数の例がさらに必要な場合は、次のマニュアルを参照してください。

- 『Pro*COBOLプログラマーズ・ガイド』

- 『Oracle Call Interfaceプログラマーズ・ガイド』

例6-12では、PL/SQLカーソル変数型および2つのプロシージャを定義するパッケージを作成し、PL/SQLブロックからプロシージャを起動します。最初のプロシージャは、WHERE句にバインド変数を使用してカーソル変数をオープンします。2番目のプロシージャは、カーソル変数を使用してEMPLOYEES表の行をフェッチします。

例6-12 カーソル変数を使用するデータのフェッチ

CREATE OR REPLACE PACKAGE emp_data AS
TYPE emp_val_cv_type IS REF CURSOR
RETURN EMPLOYEES%ROWTYPE;

PROCEDURE open_emp_cv (
emp_cv       IN OUT emp_val_cv_type,
dept_number  IN     EMPLOYEES.DEPARTMENT_ID%TYPE
);

PROCEDURE fetch_emp_data (
emp_cv   IN  emp_val_cv_type,
emp_row  OUT EMPLOYEES%ROWTYPE
);
END emp_data;
/
CREATE OR REPLACE PACKAGE BODY emp_data AS
PROCEDURE open_emp_cv (
emp_cv       IN OUT emp_val_cv_type,
dept_number  IN     EMPLOYEES.DEPARTMENT_ID%TYPE
)
IS
BEGIN
OPEN emp_cv FOR
SELECT * FROM EMPLOYEES
WHERE DEPARTMENT_ID = dept_number
ORDER BY last_name;
END open_emp_cv;

PROCEDURE fetch_emp_data (
emp_cv   IN  emp_val_cv_type,
emp_row  OUT EMPLOYEES%ROWTYPE
)
IS
BEGIN
FETCH emp_cv INTO emp_row;
END fetch_emp_data;
END emp_data;
/

パッケージ・プロシージャを起動します。

DECLARE
emp_curs     emp_data.emp_val_cv_type;
dept_number  EMPLOYEES.DEPARTMENT_ID%TYPE;
emp_row      EMPLOYEES%ROWTYPE;

BEGIN
dept_number := 20;

-- Open cursor, using variable:

emp_data.open_emp_cv(emp_curs, dept_number);

-- Fetch and display data:

LOOP
emp_data.fetch_emp_data(emp_curs, emp_row);
EXIT WHEN emp_curs%NOTFOUND;
DBMS_OUTPUT.PUT(emp_row.LAST_NAME || '  ');
DBMS_OUTPUT.PUT_LINE(emp_row.SALARY);
END LOOP;
END;
/

例6-13では、プロシージャは、パラメータdiscrimの値に応じてEMPLOYEES表またはDEPARTMENTS表のカーソル変数をオープンします。無名ブロックは、プロシージャを起動してEMPLOYEES表のカーソル変数をオープンしますが、DEPARTMENTS表からフェッチするため、事前定義の例外ROWTYPE_MISMATCHが発生します。

例6-13 識別子を使用したカーソル変数

CREATE OR REPLACE PACKAGE emp_dept_data AS
TYPE cv_type IS REF CURSOR;

PROCEDURE open_cv (
cv       IN OUT cv_type,
discrim  IN     POSITIVE
);
END emp_dept_data;
/

CREATE OR REPLACE PACKAGE BODY emp_dept_data AS
PROCEDURE open_cv (
cv      IN OUT cv_type,
discrim IN     POSITIVE) IS
BEGIN
IF discrim = 1 THEN
OPEN cv FOR
SELECT * FROM EMPLOYEES ORDER BY employee_id;
ELSIF discrim = 2 THEN
OPEN cv FOR
SELECT * FROM DEPARTMENTS ORDER BY department_id;
END IF;
END open_cv;
END emp_dept_data;
/

無名ブロックからプロシージャopen_cvを起動します。

DECLARE
emp_rec   EMPLOYEES%ROWTYPE;
dept_rec  DEPARTMENTS%ROWTYPE;
cv        Emp_dept_data.CV_TYPE;
BEGIN
emp_dept_data.open_cv(cv, 1);  -- Open cv for EMPLOYEES fetch.
FETCH cv INTO dept_rec;        -- Fetch from DEPARTMENTS.
DBMS_OUTPUT.PUT(dept_rec.DEPARTMENT_ID);
DBMS_OUTPUT.PUT_LINE('  ' || dept_rec.LOCATION_ID);
EXCEPTION
WHEN ROWTYPE_MISMATCH THEN
BEGIN
DBMS_OUTPUT.PUT_LINE
('Row type mismatch, fetching EMPLOYEES data ...');
FETCH cv INTO emp_rec;
DBMS_OUTPUT.PUT(emp_rec.DEPARTMENT_ID);
DBMS_OUTPUT.PUT_LINE('  ' || emp_rec.LAST_NAME);
END;
END;
/

結果:

Row type mismatch, fetching EMPLOYEES data ...
90  King

PL/SQLコンパイル時のエラー処理

コンパイル時のエラーをリスト表示するには、静的データ・ディクショナリ・ビュー*_ERRORSを問い合せます。これらのビューからは、元のソース・コードを取得できます。サブプログラムのコンパイルに関するエラー・メッセージは、サブプログラムを置き換えると更新され、サブプログラムを削除すると削除されます。

SQL*Plusによって、コンパイル時のエラーに関する警告メッセージが発行されます。詳細を確認するには、SHOW ERRORSコマンドを使用する必要があります。

注意:
長い行を出力するには、SHOW ERRORS文を発行する前にSET LINESIZE文を使用してください。通常、次のように値を132に指定することをお薦めします。次に例を示します。

SET LINESIZE 132

例6-14にはコンパイル時のエラーが2つあり、WHERはWHEREの誤りで、ENDの後にはセミコロンが必要です。SHOW ERRORSを使用すると、各エラーの行、列および説明が表示されます。

例6-14 コンパイル時のエラー

CREATE OR REPLACE PROCEDURE fire_emp (
emp_id NUMBER
) AS
BEGIN
DELETE FROM EMPLOYEES
WHER EMPLOYEE_ID = Emp_id;
END
/

結果:

Warning: Procedure created with compilation errors.

コマンド:

SHOW ERRORS;

結果:

Errors for PROCEDURE FIRE_EMP:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/3      PL/SQL: SQL Statement ignored
6/8    PL/SQL: ORA-00933: SQL command not properly ended
7/3    PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
; <an identifier> <a double-quoted delimited-identifier>
current delete exists prior <a single-quoted SQL string>
The symbol ";" was substituted for "end-of-file" to continue.

参照:

- 静的データ・ディクショナリ・ビュー*_SOURCEの詳細は、『Oracle Databaseリファレンス』を参照してください。

- SHOW ERRORS文の詳細は、『SQL*Plusユーザーズ・ガイドおよびリファレンス』を参照してください。

PL/SQLのランタイム・エラー処理

Oracle Databaseでは、PL/SQLコード内のユーザー定義エラーを処理できます。ユーザー定義エラーの番号およびメッセージがクライアント・アプリケーションに戻されて、そこで処理されます。

ユーザー定義エラーのメッセージは、RAISE_APPLICATION_ERRORプロシージャを使用して戻されます。次に例を示します。

RAISE_APPLICATION_ERROR(error_number, 'text', keep_error_stack)

このプロシージャはサブプログラムの実行を停止し、サブプログラムによるすべての影響をロールバックして、ユーザー定義エラー番号およびメッセージを戻します(例外ハンドラによってエラーが検出されない場合)。error_numberは、-20000から-20999の範囲内にある必要があります。

エラー番号-20000は、ユーザーに情報を伝えることが重要ですが、一意のエラー番号は必要とされないメッセージの一般的な番号として使用します。テキストは、2KB以下の文字式である必要があります(それより長いメッセージは無視されます)。このエラーをスタック上のエラーに追加するには、Keep_error_stackをTRUEに設定し、既存のエラーに上書きするには、FALSE(デフォルト)に設定します。

注意:
DBMS_OUTPUT、DBMS_DESCRIBE、DBMS_ALERTなど、Oracle Databaseのパッケージの中には、-20000から-20005の範囲のアプリケーション・エラー番号を使用するものがあります。詳細は、これらのパッケージの説明を参照してください。

RAISE_APPLICATION_ERRORプロシージャは、例外ハンドラまたは論理PL/SQLコードによく使用されます。たとえば、次の例外ハンドラは、ユーザー定義エラー・メッセージに関係する文字列を選択した後、RAISE_APPLICATION_ERRORプロシージャを起動します。

...
WHEN NO_DATA_FOUND THEN
SELECT Error_string INTO Message
FROM Error_table,
V$NLS_PARAMETERS V
WHERE Error_number = -20101 AND Lang = v.value AND
v.parameter = "NLS_LANGUAGE";
Raise_application_error(-20101, Message);
...

内容は次のとおりです。

- 例外および例外処理の宣言

- 未処理例外

- 分散問合せでのエラー処理

- リモート・サブプログラムでのエラー処理

例外および例外処理の宣言

ユーザー定義例外は、そのアプリケーションに固有のエラーを処理するためにPL/SQLブロック内で明示的に定義され、呼び出されます。例外が発生すると、通常のPL/SQLブロックの実行は停止し、例外ハンドラが起動されます。この例外ハンドラによって内部例外またはユーザー定義例外が処理されます。

アプリケーション・コードを使用すると、IF文により特に注意が必要な条件をチェックできます。エラー条件がある場合、次の2つのオプションのどちらかを選択できます。

- 適切な例外を指示するRAISE文を入力します。RAISE文によってサブプログラムの実行は中断され、例外ハンドラがあれば制御が渡されます。

- RAISE_APPLICATION_ERRORプロシージャを起動して、ユーザー定義エラーの番号およびメッセージを戻します。

例外ハンドラは、ユーザー定義エラー・メッセージを処理するために定義することもできます。たとえば、図6-1では、次を示しています。

- サブプログラム内の例外およびその例外に対応する例外ハンドラ

- エラー(預金がないのに振込みを行うなど)をチェックし、ユーザー定義エラーの番号およびメッセージをトリガーに入力する条件文

- ユーザー定義エラー番号を起動側の環境(この場合はサブプログラム)に戻す方法、およびアプリケーションでユーザー定義エラーの番号に対応する例外を定義する方法

ユーザー定義例外は、サブプログラム本体またはパッケージ本体で宣言するか(プライベート例外)、パッケージ仕様部で宣言します(パブリック例外)。例外ハンドラは、サブプログラム本体(スタンドアロンまたはパッケージ)に定義します。

図6-1 例外およびユーザー定義エラー

未処理例外

データベースのPL/SQLユニットでは、適切な例外ハンドラによって検出されない未処理のユーザー・エラー条件または内部エラー条件が原因で、プログラム・ユニットの暗黙的なロールバックが発生します。プログラム・ユニットで未処理例外がある場所の前にCOMMIT文が含まれている場合、そのプログラム・ユニットの暗黙的なロールバックは直前のCOMMITまで実行されます。

さらに、データベースに格納されたPL/SQLユニットの未処理例外は、ユニットを起動するクライアント側のアプリケーションに渡されます。このアプリケーションでは、その例外はデータベースにSQL文として送られるため、アプリケーション・プログラム・ユニットの起動のみがロールバックされます(アプリケーション・プログラム・ユニット全体ではありません)。

データベースのPL/SQLユニット内の未処理例外がデータベース・アプリケーションに戻される場合は、例外を処理するためにデータベースのPL/SQLコードを変更する必要があります。アプリケーションで、データベース・プログラム・ユニットを起動したときに未処理例外を検出し、それらのエラーを処理できます。

分散問合せでのエラー処理

分散問合せは、トリガーまたはストアド・サブプログラムを使用して作成できます。この分散問合せは、ローカルのOracle Databaseインスタンスによって、対応する数のリモート問合せに分解されてリモート・ノードに送られます。リモート・ノードはその問合せを実行し、ローカル・ノードにその結果を送ります。その後、ローカル・ノードは必要な後処理を行い、ユーザーまたはアプリケーションに結果を戻します。

たとえば、制約違反のために分散問合せ文の一部でエラーが発生すると、Oracle DatabaseはORA-02055を戻します。後続する文またはサブプログラムの起動は、ロールバック、またはセーブポイントまでのロールバックが入力されるまで、ORA-02067を戻します。

分散更新の一部でエラーが発生したことを示すエラー・メッセージがチェックされるように、アプリケーションを設計してください。エラーを検出した場合、アプリケーションが処理を継続する前に、トランザクション全体をロールバック(またはセーブポイントまでロールバック)してください。

リモート・サブプログラムでのエラー処理

サブプログラムがローカルまたはリモートで実行される場合、次の例外が発生する可能性があります。

- キーワードEXCEPTIONを使用した宣言が必要なPL/SQLのユーザー定義例外

- NO_DATA_FOUNDなどのPL/SQL事前定義例外

- ORA-00900などのSQLエラー

- RAISE_APPLICATION_ERRORプロシージャを使用して生成されるアプリケーション例外

ローカル・サブプログラムを使用する場合、これらのすべてのメッセージは次のような例外ハンドラを作成することによって検出できます。

EXCEPTION
WHEN ZERO_DIVIDE THEN
/* Handle the exception */

WHEN句の例外名は必須です。RAISE_APPLICATION_ERRORで生成される例外のように、発生した例外に名前がない場合は、プラグマPRAGMA_EXCEPTION_INITを使用して名前を割り当てることができます。次に例を示します。

DECLARE
...
Null_salary EXCEPTION;
PRAGMA EXCEPTION_INIT(Null_salary, -20101);
BEGIN
...
RAISE_APPLICATION_ERROR(-20101, 'salary is missing');
...
EXCEPTION
WHEN Null_salary THEN
...

リモート・サブプログラムを起動する場合、例外はローカル例外ハンドラを作成することでも処理されます。リモート・サブプログラムは、ローカルの起動側サブプログラムにエラー番号を戻す必要があり、その後、ローカル・サブプログラムは、前述の例に示したように、例外を処理します。PL/SQLのユーザー定義例外は、常にローカル・サブプログラムにORA-06510を戻すため、これらの例外は処理できません。その他のリモート例外はすべて、ローカル例外と同じ方法で処理できます。

ストアド・サブプログラムのデバッグ

ストアド・サブプログラムのコンパイルにはコードの構文エラーの修正が含まれます。サブプログラムが正常に実行され、エラーが修正されていることを確認するには、追加のデバッグを行う必要があります。次のようなデバッグが考えられます。

- 出力文を追加して、実行処理の検証およびサブプログラム内の任意の点でのデータ値のチェックをする。

- 別のデバッガを実行して、実行を詳細に分析する。

内容は次のとおりです。

- PL/Scope

- PL/SQL階層プロファイラ

- Oracle JDeveloper

- DBMS_OUTPUTパッケージ

- PL/SQLストアド・サブプログラムおよびJavaストアド・サブプログラムのデバッグ権限

- 低レベルのデバッグ・コードの書込み

- DBMS_DEBUG_JDWPパッケージ

- DBMS_DEBUGパッケージ

PL/Scope

PL/Scopeはコンパイラ駆動方式のツールであり、PL/SQLソース・コードからユーザー定義の識別子に関するデータを収集して構成します。PL/Scopeはコンパイラ駆動方式のツールであるため、直接使用するのではなく、対話型の開発環境(SQL DeveloperやJDeveloperなど)を介して使用します。

PL/Scopeによって、強力で効率的なPL/Scopeソース・コード・ブラウザの開発が可能になります。このブラウザは、ソース・コードの参照および理解に費やされる時間を最小限にすることによって、PL/SQL開発者の生産性を向上させます。

PL/Scopeの詳細は、第7章「PL/Scopeの使用」を参照してください。

PL/SQL階層プロファイラ

PL/SQL階層プロファイラは、サブプログラム・コール別に編成されたPL/SQLプログラムの動的実行プロファイルをレポートします。SQL実行時間およびPL/SQL実行時間が個別に説明されます。動的実行プロファイルにおけるサブプログラム・レベルの各サマリーには、サブプログラムへのコール数、サブプログラム自体に要した時間、サブプログラムのサブツリー(つまり依存サブプログラム)に要した時間、詳細な親子情報などが表示されます。

生成されたHTMLレポートは任意のブラウザで参照できます。ブラウザのナビゲーション機能と厳選したリンクを組み合せた効率的な手段により、大規模なアプリケーションのパフォーマンスを分析し、アプリケーションのパフォーマンスを向上させ、開発コストを削減できます。

PL/SQL階層プロファイラの詳細は、第8章「PL/SQL階層プロファイラの使用」を参照してください。

Oracle JDeveloper

Oracle JDeveloperの最新のリリースには、PL/SQL、Javaおよびマルチ言語プログラムをデバッグする広範な機能が含まれています。各種Oracle製品の一部としてOracle JDeveloperを取得できます。通常、最新のリリースは次のURLからダウンロードできます。

http://www.oracle.com/technetwork/developer-tools/jdev/downloads/index.html

DBMS_OUTPUTパッケージ

OracleパッケージDBMS_OUTPUTを使用すると、ストアド・サブプログラムおよびトリガーもデバッグできます。コードにはPUT文およびPUT_LINE文を入れて、変数および式の値を端末に出力します。

PL/SQLストアド・サブプログラムおよびJavaストアド・サブプログラムのデバッグ権限

Oracle Database 10gから、データベース内で実行されるPL/SQLおよびJavaコードのデバッグに新しい権限モデルが適用されるようになりました。このモデルは、Oracle JDeveloper、Oracle Developer、または各種サード・パーティのPL/SQLやJavaの開発環境のいずれを使用していても適用され、DBMS_DEBUG APIおよびDBMS_DEBUG_JDWP APIの両方に影響します。

デバッガに接続するセッションでは、DEBUG CONNECT SESSIONシステム権限を所有するユーザーが接続操作を実行する必要があります。接続コールに関係するDRサブプログラムの所有者であるユーザーも、この操作を実行できます。

デバッガがセッションに接続されると、セッション・ログイン・ユーザーおよび有効なセッションレベルのロールが、このデバッグ用の接続の権限環境として決定されます。デバッグに必要なすべてのDEBUG権限またはEXECUTE権限を、このユーザーとロールの組合せに付与する必要があります。

- Javaのパブリック変数またはPL/SQLのパッケージ仕様部内に宣言された変数を表示および変更できるようにするために、関連するコードのEXECUTE権限またはDEBUG権限をデバッグ用の接続に付与する必要があります。

- プライベート変数またはブレークポイントを表示および変更し、コードを1行ずつ実行できるようにするために、関連するコードのDEBUG権限を付与する必要があります。

注意:
DEBUG権限を付与することにより、デバッグ対象のサブプログラムが実行するようにコーディングされている処理をデバッグ・セッションで実行することが可能になります。

このような権限要件に加えて、コードの各行で停止する機能とデバッガからの変数へのアクセスを実行できるのは、生成されたデバッグ情報とともにコンパイルされているコード内のみという制限があります。ALTER PACKAGEなどの文でPL/SQLコンパイル・パラメータPLSQL_DEBUGおよびDEBUGキーワードを使用し、PL/SQLコンパイラで結果にデバッグ情報を含めるかどうかを制御できます。デバッグ情報を含めない場合、変数にはアクセスできず、コードの各行でステップ実行やブレークポイントを指定することもできません。PL/SQLコンパイラでは、PL/SQLのwrapユーティリティにより非表示になっているコードに対しては、デバッグ情報は生成されません。

参照:
wrapユーティリティの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

DEBUG ANY PROCEDUREシステム権限の効力は、データベース内のすべてのオブジェクトにDEBUG権限を付与したときの効力と同じです。O7_DICTIONARY_ACCESSIBILITYパラメータの値がTRUEである場合は、SYSが所有しているオブジェクトにも付与します。

デバッグ・ロール・メカニズムを使用すると、セッションでは通常使用できない、デバッグ用の権限を保持できます。デバッグ・ロールおよび必要な関連パスワードの指定方法の詳細は、マニュアルでDBMS_DEBUGパッケージおよびDBMS_DEBUG_JDWPパッケージについての説明を参照してください。

JAVADEBUGPRIVロールは、DEBUG CONNECT SESSION権限およびDEBUG ANY PROCEDURE権限を保持します。必要な場合にのみ、これらの権限をこのロールに付与してください。

注意:
SYSが所有するオブジェクトにDEBUG ANY PROCEDURE権限またはDEBUG権限を付与することは、すべての権限をデータベースに付与することを意味します。

低レベルのデバッグ・コードの書込み

デバッガの一部のコードを書き込む場合は、DBMS_DEBUG_JDWPやDBMS_DEBUGなどのパッケージを使用する必要があります。

DBMS_DEBUG_JDWPパッケージ

Oracle Database 9gリリース2から提供されているDBMS_DEBUG_JDWPパッケージは、将来DBMS_DEBUGパッケージと置き換わるマルチ言語デバッグ用のフレームワークを提供します。PL/SQLとJavaの組合せのプログラムには特に有効です。

DBMS_DEBUGパッケージ

Oracle8iから提供されているDBMS_DEBUGパッケージでは、サーバー側のデバッガが実装されており、サーバー側のPL/SQLユニットをデバッグする方法を提供します。Oracle Procedure Builderやその他の様々なサード・パーティ・ベンダーが提供するソリューションなどデバッガのいくつかでは、このAPIが使用されています。

参照:

- 『Oracle Procedure Builder Developer's Guide』

- DBMS_DEBUGパッケージおよび関連する権限の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- DBMS_OUTPUTパッケージおよび関連する権限の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- DBMS_DEBUG_JDWPパッケージの使用方法の詳細は、Oracle JDeveloperのドキュメントを参照してください。

- 権限の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- http://www.oracle.com/technetwork/database/features/plsql/index.html

ストアド・サブプログラムの起動

ストアドPL/SQLサブプログラムは、次のように様々な環境から起動できます。次に例を示します。

- Oracle Databaseのツール製品を使用した対話形式による起動

- 別のサブプログラム本体からの起動

- アプリケーション(SQL*Formsやプリコンパイラなど)の内部からの起動

- トリガー本体からの起動

ストアドPL/SQLファンクション(プロシージャではない)は、SQL文から起動することもできます。詳細は、「SQL文からのストアドPL/SQLファンクションの起動」を参照してください。

内容は次のとおりです。

- サブプログラムの起動に必要な権限

- Oracleツールを使用した対話形式によるサブプログラムの起動

- 別のサブプログラムからのサブプログラムの起動

- 3GLアプリケーションからのサブプログラムの起動

参照:

- パラメータの受渡しも含めたPL/SQLサブプログラムの起動の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- トリガー本体のコーディングの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

サブプログラムの起動に必要な権限

次のようなサブプログラムを起動する場合、権限は必要ありません。

- 所有しているスタンドアロン・サブプログラム

- 所有しているパッケージ内のサブプログラム

- パブリック・スタンドアロン・サブプログラム

- パブリック・パッケージ内のサブプログラム

別のユーザーが所有するスタンドアロン・サブプログラムまたはパッケージ・サブプログラムを起動する場合は、次のようになります。

- スタンドアロン・サブプログラムまたはサブプログラムを含むパッケージのEXECUTE権限、またはEXECUTE ANY PROCEDUREシステム権限が必要です。

- リモート・サブプログラムを実行する場合は、EXECUTE権限またはEXECUTE ANY PROCEDUREシステム権限が、ロールを介してではなく直接付与されている必要があります。

- 起動の際に所有者の名前を指定する必要があります。次に例を示します。

EXECUTE jdoe.Fire_emp (1043);
EXECUTE jdoe.Hire_fire.Fire_emp (1043);

- サブプログラムが定義者権限(DR)サブプログラムである場合、このサブプログラムはその所有者の権限を使用して実行されます。所有者は、参照オブジェクトに必要なオブジェクト権限をすべて所有している必要があります。

- サブプログラムが実行者権限(IR)サブプログラムである場合、このサブプログラムはユーザーの権限を使用して実行されます。すべての参照オブジェクト、つまり自スキーマ内で変換される外部参照を介してサブプログラムがアクセスするオブジェクトに対して、必要なオブジェクト権限をすべて所有している必要があります。これらの権限は直接、またはロールを介して保持できます。IRサブプログラムが直接、または間接的にDRサブプログラムから起動されないかぎり、ロールは有効です。

Oracleツールを使用した対話形式によるサブプログラムの起動

サブプログラムは、SQL*Plusなど、Oracle Databaseのツール製品から対話形式で起動できます。例6-15では、SQL*Plusを使用してプロシージャを作成し、2つの方法で起動します。

例6-15 SQL*Plusを使用した対話形式によるサブプログラムの起動

CREATE OR REPLACE PROCEDURE salary_raise (
employee  EMPLOYEES.EMPLOYEE_ID%TYPE,
increase  EMPLOYEES.SALARY%TYPE
)
IS
BEGIN
UPDATE EMPLOYEES
SET SALARY = SALARY + increase
WHERE EMPLOYEE_ID = employee;
END;
/

PL/SQLブロックの内部からプロシージャを起動します。

BEGIN
salary_raise(205, 200);
END;
/

結果:

PL/SQL procedure successfully completed.

EXECUTE文でプロシージャを起動します。

EXECUTE salary_raise(205, 200);

結果:

PL/SQL procedure successfully completed.

一部の対話形式ツールでは、セッション中に使用できるセッション変数を作成することができます。例6-16では、SQL*Plusを使用してセッション変数の作成、使用および出力を行います。

例6-16 SQL*Plusを使用したセッション変数の作成と使用

-- Create function for later use:

CREATE OR REPLACE FUNCTION get_job_id (
emp_id  EMPLOYEES.EMPLOYEE_ID%TYPE
) RETURN EMPLOYEES.JOB_ID%TYPE
IS
job_id  EMPLOYEES.JOB_ID%TYPE;
BEGIN
SELECT JOB_ID INTO job_id
FROM EMPLOYEES
WHERE EMPLOYEE_ID = emp_id;

RETURN job_id;
END;
/
-- Create session variable:

VARIABLE job VARCHAR2(10);

-- Run function and store returned value in session variable:

EXECUTE :job := get_job_id(204);

PL/SQL procedure successfully completed.

SQL*Plusコマンド:

PRINT job;

結果:

JOB
--------------------------------
PR_REP

参照:

- EXECUTEコマンドの詳細は、『SQL*Plusユーザーズ・ガイドおよびリファレンス』を参照してください。

- 開発ツールを使用して同様の操作を実行する詳細は、ご使用のツール製品のドキュメントを参照してください。

別のサブプログラムからのサブプログラムの起動

ストアド・サブプログラムは、別のサブプログラムやトリガーから起動できます。例6-17では、プロシージャprint_mgr_nameがプロシージャprint_emp_nameを起動します。

サブプログラムの再帰的な起動が可能です(つまり、サブプログラムがサブプログラム自体を起動できます)。

例6-17 別のサブプログラムからのサブプログラムの起動

-- Create procedure that takes employee's ID and prints employee's name:

CREATE OR REPLACE PROCEDURE print_emp_name (
emp_id  EMPLOYEES.EMPLOYEE_ID%TYPE
)
IS
fname  EMPLOYEES.FIRST_NAME%TYPE;
lname  EMPLOYEES.LAST_NAME%TYPE;
BEGIN
SELECT FIRST_NAME, LAST_NAME
INTO fname, lname
FROM EMPLOYEES
WHERE EMPLOYEE_ID = emp_id;

DBMS_OUTPUT.PUT_LINE (
'Employee #' || emp_id || ':  ' || fname || ' ' || lname
);
END;
/

-- Create procedure that takes employee's ID and prints manager's name:

CREATE OR REPLACE PROCEDURE print_mgr_name (
emp_id  EMPLOYEES.EMPLOYEE_ID%TYPE
)
IS
mgr_id  EMPLOYEES.MANAGER_ID%TYPE;
BEGIN
SELECT MANAGER_ID
INTO mgr_id
FROM EMPLOYEES
WHERE EMPLOYEE_ID = emp_id;

DBMS_OUTPUT.PUT_LINE (
'Manager of employee #' || emp_id || ' is:  '
);

print_emp_name(mgr_id);
END;
/

プロシージャを起動します。

BEGIN
print_emp_name(200);
print_mgr_name(200);
END;
/

結果:

Employee #200:  Jennifer Whalen
Manager of employee #200 is:
Employee #101:  Neena Kochhar

3GLアプリケーションからのサブプログラムの起動

3GLデータベース・アプリケーション(プリコンパイラまたはOCIアプリケーションなど)では、コード内からサブプログラムを起動することができます。

プロシージャFire_emp1が次のように作成されているとします。

CREATE OR REPLACE PROCEDURE fire_emp1 (Emp_id NUMBER) AS
BEGIN
DELETE FROM Emp_tab WHERE Empno = Emp_id;
END;

プリコンパイラ・アプリケーションからサブプログラムを実行するには、EXECコール・インタフェースを使用する必要があります。たとえば、次の文は、プリコンパイラ・アプリケーションのコード内でFire_empプロシージャを起動します。

EXEC SQL EXECUTE
BEGIN
Fire_emp1(:Empnum);
END;
END-EXEC;

参照:
3GLアプリケーション内部からのPL/SQLサブプログラムの起動方法の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

リモート・サブプログラムの起動

リモート・サブプログラム(スタンドアロン・サブプログラムおよびパッケージ・サブプログラム)は、そのリモート・サブプログラム名、データベース・リンクおよびリモート・サブプログラムのパラメータを指定することによって、サブプログラム、OCIアプリケーションまたはプリコンパイラの中から起動できます。

たとえば、次のSQL*Plus文はプロシージャfire_emp1を起動します。このプロシージャはデータベース内にあり、boston_serverという名前のローカル・データベース・リンクによって参照されています。

EXECUTE fire_emp1@boston_server(1043);

デフォルト値がある場合でも、すべてのリモート・サブプログラムのパラメータに対して値を指定する必要があります。リモート・パッケージ変数および定数にはアクセスできません。

注意:

- リモート・サブプログラムの起動では、実行時バインディングが使用されます。接続するユーザー・アカウントは、データベース・リンクに依存します。(ストアド・サブプログラムではコンパイル時バインディングが使用されます。)

- ローカル・サブプログラムがリモート・サブプログラムを起動する場合、ローカル・サブプログラムの実行中にタイムスタンプの不一致が検出されると、リモート・サブプログラムは実行されず、ローカル・サブプログラムが無効になります。

内容は次のとおりです。

- リモート・サブプログラムのシノニム

- トランザクションのコミット

参照:
リモート・サブプログラム起動時の例外処理の詳細は、「リモート・サブプログラムでのエラー処理」を参照してください。

リモート・サブプログラムのシノニム

リモート・サブプログラム名とデータベース・リンクのシノニムを作成し、シノニムを使用してサブプログラムを起動することができます。次に例を示します。

CREATE SYNONYM synonym1 for fire_emp1@boston_server;

EXECUTE synonym1(1043);
/

シノニムによって、サブプログラム、OCIアプリケーションまたはプリコンパイラのみでなく、SQL*Formsアプリケーションなど、Oracle Databaseのツール製品のアプリケーションからリモート・サブプログラムを起動できるようになります。

シノニムによってデータの独立性と場所の透過性の両方が実現されます。シノニムを使用すると、オブジェクトを所有するユーザーやオブジェクトを格納するデータベースに関係なく、アプリケーションを変更せずに使用できます。ただし、シノニムはデータベース・オブジェクトに対する権限の代用とはなりません。ユーザーがシノニムを使用するためには、そのユーザーが適切な権限を付与されている必要があります。

パッケージ内に定義されているサブプログラムは個別のオブジェクトではないため(パッケージはオブジェクトです)、パッケージ内の個々のサブプログラムのシノニムは作成できません。

シノニムを使用しない場合は、リモート・サブプログラムを起動するローカル・サブプログラムを作成することもできます。次に例を示します。

CREATE OR REPLACE PROCEDURE local_procedure
(arg IN NUMBER)
AS
BEGIN
fire_emp1@boston_server(arg);
END;
/
DECLARE
arg NUMBER;
BEGIN
local_procedure(arg);
END;
/

参照:

- シノニムの詳細は、『Oracle Database概要』を参照してください。

- CREATE SYNONYM文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

トランザクションのコミット

リモートのストアド・サブプログラムの起動は、更新処理を前提とするため、このような参照でも、常に2フェーズ・コミットのトランザクションが必要です(リモート・サブプログラムが読取り専用の場合を含む)。さらに、リモート・サブプログラムの起動を含むトランザクションをロールバックする場合、そのリモート・サブプログラムによって実行された処理も同時にロールバックされます。

リモートで起動されたサブプログラムでは通常、ローカル・サブプログラムと同じように、COMMIT、ROLLBACK、SAVEPOINTの各文を実行できます。ただし、次のように、アクションに少し違いがあります。

- トランザクションがOracle Database以外のデータベースによって開始された場合(XAアプリケーションなどの場合)、リモート・サブプログラムでこれらの操作はできません。

- これらの操作の1つを実行すると、リモート・サブプログラムは独自の分散トランザクションを開始できません。

- リモート・サブプログラムがその作業をコミットまたはロールバックしない場合、データベース・リンクがクローズした時点で暗黙的にコミットが実行されます。このとき、トランザクションは実行中とみなされるため、リモート・サブプログラムを起動できません。

分散トランザクションではデータは複数のデータベースで更新されます。異なるデータベースのデータにアクセスする複数のリモート更新を含むサブプログラムを使用できます。構文内の文はリモート・データベースに送信され、構文の実行はユニット単位で正常終了または異常終了します。分散更新の一部がエラーとなり、一部が正常終了した場合、処理を続けるには(トランザクション全体またはセーブポイントまでの)ロールバックが必要です。分散更新を実行するサブプログラムを作成する場合は、この点を考慮する必要があります。

SQL文からのストアドPL/SQLファンクションの起動

注意:
SQLは命令型(または手続き型)言語ではなく宣言型言語であるため、ファンクションが命令型言語のPL/SQLで記述されていても、SQL文から起動されるファンクションが何回実行されるかはわかりません。
アプリケーションでファンクションが特定の回数実行されることが必要な場合には、SQL文からファンクションを起動しないでください。かわりにカーソルを使用します。

たとえば、選択した行ごとにファンクションをコールすることがアプリケーションで必要な場合は、カーソルをオープンして、カーソルから行を選択し、各行に対してファンクションをコールします。このようにすると、ファンクションをコールする回数が、カーソルからフェッチされる行数と同じになります。

ストアドPL/SQLファンクションをSQL文から起動するには、そのファンクションをスキーマ・レベルまたはパッケージ仕様部で宣言する必要があります。

ストアドPL/SQLファンクションを起動できるSQL文は次のとおりです。

- INSERT

- UPDATE

- DELETE

- SELECT

- CALL
(CALLは、ストアドPL/SQLプロシージャを起動することもできます。)

SQLからPL/SQLサブプログラムを起動するには、その所有者であるか、またはそのサブプログラムに対するEXECUTE権限を保持している必要があります。PL/SQLファンクションを使用して定義されているビューから選択するには、そのビューに対するSELECT権限が必要です。そのビューからの選択には、別のEXECUTE権限は必要ありません。

パラメータを渡す方法など、サブプログラムを起動する方法の概要は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

内容は次のとおりです。

- SQL文からストアドPL/SQLサブプログラムを起動する理由

- SQL文の中でPL/SQLファンクションを使用できる箇所

- SQL式の中でPL/SQLファンクションを使用できる条件

- 副作用の制御

SQL文からストアドPL/SQLサブプログラムを起動する理由

SQL文からPL/SQLサブプログラムを起動すると、次のような利点があります。

- SQLの拡張によって、ユーザーの生産性が向上します。
実行する内容がSQL文のみで表現するには複雑すぎたり、非常に扱いにくかったり、不可能な場合に、SQL文の表現機能が強化されます。

- 問合せの効率を向上します。
問合せのWHERE句にファンクションを指定すると、条件を使用してデータをフィルタできます。ファンクションを使用できない場合は、アプリケーションで評価する必要があります。

- 特殊なデータ型(緯度、経度、温度など)を表すための文字列を操作できます。

- パラレル問合せを実行できます。
問合せがパラレル化されると、PL/SQLサブプログラム内のSQL文も(パラレル問合せオプションを使用して)パラレルに実行できます。

SQL文の中でPL/SQLファンクションを使用できる箇所

SQL文では、PL/SQLファンクションや式を使用できる任意の箇所でPL/SQLファンクションを使用できます。次に例を示します。

- SELECT文の選択リスト

- WHERE句またはHAVING句の条件

- CONNECT BY句、START WITH句、ORDER BY句またはGROUP BY句

- INSERT文のVALUES句

- UPDATE文のSET句

SELECT文では、次のかわりにPL/SQL表ファンクション(複数の行をまとめて戻す)を使用できます。

- SELECTリストの列名

- FROM句の表名

不変の定義が必要な次のようなコンテキストには、PL/SQLファンクションは使用できません。

- CREATE文またはALTER TABLE文のCHECK制約句

- 列に対するデフォルト値の指定

SQL式の中でPL/SQLファンクションを使用できる条件

PL/SQLファンクションをSQL式から起動するには、そのファンクションが次の要件を満たしている必要があります。

- 列(グループ)ファンクションではなく、行ファンクションであること。つまり、列全体をその引数としてとることはできません。

- 仮パラメータが、OUTパラメータやIN OUTパラメータではなく、INパラメータであること。

- 仮パラメータおよび戻り値(存在する場合)のデータ型が、PL/SQLデータ型(BOOLEAN、RECORD、TABLEなど)ではなく、Oracleの組込みデータ型(CHAR、DATE、NUMBERなど)であること。
ただし、このルールの例外として、対応する実パラメータが暗黙的に仮パラメータのデータ型に変換される場合には、その仮パラメータはPL/SQLデータ型を持つことができます(例6-19を参照してください)。

例6-18のファンクションは、これらの要件を満たしています。

例6-18 SQL式でのPL/SQLファンクション(規則に従った場合)

DROP TABLE payroll;  -- in case it exists
CREATE TABLE payroll (
srate  NUMBER,
orate  NUMBER,
acctno NUMBER
);

CREATE OR REPLACE FUNCTION gross_pay (
emp_id  IN NUMBER,
st_hrs  IN NUMBER := 40,
ot_hrs  IN NUMBER := 0
) RETURN NUMBER
IS
st_rate  NUMBER;
ot_rate  NUMBER;
BEGIN
SELECT srate, orate
INTO st_rate, ot_rate
FROM payroll
WHERE acctno = emp_id;

RETURN st_hrs * st_rate + ot_hrs * ot_rate;
END gross_pay;
/

例6-19では、SQL文CALLによりPL/SQLファンクションf1が起動され、このファンクションの仮パラメータと戻り値のデータ型はPL/SQLデータ型PLS_INTEGERです。実パラメータ2は暗黙的にデータ型PLS_INTEGERへ変換されるため、このCALL文は正常に実行されます。実パラメータの値がPLS_INTEGERの範囲外であれば、このCALLは正常には実行されません。

例6-19 SQL式でのPL/SQLファンクション(規則への例外がある場合)

CREATE OR REPLACE FUNCTION f1 (
b IN PLS_INTEGER
) RETURN PLS_INTEGER
IS
BEGIN
RETURN
CASE
WHEN b > 0  THEN  1
WHEN b <= 0 THEN -1
ELSE NULL
END;
END f1;
/

VARIABLE x NUMBER;
CALL f1(b=>2) INTO :x;
PRINT x;

結果:

X
----------
1

副作用の制御

ストアド・サブプログラムの純粋度とは、データベース表またはパッケージ変数に対してそのサブプログラムが及ぼす副作用のことをいいます。副作用によって、問合せのパラレル処理が妨害されたり、処理順序に依存する(したがって、不確定な)結果が発生したり、ユーザー・セッションにまたがったパッケージ状態のメンテナンスが必要になります。ファンクションがSQL問合せまたはDML文から起動される場合は、様々な副作用は受け入れられません。

Oracle Database 8gリリース1より前のリリースでは、Oracle DatabaseはPL/SQLコンパイラを使用して、ストアド・サブプログラムまたはSQL文のコンパイル中に制限を施行していました。Oracle Database 8gリリース1からは、コンパイル時の制限は緩和され、実行中の制限も少なくなっています。

この変更によって、PL/SQL、JavaおよびCで作成されたストアド・サブプログラムが統一してサポートされ、プログラマには最大限の柔軟性が提供されています。

内容は次のとおりです。

- 制限事項

- ファンクションの宣言

- パラレル問合せおよびパラレルDML

- 下位互換性のためのPRAGMA RESTRICT_REFERENCES

制限事項

新しいSQL文が実行されるとき、実行中のSQL文の中にこのSQL文が論理的に埋め込まれているかどうかが確認されます。文がトリガーから、または実行中のSQL文から起動されたサブプログラムから実行されると、この確認が行われます。このような場合は、新しいSQL文が特定のコンテキスト内で安全かどうかを判断するために、さらに確認が行われます。

サブプログラムには次の制限が適用されます。

- 問合せ(SELECT文)またはDML文から起動されるサブプログラムは、現行のトランザクションの終了、セーブポイントの作成またはセーブポイントまでのロールバック、あるいはシステムまたはセッションの変更(ALTER)を実行できません。

- 問合せまたはパラレル化されたDML文から起動されるサブプログラムは、DML文を実行できないか、またはデータベースを変更できません。

- DML文から起動されるサブプログラムでは、そのDML文が変更中の表の読取りおよび変更はできません。

前述のすべての制限は、サブプログラムまたはトリガー内でSQL文が実行される方法にかかわらず適用されます。次に例を示します。

- 前述の制限は、PL/SQLから起動されるSQL文(サブプログラムまたはトリガーの本体に直接埋め込まれている文かどうかにかかわらず)が、ネイティブ動的メカニズム(EXECUTE IMMEDIATE)を使用して実行されるか、またはDBMS_SQLパッケージを使用して実行される場合、そのSQL文に適用されます。

- SQLJ構文を使用してJavaに埋め込まれている文、またはJDBCを使用して実行される文に適用されます。

- 外部C関数内からコールバック・コンテキストを使用してOCIで実行される文に適用されます。

新しいSQL文の実行が、実行中の文のコンテキストに論理的に埋め込まれていない場合は、前述の制約を回避できます。そのような回避方法の1つとして、PL/SQLの自律型トランザクションの使用があります(「自律型トランザクション」を参照)。外部C関数からOCIを使用するという別の回避方法もあり、この場合は、OCIExtProcContext引数から使用できるハンドルを使用せず、新しい接続を作成します。

ファンクションの宣言

キーワードDETERMINISTICおよびPARALLEL_ENABLEを、ファンクションを宣言する構文内で使用できます。この2つのキーワードは最適化ヒントで、問合せオプティマイザおよび他のソフトウェア・コンポーネントに対して、次のファンクションについての情報を提供します。

- 重複して起動する必要のないファンクション

- パラレル問合せまたはDML文の中で許可されているファンクション

ファンクション索引および特定のスナップショットやマテリアライズド・ビューで使用できるのは、DETERMINISTICを指定したファンクションのみです。

確定的な(DETERMINISTIC)ファンクションは、引数として渡される値のみに依存し、パッケージ変数またはデータベースの内容を参照したり変更することがなく、また、他の副作用を持ちません。このようなファンクションは、渡される引数値の組合せが同じであるかぎり、同じ戻り値を生成します。

the DETERMINISTICキーワードは、ファンクションの宣言の中で戻り値の型の後に入れます。次に例を示します。

CREATE OR REPLACE FUNCTION f1 (
p1 NUMBER
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
RETURN p1 * 2;
END;
/

このキーワードは、次の場所に挿入できます。

- CREATE FUNCTION文で定義されたファンクション

- CREATE PACKAGE文で宣言されたファンクション

- CREATE TYPE文のメソッド宣言

CREATE PACKAGE BODY文またはCREATE TYPE BODY文のファンクション本体またはメソッド本体には、キーワードは配置できません。

DETERMINISTICとマークされているファンクションの起動では、他にアクションを実行しなくても、パフォーマンスがある程度最適化されます。次の機能では、その機能で使用されるすべてのファンクションをDETERMINISTICとして宣言する必要があります。

- ファンクション索引で使用されるすべてのユーザー定義ファンクション。

- 高速リフレッシュ対象、またはENABLE QUERY REWRITEとしてマークされるマテリアライズド・ビューで使用されるファンクション

これらの機能では、ファンクションを起動するのではなく、事前に計算されている結果をできるかぎり使用しようとします。

プログラミングにおいては、次のDETERMINISTICカテゴリに属するファンクションを作成するのが適切です。

- WHERE句、ORDER BY句またはGROUP BY句の中で使用されるファンクション

- SQL型のMAPメソッドまたはORDERメソッドであるファンクション

- 結果セットに行を入れるかどうか、またはどこに入れるかを決定するファンクション

DETERMINISTICを作成する場合は、次の点に注意してください。

- ファンクションのアクションが本当に確定的であるかどうかをデータベースで認識することはできません。そのアクションが本当の意味で確定的ではないファンクションに対してDETERMINISTICキーワードが適用されると、そのファンクションが関係する問合せの結果は予測できません。

- DETERMINISTICファンクションのセマンティックを変更し、再コンパイルすると、既存のファンクション索引およびマテリアライズド・ビューにより、旧バージョンのファンクションの結果がレポートされます。このように、ファンクションのセマンティックを変更する場合、依存するファンクション索引およびマテリアライズド・ビューを手動で作成する必要があります。

参照:
CREATE FUNCTIONの制限事項は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

パラレル問合せおよびパラレルDML

Oracle Databaseのパラレル実行機能により、SQL文の実行作業が複数のプロセスにわたって分割されます。パラレルで実行されるSQL文から起動されるファンクションは、各プロセス内で実行される個別のコピーを持つことができ、それぞれのコピーは、そのプロセスによって処理される行のサブセットのためにのみ起動されます。

各プロセスには、そのプロセス専用のパッケージ変数のコピーがあります。パラレル実行が開始されると、これらは、ユーザーがシステムにログインするときのように、パッケージ仕様部および本体の情報に基づいて初期化され、パッケージ変数内の値は、元のログイン・セッションからはコピーされません。パッケージ変数に対する変更は、多数のセッション間で自動的に伝播したり、元のセッションに戻ることはありません。JavaのSTATICクラス属性は、同様に、各プロセス内で独立して初期化され変更されます。ファンクションでは、検出される様々な行の値をパッケージ(またはJavaのSTATIC)変数を使用して蓄積できるため、Oracle Databaseでは、すべてのユーザー定義ファンクションの実行をパラレル化しても安全であるとはいえません。

リリース8.1.5より前のOracle DatabaseのSELECT文では、パラレル問合せ最適化機能により、PRAGMA RESTRICT_REFERENCES宣言内にRNPSおよびWNPSとして記述されたファンクションは、パラレルで実行できました。CREATE FUNCTION文を使用して定義されているファンクションでは、ファンクションが十分に純粋であるかどうかを判断するために、暗黙的にコードが調べられており、パラレル実行は、これらのファンクションに対してプラグマを指定できない場合でも、発生する可能性がありました。

参照:
「下位互換性のためのPRAGMA RESTRICT_REFERENCES」

DML文の場合、8.1.5より前のリリースのOracle Databaseでは、ファンクションがPRAGMA RESTRICT_REFERENCES宣言内でRNDS、WNDS、RNPSおよびWNPSの4つすべてが記されているかどうかは、パラレル化最適化機能により調べられており、データベースまたはパッケージ変数のいずれかに対して読取りでもなく書込みでもないとマークされたファンクションは、パラレルで実行できました。ここでも、CREATE FUNCTION文を使用して定義されているファンクションでは、ファンクションが十分に純粋であるかどうかを判断するために、暗黙的にコードが調べられており、パラレル実行は、これらのファンクションに対してプラグマを指定できない場合でも、発生する可能性がありました。

Oracle Databaseリリース8.1.5以降でも、以前のバージョンでパラレル化可能として認識されていたファンクションは、引き続きパラレル化されます。コードをパラレル実行用として安全であるとマークする方法として、PARALLEL_ENABLEキーワードをお薦めします。このキーワードは、「ファンクションの宣言」で説明しているDETERMINISTICと構文的に類似しており、次に示すように、ファンクション宣言の戻り値型の後に指定します。

CREATE OR REPLACE FUNCTION f1 (
p1 NUMBER
) RETURN NUMBER PARALLEL_ENABLE
IS
BEGIN
RETURN p1 * 2;
END;
/

CREATE FUNCTIONを使用して定義されるPL/SQLファンクションは、そのファンクションがパッケージ変数の読取りも書込みを行わず、パッケージ変数の読取りまたは書込みを行う可能性のあるファンクションも起動しないことをシステムで判断できる場合は、パラレルで実行しても安全であると明示的に宣言しなくても、パラレルで実行できます。JavaメソッドまたはC関数は、プログラマがコール仕様にPARALLEL_ENABLEと明示的に指定するか、またはPRAGMA RESTRICT_REFERENCESを指定してファンクションが十分に純粋であることを示さないかぎり、システムはパラレルでの実行が安全であるとはみなしません。

パラレルDML文の一部としてパラレル実行されるファンクションに対しては、追加のランタイム制約が設けられています。このようなファンクションは、DML文の実行が許可されず、問合せ(SELECT)文の中で実行されるファンクションに対して適用される制約と同じ制約を受けます。

参照:
制限事項

下位互換性のためのPRAGMA RESTRICT_REFERENCES

8.1.5(Oracle8i)より前のOracle Databaseバージョンでは、プログラマはサブプログラムの純粋度レベルの宣言にPRAGMA RESTRICT_REFERENCESを使用していました。それ以降のバージョンでは、かわりにヒントPARALLEL_ENABLEおよびDETERMINISTICを使用して、サブプログラムの純粋度についてOracle Databaseと通信します。

コードからPRAGMA RESTRICT_REFERENCESを削除できます。ただし、このプラグマは次のような状況での下位互換性が残されています。

- 既存コードを編集してPRAGMA RESTRICT_REFERENCESをすべて削除することが不可能かつ非現実的な場合。
たとえば、サブプログラムS1がサブプログラムS2に依存し、S1からプラグマを削除しない場合、S1のコンパイルにS2のプラグマが必要になる場合があります。

- 既存コード中のPRAGMA RESTRICT_REFERENCESをヒントPARALLEL_ENABLEおよびDETERMINISTICに置き換えると、新しい依存コードのアクションに悪影響を与える可能性があります。(既存コードのアクションを保持するために、PRAGMA RESTRICT_REFERENCESを使用してください。)

既存のPL/SQLアプリケーションでは、既存コードとの統合を容易にするために、新しいファンクションに対してもプラグマを引き続き使用することができます。新しいアプリケーションではプラグマは使用しないでください。

PRAGMA RESTRICT_REFERENCESを使用する場合は、パッケージ本体ではなく、パッケージ仕様部に含めます。このプラグマは、サブプログラムの宣言の後に置く必要がありますが、直後に置く必要はありません。所定のサブプログラム宣言を参照できるプラグマは、1つのみです。

PRAGMA RESTRICT_REFERENCESをコーディングするには、次の構文を使用します。

PRAGMA RESTRICT_REFERENCES (
Function_name, WNDS [, WNPS] [, RNDS] [, RNPS] [, TRUST] );

パラメータは次のとおりです。

オプション

説明

WNDS

サブプログラムはデータベース状態を書き込みません(データベース表を変更しないということです)。

RNDS

サブプログラムはデータベース状態を読み込みません(データベース表を問い合せないということです)。

WNPS

サブプログラムはパッケージ状態を書き込みません(パッケージ変数の値を変更しないということです)。

RNPS

サブプログラムはパッケージ状態を読み込みません(パッケージ変数の値を参照しないということです)。

TRUST

プラグマにリストされているその他の制限は適用されず、真であると判断できます。これにより、RESTRICT_REFERENCES宣言を持つファンクションから、この宣言を持たないファンクション簡単に起動できます。

引数はどんな順序でも渡せます。サブプログラム本体にあるSQL文のいずれかが規則に違反する場合は、その文が解析されるときにエラーが発生します。

例6-20では、ファンクションcompound_により、データベースまたはパッケージ状態の読取りおよび書込みは行われないため、最大の純粋度レベルを宣言できます。PL/SQLコンパイラがサブプログラムを必要以上に拒否することがないように、サブプログラムで可能な最大の純粋度レベルを常に宣言してください。

例6-20 PRAGMA RESTRICT_REFERENCES

DROP TABLE accounts; -- in case it exists
CREATE TABLE accounts (
acctno   INTEGER,
balance  NUMBER
);

INSERT INTO accounts (acctno, balance)
VALUES (12345, 1000.00);

CREATE OR REPLACE PACKAGE finance AS
FUNCTION compound_ (
years  IN NUMBER,
amount IN NUMBER,
rate   IN NUMBER
) RETURN NUMBER;
PRAGMA RESTRICT_REFERENCES (compound_, WNDS, WNPS, RNDS, RNPS);
END finance;
/
CREATE PACKAGE BODY finance AS
FUNCTION compound_ (
years  IN NUMBER,
amount IN NUMBER,
rate   IN NUMBER
) RETURN NUMBER
IS
BEGIN
RETURN amount * POWER((rate / 100) + 1, years);
END compound_;
-- No pragma in package body
END finance;
/
DECLARE
interest NUMBER;
BEGIN
SELECT finance.compound_(5, 1000, 6)
INTO interest
FROM accounts
WHERE acctno = 12345;
END;
/

内容は次のとおりです。

- キーワードTRUSTの使用

- 静的SQL文と動的SQL文の違い

- パッケージ・ファンクションのオーバーロード

キーワードTRUSTの使用

PRAGMA RESTRICT REFERENCESにキーワードTRUSTが含まれる場合、プラグマにリストされている制限は適用されませんが、真であると判断できます。

プラグマを使用するPL/SQLコードのセクションから、プラグマを使用しないコードのセクションにあるサブプログラム(Javaメソッドなど)を起動するときは、起動されるサブプログラムか起動するサブプログラムのどちらかについて、PRAGMA RESTRICT REFERENCESとTRUSTを指定します。

例6-21と例6-22では両方とも、PL/SQLファンクションfがJavaプロシージャjava_sleepを起動します。例6-21では、java_sleepがTRUST付きのWNDSになるように宣言されているためこれが可能です。例6-22では、fがTRUST付きのWNDSになるように宣言されているため、サブプログラムを起動できます。

例6-21 起動される側にTRUSTが指定されたPRAGMA RESTRICT REFERENCES

CREATE OR REPLACE PACKAGE p IS
PROCEDURE java_sleep (milli_seconds IN NUMBER)
AS LANGUAGE JAVA NAME 'java.lang.Thread.sleep(long)';
PRAGMA RESTRICT_REFERENCES(java_sleep,WNDS,TRUST);

FUNCTION f (n NUMBER) RETURN NUMBER;
END p;
/
CREATE OR REPLACE PACKAGE BODY p IS
FUNCTION f (
n NUMBER
) RETURN NUMBER
IS
BEGIN
java_sleep(n);
RETURN n;
END f;
END p;
/

例6-22 起動する側にTRUSTが指定されたPRAGMA RESTRICT REFERENCES

CREATE OR REPLACE PACKAGE p IS
PROCEDURE java_sleep (milli_seconds IN NUMBER)
AS LANGUAGE JAVA NAME 'java.lang.Thread.sleep(long)';

FUNCTION f (n NUMBER) RETURN NUMBER;
PRAGMA RESTRICT_REFERENCES(f,WNDS,TRUST);
END p;
/
CREATE OR REPLACE PACKAGE BODY p IS
FUNCTION f (
n NUMBER
) RETURN NUMBER
IS
BEGIN
java_sleep(n);
RETURN n;
END f;
END p;
/

静的SQL文と動的SQL文の違い

静的なINSERT、UPDATEおよびDELETE文は、表の列などのデータベース状態を明示的に読み込まない場合は、RNDSには違反しません。ただし、動的なINSERT、UPDATEおよびDELETEの場合は、データベース状態を明示的に読み込むかどうかにかかわらず、常にRNDSに違反します。

次のINSERT文は、動的に実行される場合はRNDSに違反しますが、静的に実行される場合はRNDSに違反しません。

INSERT INTO my_table values(3, 'BOB');

次のUPDATE文は、my_tableの列nameを明示的に読み込むため、静的に実行された場合も動的に実行された場合もRNDSに違反します。

UPDATE my_table SET id=777 WHERE name='BOB';

パッケージ・ファンクションのオーバーロード

サブプログラムがオーバーロードされる場合、PRAGMA RESTRICT_REFERENCESが適用されるのは、最も新しく宣言されたバージョンに対してのみです。

例6-23では、プラグマは、2番目のvalidの宣言に適用されます。

例6-23 PRAGMA RESTRICT_REFERENCESを含むパッケージ・ファンクションのオーバーロード

CREATE OR REPLACE PACKAGE tests AS
FUNCTION valid (x NUMBER) RETURN CHAR;
FUNCTION valid (x DATE) RETURN CHAR;
PRAGMA RESTRICT_REFERENCES (valid, WNDS);
END;
/

ファンクションからの大量のデータの戻し

データ・ウェアハウス環境では、大量のデータを変換するためにPL/SQLファンクションを使用します。データは、異なるファンクションによる一連の変換を経由して渡されます。PL/SQL表ファンクションを使用すると、このような変換を、かなりのメモリー・オーバーヘッドを必要としたり、各変換の間でデータを表に格納する必要なく実行できます。これらのファンクションは、複数の行を受け入れて戻すことが可能で、一度ではなく準備できた順に行を戻すことができるだけでなく、パラレル化も可能です。

参照:
パイプライン・テーブル・ファンクションを使用して複数の変換を実行する方法の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

独自の集計関数のコード化

一連の行を分析して結果値を計算するために、次のようにSUMなどのSQL集計関数と同様に機能する集計関数をコード化することができます。

- 次のようなメンバー関数を定義するADTを定義します。

- ODCIAggregateInitialize

- ODCIAggregateIterate

- ODCIAggregateMerge

- ODCIAggregateTerminate

- メンバー関数をコーディングします。特に、ODCIAggregateIterate では、処理対象の各行について起動されると結果が蓄積されます。ADTの属性を使用して中間結果を格納します。

- 集計関数を作成して、ADTと対応付けます。

- SQL問合せ、DML文またはSQL集計関数に使用する他の場所から集計関数をコールします。集計関数を起動する際は、DISTINCTやALLなどの一般的なオプションを指定できます。

参照:
ユーザー定義の集計関数の詳細は、『Oracle Databaseデータ・カートリッジ開発者ガイド』を参照してください。

7 PL/Scopeの使用

PL/Scopeはコンパイラ駆動方式のツールであり、プログラム・ユニットのコンパイル時にPL/SQLソース・コード内の識別子に関するデータを収集し、静的データ・ディクショナリ・ビューで使用できるようにします。収集されたデータには識別子の型、使用方法(宣言、定義、参照、コール、代入)およびソース・コードにおける各使用場所に関する情報が含まれています。

PL/Scopeによって、強力で効率的なPL/Scopeソース・コード・ブラウザの開発が可能になります。このブラウザは、ソース・コードの参照および理解に費やされる時間を最小限にすることによって、PL/SQL開発者の生産性を向上させます。

PL/Scopeはアプリケーション開発者用のものであり、通常は開発データベースの環境で使用されます。

注意:
PL/Scopeでは、ソース・コードがラップされているPL/SQLユニットのデータを収集できません。PL/SQLソース・コードのラップの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

内容は次のとおりです。

- 識別子コレクションの指定

- STANDARDおよびDBMS_STANDARDのPL/Scope識別子データ

- PL/Scopeデータによる領域の使用量

- PL/Scopeデータの表示

- PL/Scopeが収集する識別子の型

- PL/Scopeがレポートする使用方法

- サンプルPL/Scopeセッション

識別子コレクションの指定

デフォルトでは、PL/ScopeはPL/SQLソース・プログラムの識別子用のデータを収集しません。パッケージ本体にある識別子など、PL/SQLソース・プログラムのすべての識別子用のデータをPL/Scopeによって収集するには、PL/SQLコンパイル・パラメータPLSCOPE_SETTINGSを'IDENTIFIERS:ALL'に設定します。

注意:
すべての識別子を収集すると大量のデータが生成され、コンパイル時間が長くなる可能性があります。

PL/Scopeでは、収集するデータをSYSAUX表領域に格納します。SYSAUX表領域が使用できず、PLSCOPE_SETTINGS='IDENTIFIERS:ALL'でプログラム・ユニットをコンパイルした場合、PL/Scopeではコンパイルされたオブジェクトのデータを収集しません。コンパイラから警告は発行されませんが、USER_ERRORS内に警告が保存されます。

参照:

- PLSCOPE_SETTINGSの詳細は、『Oracle Databaseリファレンス』を参照してください。

- PL/SQLのコンパイル・パラメータの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

STANDARDおよびDBMS_STANDARDのPL/Scope識別子データ

パッケージSTANDARDおよびDBMS_STANDARDは、VARCHAR2やNUMBERなどのベース型と、RAISE_APPLICATION_ERRORなどのサブプログラムを宣言して定義します。データベースにこれらのパッケージのPL/Scope識別子データがある場合、これらのパッケージが作成する識別子の使用状況をPL/Scopeで追跡することができます。

STANDARDおよびDBMS_STANDARD識別子データの必要性

STANDARDおよびDBMS_STANDARD識別子データがなくてもPL/Scopeを使用できます。このデータが必要となるのは、これらのパッケージで作成されるベース型またはサブプログラムがコードのどこで使用されるかを知る必要がある場合のみです。たとえば、ベース型BINARY_INTEGERがコードのどこで使用されるかを確認する場合は、PLS_INTEGERをかわりに使用できます。

データベースでのSTANDARDおよびDBMS_STANDARD識別子データの有無

新たに作成されたOracle Database 11gリリース1 (11.1.0.7)、またはOracle Database 10gリリース2から11.1.0.7にアップグレードされたデータベースには、パッケージSTANDARDおよびDBMS_STANDARDに対するPL/Scope識別子データが含まれます。11.1.0.6から11.1.0.7にアップグレードされたデータベースにはこのデータはありません。

データベースにこのデータが含まれるかどうかを確認するには、例7-1の問合せを使用します。

例7-1に、データベースにSTANDARDおよびDBMS_STANDARDのPL/Scope識別子データがある場合の問合せの結果を示します。

例7-1 STANDARDおよびDBMS_STANDARDのPL/Scope識別子データの有無

問合せ:

SELECT UNIQUE OBJECT_NAME
FROM ALL_IDENTIFIERS
WHERE OBJECT_NAME IN ('STANDARD', 'DBMS_STANDARD')
AND OWNER='SYS'
ORDER BY OBJECT_NAME;

結果:

OBJECT_NAME
------------------------------
DBMS_STANDARD
STANDARD

2 rows selected.

例7-1の問合せで行が選択されない場合、データベースにはパッケージSTANDARDおよびDBMS_STANDARDのPL/Scope識別子データがありません。このデータを収集するには、「STANDARDおよびDBMS_STANDARDの再コンパイル」で説明するように、DBAがパッケージSTANDARDおよびDBMS_STANDARDを再コンパイルする必要があります。

STANDARDおよびDBMS_STANDARDの再コンパイル

DBAは次の手順を使用して、パッケージSTANDARDおよびDBMS_STANDARDを再コンパイルすることができます。

注意:
この手順では、再コンパイルにより、データベース内のすべてのPL/SQLオブジェクトが無効化されてから再有効化されます。

1. データベースに接続し、データベースを停止してから、UPGRADEモードで起動します。

CONNECT / AS SYSDBA;
SHUTDOWN IMMEDIATE;
STARTUP PFILE=parameter_initialization_file UPGRADE;

2. パッケージSTANDARDおよびDBMS_STANDARDのすべての識別子のデータをPL/Scopeで収集します。

ALTER SESSION SET PLSCOPE_SETTINGS='IDENTIFIERS:ALL';

3. データベースを無効にして再コンパイルします。

@?/rdbms/admin/utlirp.sql

これで、PLSCOPE_SETTINGS='IDENTIFIERS:ALL'を使用して再コンパイルされたSTANDARDおよびDBMS_STANDARDを除いて、データベース内のすべてのPL/SQLオブジェクトが無効になります。

4. (オプション)PLSCOPE_SETTINGS='IDENTIFIERS:ALL'を使用して再コンパイルするその他のPL/SQLオブジェクトを無効にします。これには、次のようなスクリプトを使用します。

この問合せの5から9行をカスタマイズして、PL/Scope識別子データを必要とするオブジェクトのみを無効にします。次のスクリプトではすべてのオブジェクトのすべての識別子が収集されるため、大容量のデータが生成され、コンパイルに時間がかかる場合があります。

DECLARE
TYPE ObjIDArray IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
ObjIDs  ObjIDArray;
BEGIN
SELECT object_id BULK COLLECT INTO ObjIDs
FROM ALL_OBJECTS
WHERE object_type IN
(SELECT DISTINCT TYPE
FROM ALL_PLSQL_OBJECT_SETTINGS);
FOR i IN 1..SQL%ROWCOUNT LOOP
BEGIN
DBMS_UTILITY.INVALIDATE(ObjIDs(i),
'PLSCOPE_SETTINGS=IDENTIFIERS:ALL REUSE SETTINGS');
NULL;
END;
END LOOP;
END;
/

注意:
このスクリプトでは次のことに注意してください。

- ObjIDs属性は無名ブロックによってロックされるパッケージに依存するため、SQL%ROWCOUNTに対してObjIDs.LASTをかわりに使用しないでください。

- データベースが大きい場合にリソース不足になるため、BULK COLLECT文でカーソルFOR LOOPをかわりに使用しないでください。

5. データベースを停止してから、NORMALモードで起動します。

SHUTDOWN IMMEDIATE;
STARTUP PFILE=parameter_initialization_file;

6. 無効なPL/SQLオブジェクトが残っている場合は、次のいずれかを実行します。

- PL/SQLオブジェクトの参照時に自動的に再コンパイルされるようにします。
(複雑な依存関係がある場合には時間がかかることがあります。)

- 「無効なPL/SQLオブジェクトを再コンパイルするutlrp.sqlの実行」で説明するように、スクリプトutlrp.sqlを実行して、無効なPL/SQLオブジェクトを再コンパイルします。

無効なPL/SQLオブジェクトを再コンパイルするutlrp.sqlの実行

データベースがNORMALモードで再起動されている場合(手順5)、DBAまたはDBAロールが付与されたユーザーは次の手順を使用できます。

1. SYSとしてデータベースに接続します。

CONNECT / AS SYS;

2. スクリプトutlrp.sqlを実行します。

@?/rdbms/admin/utlrp.sql

スクリプトから指示がある場合はそれに従い、再びスクリプトを実行します。

指示がなくスクリプトが異常終了した場合は、再びスクリプトを実行します。

PL/Scopeデータによる領域の使用量

PL/ScopeのデータはSYSAUX表領域に格納されます。SYSDBAとしてログオンしている場合は、例7-2の問合せを使用してPL/Scopeデータが使用している領域の容量を表示できます。

例7-2 PL/Scopeデータによる領域の使用量

問合せ:

SELECT SPACE_USAGE_KBYTES
FROM V$SYSAUX_OCCUPANTS
WHERE OCCUPANT_NAME='PL/SCOPE';

結果:

SPACE_USAGE_KBYTES
------------------
1600

1 row selected.

SYSAUX表領域の管理の詳細は、『Oracle Database管理者ガイド』を参照してください。

PL/Scopeデータの表示

PL/Scopeで収集したデータを表示するには、次のいずれかを使用できます。

- 静的データ・ディクショナリ・ビュー

- デモ・ツール

- SQL Developer

静的データ・ディクショナリ・ビュー

静的データ・ディクショナリ・ビュー*_IDENTIFIERSでは、その型や使用方法など、PL/Scope識別子に関する情報が表示されます。これらのビューの一般情報は、『Oracle Databaseリファレンス』を参照してください。

内容は次のとおりです。

- 一意キー

- コンテキスト

- シグネチャ

一意キー

*_IDENTIFIERSビューの各行は、PL/SQLユニットの識別子の一意の使用方法を表します。これらの各ビューでは、次のものがコンパイル・ユニット内で同等の一意キーです。

- LINE、COL、USAGE

- USAGE_ID

*_IDENTIFIERSビューの使用方法は、「PL/Scopeがレポートする使用方法」を参照してください。

注意:
IN OUTモードでサブプログラムに渡される識別子では、*_IDENTIFIERSにREFERENCE使用方法(INに対応)およびASSIGNMENT使用方法(OUTに対応)の2つの行があります。

コンテキスト

コンテキストは、複数の使用方法の間の関係を検出する場合に役立ちます。最上位のスキーマ・オブジェクト宣言および定義を除き、識別子のすべての使用方法は別の使用方法のコンテキストで発生します。次に例を示します。

- ローカル変数宣言は、最上位のプロシージャ宣言のコンテキスト内で発生します。

- x VARCHAR2(10)など、識別子が変数として宣言される場合、VARCHAR2型参照のUSAGE_CONTEXT_IDには、x宣言のUSAGE_IDが挿入され、変数宣言をその型に関連付けることができます。

つまり、例7-3に示すように、USAGE_CONTEXT_IDはUSAGE_IDに対する再帰外部キーです。

例7-3 USAGE_CONTEXT_IDおよびUSAGE_ID

ALTER SESSION SET PLSCOPE_SETTINGS = 'IDENTIFIERS:ALL';

CREATE OR REPLACE PROCEDURE a (p1 IN BOOLEAN) IS
v PLS_INTEGER;
BEGIN
v := 42;
DBMS_OUTPUT.PUT_LINE(v);
RAISE_APPLICATION_ERROR (-20000, 'Bad');
EXCEPTION
WHEN Program_Error THEN NULL;
END a;
/
CREATE OR REPLACE PROCEDURE b (p2 OUT PLS_INTEGER, p3 IN OUT VARCHAR2) IS
n NUMBER;
q BOOLEAN := TRUE;
BEGIN
FOR j IN 1..5 LOOP
a(q); a(TRUE); a(TRUE);
IF j > 2 THEN
GOTO z;
END IF;
END LOOP;
<<z>> DECLARE
d CONSTANT CHAR(1) := 'X';
BEGIN
SELECT COUNT(*) INTO n FROM Dual WHERE Dummy = d;
END z;
END b;
/
WITH v AS (
SELECT    Line,
Col,
INITCAP(NAME) Name,
LOWER(TYPE)   Type,
LOWER(USAGE)  Usage,
USAGE_ID,
USAGE_CONTEXT_ID
FROM USER_IDENTIFIERS
WHERE Object_Name = 'B'
AND Object_Type = 'PROCEDURE'
)
SELECT RPAD(LPAD(' ', 2*(Level-1)) ||
Name, 20, '.')||' '||
RPAD(Type, 20)||
RPAD(Usage, 20)
IDENTIFIER_USAGE_CONTEXTS
FROM v
START WITH USAGE_CONTEXT_ID = 0
CONNECT BY PRIOR USAGE_ID = USAGE_CONTEXT_ID
ORDER SIBLINGS BY Line, Col
/

結果:

IDENTIFIER_USAGE_CONTEXTS
-------------------------------------------------------------
B................... procedure           declaration
B................. procedure           definition
P2.............. formal out          declaration
Pls_Integer... subtype             reference
P3.............. formal in out       declaration
Varchar2...... character datatype  reference
N............... variable            declaration
Number........ number datatype     reference
Q............... variable            declaration
Q............. variable            assignment
Boolean....... boolean datatype    reference
J............... iterator            declaration
A............. procedure           call
Q........... variable            reference
A............. procedure           call
A............. procedure           call
J............. iterator            reference
Z............. label               reference
Z............... label               declaration
D............. constant            declaration
D........... constant            assignment
Char........ subtype             reference
N............. variable            assignment
D............. constant            reference

24 rows selected.

シグネチャ

識別子のシグネチャは、プログラム・ユニット内および複数のプログラム・ユニット間で一意のものです。つまり、シグネチャは複数の識別子が同じ名前であっても、同じプログラム・ユニット内に定義されているか、または異なるプログラム・ユニットに定義されているかを区別します。

例7-4のプログラム・ユニットの場合、pという名前の2つの識別子があり、静的データ・ディクショナリ・ビューUSER_IDENTIFIERSにNAMEがpという行が複数ありますが、これらの行のSIGNATUREは異なるものです。外部プロシージャpに関連付けられた行に1つのシグネチャがあり、内部プロシージャpに関連付けられた行には別のシグネチャがあります。プログラム・ユニットqがプロシージャpをコールする場合、qのUSER_IDENTIFIERSビューには、NAMEがpでSIGNATUREが外部プロシージャpのシグネチャの行があります。

例7-4 名前がpの2つの識別子を持つプログラム・ユニット

CREATE OR REPLACE PROCEDURE p IS
PROCEDURE p IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Inner p');
END p;
BEGIN
DBMS_OUTPUT.PUT_LINE('Outer p');
p();
END p;
/

デモ・ツール

$ORACLE_HOME/plsql/demo/plscopedemo.sqlは、PL/SQL Web Toolkitを使用するPL/SQL Webアプリケーションとして実装されたHTMLベースのデモです。PL/SQL Webアプリケーションの詳細は、「PL/SQL Webアプリケーションの実装」を参照してください。

SQL Developer

PL/ScopeはSQL Developerの機能の1つです。SQL DeveloperからのPL/Scopeの使用の詳細は、SQL Developerのオンライン・マニュアルを参照してください。

PL/Scopeが収集する識別子の型

表7-1に、PL/Scopeが収集する識別子の型をアルファベット順に示します。表7-1の識別子の型は、*_IDENTIFIER静的データ・ディクショナリ・ビューのTYPE列に表示されます。このビューについては、『Oracle Databaseリファレンス』を参照してください。

注意:
PLSCOPE_SETTINGS='IDENTIFIERS:ALL'でコンパイルされていないコンパイル・ユニットに宣言された識別子は、*_IDENTIFIER静的データ・ディクショナリ・ビューに表示されません。

表7-1 PL/Scopeが収集する識別子の型

TYPE列の値

コメント

ASSOCIATIVE ARRAY

CONSTANT

CURSOR

BFILE DATATYPEBLOB DATATYPEBOOLEAN DATATYPECHARACTER DATATYPECLOB DATATYPEDATE DATATYPEINTERVAL DATATYPENUMBER DATATYPETIME DATATYPETIMESTAMP DATATYPE

各DATATYPEは、STANDARDパッケージで宣言されたベース型です。

EXCEPTION

FORMAL INFORMAL IN OUTFORMAL OUT

FUNCTION

INDEX TABLE

ITERATOR

イテレータはFORループの索引です。

LABEL

ラベル宣言もコンテキストとして機能します。

LIBRARY

NESTED TABLE

OBJECT

OPAQUE

内部不透明型にはANYDATAおよびXMLTypeがあります。

PACKAGE

PROCEDURE

RECORD

REFCURSOR

SUBTYPE

SYNONYM

PL/Scopeでは、シノニムのベース・オブジェクト名は解決しません。シノニムのベース・オブジェクト名を調べるには、*_SYNONYMSを問い合せます。

TRIGGER

UROWID

VARRAY

VARIABLE

オブジェクト属性、ローカル変数、パッケージ変数、レコード・フィールドのいずれにもできます。

PL/Scopeがレポートする使用方法

表7-2に、PL/Scopeがレポートする使用方法をアルファベット順に示します。表7-2の識別子の型は、*_IDENTIFIER静的データ・ディクショナリ・ビューのUSAGE列に表示されます。このビューについては、『Oracle Databaseリファレンス』を参照してください。

表7-2 PL/Scopeがレポートする使用方法

USAGE列の値

説明

ASSIGNMENT

代入は、VARIABLEなどの値を保持できる識別子に対してのみ可能です。代入には次のものがあります。

- 代入演算子の左側での識別子の使用

- FETCH文のINTO句での識別子の使用

- サブプログラムへの識別子の参照渡し(OUTモード)

- OUTまたはIN OUTモードでの、EXECUTE IMMEDIATE文のUSING句における識別子のバインド変数としての使用

IN OUTモードでサブプログラムに渡される識別子には、REFERENCE使用方法(INに対応)とASSIGNMENT使用方法(OUTに対応)の両方があります。

CALL

PL/Scopeのコンテキストでは、CALLはコール・スタックの上にコールをプッシュする操作です。つまり、次のようになります。

- FUNCTIONまたはPROCEDUREへのコール

- カーソル識別子の実行またはフェッチ(SQLへの論理コール)

GOTO文または例外の発生はどちらもコール・スタックの上にコールをプッシュしないため、CALLではありません。

DECLARATION

DECLARATIONは、識別子が存在し、それぞれの識別子に1つずつDECLARATIONがあることをコンパイラに通知します。各DECLARATIONは、関連データ型を持つことができます。

ループ索引宣言の場合、(*_IDENTIFIERSビューの)LINEおよびCOLは、暗黙的にループ索引を宣言するFOR句の行および列です。

ラベル索引宣言の場合、LINEおよびCOLは、デリミタ<<および>>内でラベルが出現する(および暗黙的に宣言される)行および列です。

DEFINITION

DEFINITIONは、以前に宣言した識別子を実装または使用する方法をコンパイラに通知します。

次の各識別子の型にそれぞれDEFINITIONがあります。

- EXCEPTION(複数定義が可能)

- FUNCTION

- OBJECT

- PACKAGE

- PROCEDURE

- TRIGGER

最上位の識別子の場合のみ、DEFINITIONおよびDECLARATIONは同じ場所にあります。

REFERENCE

REFERENCEは、その値を変更せずに識別子を使用します。参照には次のものがあります。

- 例外識別子の発生。

- 変数または仮パラメータの宣言での型識別子の使用。

- あるフィールドにアクセスするための複数のフィールドが型に含まれている変数識別子の使用。たとえば、myrecordvar.myfield := 1では、myrecordvarに対して参照が行われ、myfieldに対して代入が行われます。

- FETCHを除く任意の目的でのカーソルの使用。

- サブプログラムへの識別子の値渡し(INモード)。

- INまたはIN OUTモードでの、EXECUTE IMMEDIATE文のUSING句における識別子のバインド変数としての使用

IN OUTモードでサブプログラムに渡される識別子には、REFERENCE使用方法(INに対応)とASSIGNMENT使用方法(OUTに対応)の両方があります。

サンプルPL/Scopeセッション

次のサンプル・セッションでは、HRとしてログインしているものとします。

1. セッション・パラメータを設定します。

ALTER SESSION SET PLSCOPE_SETTINGS='IDENTIFIERS:ALL';

2. 次のパッケージを作成します。

CREATE OR REPLACE PACKAGE PACK1 IS
TYPE r1 is RECORD (rf1 VARCHAR2(10));
FUNCTION F1(fp1 NUMBER) RETURN NUMBER;
PROCEDURE P1(pp1 VARCHAR2);
END PACK1;
/
CREATE OR REPLACE PACKAGE BODY PACK1 IS
FUNCTION F1(fp1 NUMBER) RETURN NUMBER IS
a NUMBER := 10;
BEGIN
RETURN a;
END F1;
PROCEDURE P1(pp1 VARCHAR2) IS
pr1 r1;
BEGIN
pr1.rf1 := pp1;
END;
END PACK1;
/

3. PL/Scopeがそのパッケージ本体のすべての識別子を収集していることを確認します。

SELECT PLSCOPE_SETTINGS
FROM USER_PLSQL_OBJECT_SETTINGS
WHERE NAME='PACK1' AND TYPE='PACKAGE BODY'

結果:

PLSCOPE_SETTINGS
------------------------------------------------------------------------
IDENTIFIERS:ALL

4. すべてのDECLARATIONの使用方法について問い合せ、HRの一意の識別子を表示します。たとえば、%1のような名前の一意の識別子をすべて確認するには、次のSQL*Plus書式設定コマンドと問合せを使用します。

COLUMN NAME FORMAT A6
COLUMN SIGNATURE FORMAT A32
COLUMN TYPE FORMAT A9

SELECT NAME, SIGNATURE, TYPE
FROM USER_IDENTIFIERS
WHERE NAME LIKE '%1' AND USAGE='DECLARATION'
ORDER BY OBJECT_TYPE, USAGE_ID;

次に類似した結果が得られます。

NAME   SIGNATURE                        TYPE
------ -------------------------------- ---------
PACK1  41820FA4D5EF6BE707895178D0C5C4EF PACKAGE
R1     EEBB6849DEE31BC77BF186EBAE5D4E2D RECORD
RF1    41D70040337349634A7F547BC83517C7 VARIABLE
F1     4559CF050A5F5C3E5F5FFDD0D9D55EFA FUNCTION
FP1    CAC3474C112DBEC67AB926978D9A16C1 FORMAL IN
P1     B7C0576BA4D00C33A65CC0C64CADAB89 PROCEDURE
PP1    6B74CF95A5B7377A735925DFAA280266 FORMAL IN
FP1    98EB63B8A4AFEB5EF94D50A20165D6CC FORMAL IN
PP1    AD89FE0EAE9CE5D6D48AA4684E0D57DF FORMAL IN
PR1    1B5117F30E8DAE0261A02CAA5E33883F VARIABLE

10 rows selected.

*_IDENTIFIERS静的データ・ディクショナリ・ビューでは、基本的な型名のみが表示されます。たとえば、ローカル変数やレコード・フィールドのTYPEはVARIABLEです。VARIABLEの正確な型を確認するには、そのUSAGE_CONTEXT_IDを使用する必要があります。

5. すべてのローカル変数を検索します。

COLUMN VARIABLE_NAME FORMAT A13
COLUMN CONTEXT_NAME FORMAT A12

SELECT a.NAME variable_name,
b.NAME context_name,
a.SIGNATURE
FROM USER_IDENTIFIERS a, USER_IDENTIFIERS b
WHERE a.USAGE_CONTEXT_ID = b.USAGE_ID
AND a.TYPE = 'VARIABLE'
AND a.USAGE = 'DECLARATION'
AND a.OBJECT_NAME = 'PACK1'
AND a.OBJECT_NAME = b.OBJECT_NAME
AND a.OBJECT_TYPE =  b.OBJECT_TYPE
AND (b.TYPE = 'FUNCTION' or b.TYPE = 'PROCEDURE')
ORDER BY a.OBJECT_TYPE, a.USAGE_ID;

次に類似した結果が得られます。

VARIABLE_NAME CONTEXT_NAME SIGNATURE
------------- ------------ --------------------------------
A             F1           1691C6B3C951FCAA2CBEEB47F85CF128
PR1           P1           1B5117F30E8DAE0261A02CAA5E33883F

2 rows selected.

6. ローカル変数Aに対して実行されたすべての使用方法を検索します。

COLUMN USAGE FORMAT A11
COLUMN USAGE_ID FORMAT 999
COLUMN OBJECT_NAME FORMAT A11
COLUMN OBJECT_TYPE FORMAT A12

SELECT USAGE, USAGE_ID, OBJECT_NAME, OBJECT_TYPE
FROM USER_IDENTIFIERS
WHERE SIGNATURE='1691C6B3C951FCAA2CBEEB47F85CF128'  -- signature of A
ORDER BY OBJECT_TYPE, USAGE_ID;

結果:

USAGE       USAGE_ID OBJECT_NAME OBJECT_TYPE
----------- -------- ----------- ------------
DECLARATION        6 PACK1       PACKAGE BODY
ASSIGNMENT         8 PACK1       PACKAGE BODY
REFERENCE          9 PACK1       PACKAGE BODY

3 rows selected.

ローカル識別子Aに対して実行された使用方法は、識別子宣言(USAGE_ID 6)、代入(USAGE_ID 8)、および参照(USAGE_ID 9)です。

7. ローカル識別子Aの宣言から、その型を調べます。

COLUMN NAME FORMAT A6
COLUMN TYPE FORMAT A15

SELECT a.NAME, a.TYPE
FROM USER_IDENTIFIERS a, USER_IDENTIFIERS b
WHERE a.USAGE = 'REFERENCE'
AND a.USAGE_CONTEXT_ID = b.USAGE_ID
AND b.USAGE = 'DECLARATION'
AND b.SIGNATURE = '4559CF050A5F5C3E5F5FFDD0D9D55EFA'  -- signature of F1
AND a.OBJECT_TYPE = b.OBJECT_TYPE
AND a.OBJECT_NAME = b.OBJECT_NAME;

結果:

NAME   TYPE
------ ---------------
NUMBER NUMBER DATATYPE

1 row selected.

注意:
この問合せでは、パッケージSTANDARDおよびDBMS_STANDARDのPL/Scope識別子データがデータベースに含まれる場合のみ、出力が表示されます。詳細は、「STANDARDおよびDBMS_STANDARDのPL/Scope識別子データ」を参照してください。

8. ローカル識別子Aに対する代入が行われた場所を調べます。

SELECT LINE, COL, OBJECT_NAME, OBJECT_TYPE
FROM USER_IDENTIFIERS
WHERE SIGNATURE='1691C6B3C951FCAA2CBEEB47F85CF128'  -- signature of A
AND USAGE='ASSIGNMENT';

結果:

LINE        COL OBJECT_NAME OBJECT_TYPE
---------- ---------- ----------- ------------
3          5 PACK1       PACKAGE BODY

1 row selected.

8 PL/SQL階層プロファイラの使用

PL/SQL階層プロファイラを使用すると、PL/SQLアプリケーションのボトルネックおよびパフォーマンスのチューニング機会を特定できます。

このプロファイラにより、ファンクション・コール別に編成されたPL/SQLプログラムの動的実行プロファイルがレポートされ、SQL実行時間とPL/SQL実行時間が個別に明確になります。特別なソースやコンパイル時間の準備は必要なく、あらゆるPL/SQLプログラムをプロファイリングできます。

この章では、PL/SQL階層プロファイラについて説明するとともに、これを使用してPL/SQLプログラムのプロファイル・データを収集して分析する方法を示します。

内容は次のとおりです。

- PL/SQL階層プロファイラの概要

- プロファイル・データの収集

- RAWプロファイラ出力の理解

- プロファイル・データの分析

- plshprofユーティリティ

PL/SQL階層プロファイラの概要

非階層(フラット)プロファイラにより、プログラムによって各サブプログラム内で費やされた時間(サブプログラムの関数時間または自己時間)が記録されます。関数時間は役に立ちますが、たいていこれでは十分ではありません。たとえば、サブプログラムINSERT_ORDERでプログラム全体の40%が費やされたことがわかれば参考になりますが、INSERT_ORDERを頻繁にコールするプログラムや、INSERT_ORDERの下(子サブプログラムを含む)で費やされた合計時間がわかればさらに便利です。階層プロファイラは、このような情報を提供します。

PL/SQL階層プロファイラには、次の機能があります。

- サブプログラム・コール別に編成されたPL/SQLプログラムの動的実行プロファイルのレポート

- SQL実行時間およびPL/SQL実行時間の個別の説明

- 特殊なソースやコンパイル時間の準備が不要

- カスタム・レポートを生成するために統合開発環境(IDE)ツール(SQL Developerやサード・パーティ・ツールなど)によって処理された結果のデータベース表(階層プロファイラ表)への格納

- 次のような、サブプログラム・レベルの実行サマリー情報の提供

- サブプログラムに対するコールの数

- サブプログラム自体で費やされた時間(関数時間または自己時間)

- サブプログラム自体およびその子サブプログラムで費やされた時間(サブツリー時間)

- 次のような、詳細な親子情報

- 特定のサブプログラムのすべてのコール元(親)

- 特定のサブプログラムによってコールされたすべてのサブプログラム(子)

- サブプログラムxがyからコールされたときに費やされた時間

- サブプログラムxがyからコールされた回数

PL/SQL階層プロファイラは、DBMS_HPROFパッケージによって実装され、次の2つのコンポーネントを持ちます。

- データ・コレクション
データ・コレクション・コンポーネントは、PL/SQL Virtual Machine固有のパーツです。DBMS_HPROFパッケージには、階層プロファイリングのオンとオフを切り替えるAPIが用意されています。RAWプロファイラ出力はファイルに書き込まれます。

- アナライザ
アナライザ・コンポーネントにより、RAWプロファイラ出力が処理され、その結果が階層プロファイラ表に格納されます。

注意:
アナライザを使用せずに、RAWプロファイラ出力から直接簡単なHTMLレポートを生成するには、plshprofコマンドライン・ユーティリティを使用できます。

プロファイル・データの収集

PL/SQL階層プロファイラ用としてPL/SQLプログラムからプロファイル・データを収集する手順は、次のとおりです。

1. 次の権限があることを確認します。

- DBMS_HPROFパッケージに対するEXECUTE権限

- DBMS_HPROF.START_PROFILINGをコールするときに指定するディレクトリに対するWRITE権限

2. DBMS_HPROF.START_PROFILING PL/SQL APIを使用して、階層プロファイラのデータ・コレクションをセッションで開始します。

3. 適切なコード・カバレッジを取得するために十分な時間PL/SQLプログラムを実行します。
経過時間を最大限正確に測定するために、PL/SQLプログラムが実行されているシステム上で関係のないアクティビティは実行しないようにしてください。

4. DBMS_HPROF.STOP_PROFILING PL/SQL APIを使用して、階層プロファイラのデータ・コレクションを終了します。

DBMS_HPROF.START_PROFILINGおよびDBMS_HPROF.STOP_PROFILINGの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

次のPL/SQLプロシージャtestについて検討してみます。

CREATE OR REPLACE PROCEDURE test IS
n NUMBER;

PROCEDURE foo IS
BEGIN
SELECT COUNT(*) INTO n FROM EMPLOYEES;
END foo;

BEGIN  -- test
FOR i IN 1..3 LOOP
foo;
END LOOP;
END test;
/

例8-1のSQLスクリプトは、PL/SQLプロシージャtestの実行をプロファイリングしたものです。

例8-1 PL/SQLプロシージャのプロファイリング

BEGIN
/* Start profiling.
Write raw profiler output to file test.trc in a directory
that is mapped to directory object PLSHPROF_DIR
(see note after example). */

DBMS_HPROF.START_PROFILING('PLSHPROF_DIR', 'test.trc');
END;
/
-- Run procedure to be profiled
BEGIN
test;
END;
/
BEGIN
-- Stop profiling
DBMS_HPROF.STOP_PROFILING;
END;
/

注意:
ディレクトリ・オブジェクトは、ファイル・システムのパス名の別名です。たとえば、データベースAS SYSDBAに接続している場合、次のCREATE DIRECTORY文では、ディレクトリ・オブジェクトPLSHPROF_DIRが作成され、これがファイル・システム・ディレクトリ/private/plshprof/resultsにマップされます。

CREATE DIRECTORY PLSHPROF_DIR as '/private/plshprof/results';

例8-1のSQLスクリプトを実行するには、PLSHPROF_DIRとマップ先のディレクトリの両方に対するREADおよびWRITE権限が必要です。データベースにAS SYSDBAで接続している場合、次のGRANT文では、PLSHPROF_DIRに対するREADおよびWRITE権限がHRに付与されます。

GRANT READ, WRITE ON DIRECTORY PLSHPROF_DIR TO HR;

ディレクトリ・オブジェクトの使用の詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。

RAWプロファイラ出力の理解

RAWプロファイラ出力は、PL/SQL階層プロファイラのアナライザ・コンポーネントによって処理されることを目的としています。ただし、このように処理されなくても、プログラムの簡単な関数レベルのトレースは提供できます。ここでは、RAWプロファイラ出力について説明します。

注意:
この章で示すRAWプロファイラの形式は、RAWプロファイラ出力の概念的な機能を示すことのみを目的としています。形式の詳細は、Oracle Databaseリリースごとに異なる可能性があります。

例8-1のSQLスクリプトでは、次のRAWプロファイラ出力がファイルtest.trcに書き込まれました。

P#V PLSHPROF Internal Version 1.0
P#! PL/SQL Timer Started
P#C PLSQL."".""."__plsql_vm"
P#X 2
P#C PLSQL."".""."__anonymous_block"
P#X 50
P#C PLSQL."HR"."TEST"::7."TEST"#980980e97e42f8ec #1
P#X 3
P#C PLSQL."HR"."TEST"::7."TEST.FOO"#980980e97e42f8ec #4
P#X 35
P#C SQL."HR"."TEST"::7."__static_sql_exec_line6" #6
P#X 206
P#R
P#X 26
P#R
P#X 2
P#C PLSQL."HR"."TEST"::7."TEST.FOO"#980980e97e42f8ec #4
P#X 4
P#C SQL."HR"."TEST"::7."__static_sql_exec_line6" #6
P#X 80
P#R
P#X 3
P#R
P#X 0
P#C PLSQL."HR"."TEST"::7."TEST.FOO"#980980e97e42f8ec #4
P#X 3
P#C SQL."HR"."TEST"::7."__static_sql_exec_line6" #6
P#X 69
P#R
P#X 3
P#R
P#X 1
P#R
P#X 1
P#R
P#X 3
P#R
P#C PLSQL."".""."__plsql_vm"
P#X 3
P#C PLSQL."".""."__anonymous_block"
P#X 44
P#C PLSQL."SYS"."DBMS_HPROF"::11."STOP_PROFILING"#980980e97e42f8ec #53
P#R
P#R
P#R
P#! PL/SQL Timer Stopped

表8-1 RAWプロファイラ出力ファイルのインジケータ

インジケータ

意味

P#V

PLSHPROFバナーとバージョン番号

P#C

サブプログラムへのコール(コール・イベント)

P#R

サブプログラムからの戻り値(戻りイベント)

P#X

前のイベントと次のイベント間の経過時間

P#!

コメント

コール・イベント(P#C)と戻りイベント(P#R)は、(一対のカッコのように)常に正しくネストされます。未処理の例外が原因でコール先のサブプログラムが終了しても、対応する戻りイベントはレポートされます。

RAWプロファイラ出力の各コール・イベント(P#C)のエントリには、次の情報が含まれます。

- コール先のサブプログラムが属するネームスペース
「追跡されるサブプログラムのネームスペース」を参照してください。

- コール先のサブプログラムが定義されているPL/SQLモジュールの名前

- コール先のサブプログラムが定義されているPL/SQLモジュールのタイプ

- コール先のサブプログラムの名前
この名前は、「特別な関数名」の1つである場合があります。

- コール先のサブプログラムのシグネチャのMD5ハッシュを表す16進値
DBMS_HPROF.analyze PL/SQL API(「プロファイル・データの分析」を参照)により、ハッシュ値が階層プロファイラ表に格納されます。これにより、ユーザーとDBMS_HPROF.analyzeの両方が、オーバーロードされたサブプログラム(同じ名前を持つサブプログラム)を区別できるようになります。

- コール先のサブプログラムがPL/SQLモジュールに定義されている行番号
PL/SQL階層プロファイラでは、モジュール内の個々の行で費やされた時間は測定されませんが、行番号を使用すると、(IDE/ツールのように)モジュール内のサブプログラムのソースの場所を特定し、オーバーロードされたサブプログラムを区別できるようになります。

たとえば、前述の例のRAWプロファイラ出力の次のエントリについて検討してみます。

P#C PLSQL."HR"."TEST"::7."TEST.FOO"#980980e97e42f8ec #4

前述のエントリの構成要素には、次のような意味があります。

構成要素

意味

PLSQL

PLSQLは、コール先のサブプログラムが属するネームスペースです。

"HR"."TEST"

HR.TESTは、コール先のサブプログラムが定義されているPL/SQLモジュールの名前です。

7

7は、HR.TESTのモジュール・タイプの内部列挙子です。モジュール・タイプの例としては、プロシージャ、パッケージおよびパッケージ本体があります。

"TEST.FOO"

TEST.FOOは、コール先のサブプログラムの名前です。

#980980e97e42f8ec

#980980e97e42f8ecは、TEST.FOOのシグネチャのMD5ハッシュを表す16進値です。

#4

4は、TEST.FOOが定義されているPL/SQLモジュールHR.TEST内の行番号です。

注意:
サブプログラムがインラインされている場合、プロファイラ出力ではレポートされません。サブプログラムのインラインの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。
DETERMINISTICファンクションのコールが最適化されている場合、プロファイラ出力ではレポートされません。DETERMINISTICファンクションの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

追跡されるサブプログラムのネームスペース

PL/SQL階層プロファイラが追跡するサブプログラムは、次のようにネームスペースPLSQLおよびSQLに分類されます。

- ネームスペースPLSQLには、次が含まれます。

- PL/SQLサブプログラム・コール

- PL/SQLトリガー

- 無名PL/SQLブロック

- リモート・サブプログラム・コール

- パッケージ初期化ブロック

- ネームスペースSQLには、問合せ、データ操作言語(DML)文、データ定義言語(DDL)文およびネイティブ動的SQL文など、PL/SQLから実行されるSQL文が含まれます。

特別な関数名

PL/SQL階層プロファイラでは、特定の操作が表8-2に示す名前とネームスペースを持つ関数であるかのように追跡されます。

表8-2 PL/SQL階層プロファイラによって追跡される操作の関数名

追跡される操作

関数名

ネームスペース

PL/SQL Virtual Machineへのコール

__plsql_vm

PL/SQL

無名PL/SQLブロック

__anonymous_block

PL/SQL

パッケージ初期化ブロック

__pkg_init

PL/SQL

行line#の静的SQL文

__static_sql_exec_lineline#

SQL

行line#の動的SQL文

__dyn_sql_exec_lineline#

SQL

行line#のSQL FETCH文

__sql_fetch_lineline#

SQL

プロファイル・データの分析

PL/SQL階層プロファイラのアナライザ・コンポーネントDBMS_HPROF.analyzeにより、RAWプロファイラ出力が処理され、表8-3に示す階層データベース表に結果が格納されます。

表8-3 PL/SQL階層プロファイラ・データベース表

表

説明

DBMSHP_RUNS

このDBMS_HPROF.analyzeの実行時のトップレベル情報。列の詳細は、表8-4を参照してください。

DBMSHP_FUNCTION_INFO

このDBMS_HPROF.analyzeの実行時にプロファイリングされる各サブプログラムの情報。列の詳細は、表8-5を参照してください。

DBMSHP_PARENT_CHILD_INFO

このDBMS_HPROF.analyzeの実行時にプロファイリングされる各サブプログラムの親子情報。列の詳細は、表8-6を参照してください。

内容は次のとおりです。

- 階層プロファイラ表の作成

- 階層プロファイラ表の理解

注意:
アナライザを使用せずに、RAWプロファイラ出力から直接簡単なHTMLレポートを生成するには、plshprofコマンドライン・ユーティリティを使用できます。詳細は、「plshprofユーティリティ」を参照してください。

階層プロファイラ表の作成

表8-3にある階層プロファイラ表と、プロファイル・データを永続的に格納するために必要な他のデータ構造を作成する手順は、次のとおりです。

1. スクリプトdbmshptab.sql(ディレクトリrdbms/adminにあります)を実行します。
このスクリプトにより、表8-3にある階層プロファイラ表と、プロファイル・データを永続的に格納するために必要な他のデータ構造の両方が作成されます。

注意:
スクリプトdbmshptab.sqlを実行すると、以前に作成されたすべての階層プロファイラ表が削除されます。

2. 次の権限があることを確認します。

- DBMS_HPROFパッケージに対するEXECUTE権限

- DBMS_HPROF.analyzeで指定されるディレクトリに対するREAD権限

3. PL/SQL API DBMS_HPROF.analyzeを使用して、単一のRAWプロファイラ出力ファイルを分析し、結果を階層プロファイラ表に格納します。
(RAWプロファイラ出力ファイルの例は、「RAWプロファイラ出力の理解」にあるtest.trcを参照してください。)

DBMS_HPROF.analyzeの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

4. 階層プロファイラ表を使用して、カスタム・レポートを生成します。

例8-2の無名ブロックでは、次の処理を行います。

- DBMS_HPROF.analyze機能の起動により、次が実行されます。

- ディレクトリ・オブジェクトPLSHPROF_DIRにマップされたディレクトリにあるRAWプロファイラ出力ファイルtest.trc(「RAWプロファイラ出力の理解」を参照)のプロファイル・データを分析し、データを表8-3の階層プロファイラ表に格納します。

- 表8-3の階層プロファイラ表に問い合せるために使用できる一意の識別子を戻します。(これらの階層プロファイラ表に問い合せることにより、カスタマイズ・レポートを作成できます。)

- 一意の識別子を、出力のための変数runidに保存します。

例8-2 DBMS_HPROF.analyzeの起動

DECLARE
runid NUMBER;
BEGIN
runid := DBMS_HPROF.analyze(LOCATION=>'PLSHPROF_DIR',
FILENAME=>'test.trc');
DBMS_OUTPUT.PUT_LINE('runid = ' || runid);
END;
/

階層プロファイラ表の理解

次の各項では、表8-3の階層プロファイラ表を使用する方法について説明します。

- 階層プロファイラ・データベース表の列

- オーバーロードされたサブプログラムの区別

- サンプルのPL/SQLプロシージャの階層プロファイラ表

- オプションを使用したDBMS_HPROF.analyzeのコール例

階層プロファイラ・データベース表の列

表8-4は、階層プロファイラ表DBMSHP_RUNSの列を示します。この表には、DBMS_HPROF.analyzeの実行時ごとに1行のトップレベル情報が含まれます。

階層プロファイラ表DBMSHP_RUNSの主キーはRUNIDです。

表8-4 DBMSHP_RUNS表の列

列名

列のデータ型

列の内容

RUNID

NUMBER PRIMARY KEY

DBMSHP_RUNNUMBER順序から生成された、このDBMS_HPROF.analyzeの実行時の一意の識別子。

RUN_TIMESTAMP

TIMESTAMP

このDBMS_HPROF.analyzeの実行時のタイムスタンプ。

RUN_COMMENT

VARCHAR2(2047)

このDBMS_HPROF.analyzeの実行時に指定したコメント。

TOTAL_ELAPSED_TIME

INTEGER

このDBMS_HPROF.analyzeの実行時の合計経過時間。

表8-5は、階層プロファイラ表DBMSHP_FUNCTION_INFOの列を示します。この表には、このDBMS_HPROF.analyzeの実行時にプロファイリングされたサブプログラムごとに1行の情報が含まれます。サブプログラムがオーバーロードされた場合、表8-5には、このサブシステムのバリエーションごとに1行が含まれます。各バリエーションには、独自のLINE#およびHASHがあります(「オーバーロードされたサブプログラムの区別」を参照)。

階層プロファイラ表DBMSHP_FUNCTION_INFOの主キーはRUNID, SYMBOLIDです。

表8-5 DBMSHP_FUNCTION_INFO表の列

列名

列のデータ型

列の内容

RUNID

NUMBER

DBMSHP_RUNS表のRUNID列を参照します。この列の詳細は、表8-4を参照してください。

SYMBOLID

NUMBER

サブプログラムの記号識別子(このDBMS_HPROF.analyzeの実行時に固有)。

OWNER

VARCHAR2(32)

各サブプログラムが定義されているモジュールの所有者(SYSまたはHRなど)。

MODULE

VARCHAR2(2047)

サブプログラムが定義されているモジュール(DBMS_LOB、UTL_HTTPまたはMY_PACKAGEなど)。

TYPE

VARCHAR2(32)

サブプログラムが定義されているモジュールのタイプ(PACKAGE、PACKAGE_BODYまたはPROCEDUREなど)。

FUNCTION

VARCHAR2(4000)

サブプログラムの名前(必ずしも関数であるとはかぎりません)(INSERT_ORDER、PROCESS_ITEMSまたはTESTなど)。

この名前は、「特別な関数名」の1つである場合があります。

サブプログラムA内で定義されているサブプログラムBの場合、この名前はA.Bになります。

関数Xに対する再帰的コールはX@nとして表されます。nは再帰の深さです。たとえば、X@1は、Xに対する第1再帰的コールです。

LINE#

NUMBER

FUNCTIONが定義されているOWNER.MODULE内の行番号。

HASH

RAW(32)

サブプログラムのシグネチャのハッシュ・コード(このDBMS_HPROF.analyzeの実行時に固有)。

NAMESPACE

VARCHAR2(32)

サブプログラムのネームスペース。詳細は、「追跡されるサブプログラムのネームスペース」を参照してください。

SUBTREE_ELAPSED_TIME

INTEGER

子サブプログラムで費やされた時間を含む、サブプログラムの経過時間(マイクロ秒単位)。

FUNCTION_ELAPSED_TIME

INTEGER

子サブプログラムで費やされた時間を除く、サブプログラムの経過時間(マイクロ秒単位)。

CALLS

INTEGER

サブプログラムに対するコールの数。

表8-6は、階層プロファイラ表DBMSHP_PARENT_CHILD_INFOの列を示します。この表には、このDBMS_HPROF.analyzeの実行時にプロファイリングされた一意の親子サブプログラムの組合せごとに1行の親子情報が含まれます。

表8-6 DBMSHP_PARENT_CHILD_INFO表の列

列名

列のデータ型

列の内容

RUNID

NUMBER

DBMSHP_FUNCTION_INFO表のRUNID列を参照します。この列の詳細は、表8-5を参照してください。

PARENTSYMID

NUMBER

親記号ID。

RUNID、PARENTSYMIDは、DBMSHP_FUNCTION_INFO(RUNID、SYMBOLID)を参照します。

CHILDSYMID

VARCHAR2(32)

子記号ID。

RUNID、CHILDSYMIDは、DBMSHP_FUNCTION_INFO(RUNID、SYMBOLID)を参照します。

SUBTREE_ELAPSED_TIME

INTEGER

子サブプログラムで費やされた時間を含む、RUNID、PARENTSYMIDからコールされたときのRUNID、CHILDSYMIDの経過時間(マイクロ秒単位)。

FUNCTION_ELAPSED_TIME

INTEGER

子サブプログラムで費やされた時間を除く、RUNID、PARENTSYMIDからコールされたときのRUNID、CHILDSYMIDの経過時間(マイクロ秒単位)。

CALLS

INTEGER

RUNID、PARENTSYMIDからRUNID、CHILDSYMIDへのコールの数。

オーバーロードされたサブプログラムの区別

オーバーロードされたサブプログラムは、同じ名前を持つ異なるサブプログラムです(『Oracle Database PL/SQL言語リファレンス』を参照)。

プログラムによってcomputeという名前の3つのサブプログラム(1番目は50行目、2番目は76行目、3番目は100行目)が宣言されるとします。DBMSHP_FUNCTION_INFO表では、これらのサブプログラムごとにFUNCTION列にcomputeがあります。これらの3つのサブプログラムを区別するには、LINE#列(1番目のサブプログラムは50、2番目は76、3番目は100)またはHASH列(サブプログラムごとに一意の値)を使用します。

2回の異なる実行時のプロファイル・データでは、関数のLINE#およびHASH値が異なる可能性があります。関数のLINE#値は、関数定義の前で行を挿入または削除したときに変更されます。HASH値は、パラメータ・リストを変更した場合など、関数のシグネチャが変更されたときのみ変更されます。

サンプルのPL/SQLプロシージャの階層プロファイラ表

「プロファイル・データの収集」のPL/SQLプロシージャtestの階層プロファイラ表を例8-3から例8-5に示します。

例8-3 サンプルのPL/SQLプロシージャのDBMSHP_RUNS表

RUNID  RUN_TIMESTAMP                 TOTAL_ELAPSED_TIME  RUN_COMMENT
1      10-APR-06 12.01.56.766743 PM  2637                 First run of TEST

例8-4 サンプルのPL/SQLプロシージャのDBMSHP_FUNCTION_INFO表

RUNID  SYMBOLID  OWNER  MODULE      TYPE          NAMESPACE  FUNCTION
1      1                                          PLSQL      __anonymous_block
1      2                                          PLSQL      __plsql_vm
1      3         HR     TEST        PROCEDURE     PLSQL      TEST
1      4         HR     TEST        PROCEDURE     PLSQL      TEST.FOO
1      5         SYS    DBMS_HPROF  PACKAGE_BODY  PLSQL      STOP_PROFILING
1      6         HR     TEST        PROCEDURE     SQL        __static_sql_exec_line5

LINE#  CALLS  HASH              SUBTREE_ELAPSED_TIME  FUNCTION_ELAPSED_TIME
0      2      980980E97E42F8EC  2554                  342
0      2      980980E97E42F8EC  2637                  83
1      1      980980E97E42F8EC  2212                  28
3      3      980980E97E42F8EC  2184                  126
57     1      980980E97E42F8EC  0                     0
5      3      980980E97E42F8EC  1998                  1998

例8-5 サンプルのPL/SQLプロシージャのDBMSHP_PARENT_CHILD_INFO表

RUNID  PARENTSYMID  CHILDSYMID  SUBTREE_ELAPSED_TIME  FUNCTION_ELAPSED_TIME  CALLS
1      2            1           2554                   342                   2
1      1            3           2212                   28                    1
1      3            4           2184                   126                   3
1      1            5           0                      0                     1
1      4            6           1998                   1998                  3

DBMSHP_PARENT_CHILD_INFO表(例8-5)の第3行を検討してみます。RUNID列は、この行が初回実行時のものであることを示します。列PARENTSYMIDおよびCHILDSYMIDは、親(コール元)と子(コール先サブプログラム)の記号IDがそれぞれ3と4であることを示します。表DBMSHP_FUNCTION_INFO(例8-4)は、初回実行時については記号ID 3と4がそれぞれTESTとTEST.FOOに対応することを示します。このため、この行の情報は、モジュールHR.TESTにおけるプロシージャTESTからプロシージャFOO(TEST内で定義)へのコールに関するものとなります。この行は、プロシージャTESTからコールされたときのプロシージャFOOの関数時間が126マイクロ秒で、FOOサブツリーで費やされた時間(子を含む)が2184マイクロ秒であることを示します。

オプションを使用したDBMS_HPROF.analyzeのコール例

オプションを使用しないDBMS_HPROF.analyzeのコール例は、例8-2を参照してください。

例8-6では、パッケージを作成し、パッケージ内のサブプログラムを起動するプロシージャを作成し、プロシージャをプロファイリングし、RAWプロファイラ出力ファイルの分析にDBMS_HRPROF.analyzeを使用します。RAWプロファイル出力ファイルは、PLSHPROF_DIRディレクトリ・オブジェクトに対応するディレクトリにあります。

例8-6 オプションを使用したDBMS_HPROF.analyzeの起動

-- Create package

CREATE OR REPLACE PACKAGE pkg IS
PROCEDURE myproc (n IN out NUMBER);
FUNCTION myfunc (v VARCHAR2) RETURN VARCHAR2;
FUNCTION myfunc (n PLS_INTEGER) RETURN PLS_INTEGER;
END pkg;
/
CREATE OR REPLACE PACKAGE BODY pkg IS
PROCEDURE myproc (n IN OUT NUMBER) IS
BEGIN
n := n + 5;
END;

FUNCTION myfunc (v VARCHAR2) RETURN VARCHAR2 IS
n NUMBER;
BEGIN
n := LENGTH(v);
myproc(n);
IF n > 20 THEN
RETURN SUBSTR(v, 1, 20);
ELSE
RETURN v || '...';
END IF;
END;

FUNCTION myfunc (n PLS_INTEGER) RETURN PLS_INTEGER IS
i PLS_INTEGER;
PROCEDURE myproc (n IN out PLS_INTEGER) IS
BEGIN
n := n + 1;
END;
BEGIN
i := n;
myproc(i);
RETURN i;
END;
END pkg;
/

-- Create procedure that invokes package subprograms

CREATE OR REPLACE PROCEDURE test2 IS
x NUMBER := 5;
y VARCHAR2(32767);
BEGIN
pkg.myproc(x);
y := pkg.myfunc('hello');
END;

-- Profile test2

BEGIN
DBMS_HPROF.START_PROFILING('PLSHPROF_DIR', 'test2.trc');
END;
/
BEGIN
test2;
END;
/
BEGIN
DBMS_HPROF.STOP_PROFILING;
END;
/
-- If not done, create hierarchical profiler tables
-- (see "Creating Hierarchical Profiler Tables".)

-- Call DBMS_HPROF.analyze with options

DECLARE
runid NUMBER;
BEGIN
-- Analyze only subtrees rooted at trace entry "HR"."PKG"."MYPROC"

runid := DBMS_HPROF.analyze('PLSHPROF_DIR', 'test2.trc',
trace => '"HR"."PKG"."MYPROC"');

-- Analyze up to 20 calls to subtrees rooted at trace entry
-- "HR"."PKG"."MYFUNC".  Because "HR"."PKG"."MYFUNC" is overloaded,
-- both overloads are considered for analysis.

runid := DBMS_HPROF.analyze('PLSHPROF_DIR', 'test2.trc',
collect => 20,
trace => '"HR"."PKG"."MYFUNC"');

-- Analyze second call to PL/SQL virtual machine

runid := DBMS_HPROF.analyze('PLSHPROF_DIR', 'test2.trc',
skip => 1, collect => 1,
trace => '""."".""__plsql_vm"');
END;
/

plshprofユーティリティ

plshprofコマンドライン・ユーティリティ(ディレクトリ$ORACLE_HOME/bin/にあります)により、1つまたは2つのRAWプロファイラ出力ファイルから簡単なHTMLレポートが生成されます。(RAWプロファイラ出力ファイルの例は、「プロファイル・データの収集」にあるtest.trcを参照してください。)

生成されたHTMLレポートは任意のブラウザで参照できます。ブラウザのナビゲーション機能と厳選したリンクを組み合せた効率的な手段により、大規模なアプリケーションのパフォーマンスを分析し、アプリケーションのパフォーマンスを向上させ、開発コストを削減できます。

内容は次のとおりです。

- plshprofのオプション

- 単一のRAWプロファイラ出力ファイルから生成するHTMLレポート

- 2つのRAWプロファイラ出力ファイルから生成するHTML差分レポート

plshprofのオプション

plshprofユーティリティを実行するコマンドは、次のとおりです。

plshprof [option...] profiler_output_filename_1 profiler_output_filename_2

optionは、次のいずれかを使用します。

オプション

説明

デフォルト

-skip count

最初のcountコールをスキップします。-trace symbolとともにのみ使用します。

0

-collect count

countコールに関する情報を収集します。-trace symbolとともにのみ使用します。

1

-output filename

出力ファイルの名前を指定します。

symbol.htmlまたはtracefile1.html

-summary

経過時間のみを出力します。

なし

-trace symbol

ツリー・ルートの関数名を指定します。

適用なし

RAWプロファイラ出力ファイルtest.trcが現行のディレクトリ内にあるとします。また、HTMLレポートを分析および生成し、HTMLレポートのルート・ファイルの名前をreport.htmlにするとします。次のコマンドを使用します(%はプロンプトです)。

% plshprof -output report test.trc

単一のRAWプロファイラ出力ファイルから生成するHTMLレポート

単一のRAWプロファイラ出力ファイルからPL/SQL階層プロファイラのHTMLレポートを生成するには、次のコマンドを使用します。

% cd target_directory
% plshprof -output html_root_filename profiler_output_filename

target_directoryは、HTMLファイルを作成するディレクトリです。

html_root_filenameは、作成するルートHTMLファイルの名前です。

profiler_output_filenameは、RAWプロファイラ出力ファイルの名前です。

前述のplshprofコマンドにより、一連のHTMLファイルが生成されます。html_root_filename.htmlからこれらの参照を開始します。

内容は次のとおりです。

- レポートの最初のページ

- 関数レベルのレポート

- モジュール・レベルのレポート

- ネームスペース・レベルのレポート

- 関数の親子レポート

レポートの最初のページ

単一のRAWプロファイラ出力ファイルから生成するHTMLレポートの最初のページには、サマリー情報やレポートの他のページへのハイパーリンクが含まれます。

最初のページのサンプル

PL/SQLの経過時間(マイクロ秒)の分析

2831マイクロ秒(経過時間)および12のファンクション・コール

PL/SQL階層プロファイラにより、様々な形式でプロファイラの出力ログから導出された情報が示されたレポートの集合が作成されます。一般的に、最初の参照レポートとしては次のレポートが最も役に立つことがわかっています。

- サブツリーの合計経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

- 関数の合計経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

また、次のレポートも使用できます。

- 関数名別にソートした関数の経過時間(マイクロ秒)データ

- 子の合計経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

- 関数の合計コール件数別にソートした関数の経過時間(マイクロ秒)データ

- サブツリーの平均経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

- 関数の平均経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

- 子の平均経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

- 関数の合計経過時間(マイクロ秒)別にソートしたモジュールの経過時間(マイクロ秒)データ

- モジュール名別にソートしたモジュールの経過時間(マイクロ秒)データ

- 関数の合計コール件数別にソートしたモジュールの経過時間(マイクロ秒)データ

- 関数の合計経過時間(マイクロ秒)別にソートしたネームスペースの経過時間(マイクロ秒)データ

- ネームスペース別にソートしたネームスペースの経過時間(マイクロ秒)データ

- 関数の合計コール件数別にソートしたネームスペースの経過時間(マイクロ秒)データ

- 親子の経過時間(マイクロ秒)データ

関数レベルのレポート

関数レベルのレポートは、プロファイル情報のフラット・ビューを提供します。関数レベルの各レポートには、関数ごとに次の情報が含まれます。

- 関数時間(関数自体で費やされた時間で、自己時間とも呼ばれます)

- 子の時間(関数の子で費やされた時間)

- サブツリー時間(関数のサブツリーで費やされた時間: 関数時間と子の時間の合計)

- 関数に対するコールの数

- 関数名
関数名からは、関数の親子レポートへのハイパーリンクが作成されます。

関数レベルの各レポートは、関数時間またはサブツリー時間などの特定の属性によってソートされます。

次のサンプル・レポートは、関数のサブツリーの合計経過時間の降順でソートされています。「サブツリー」および「Ind%」列の情報が太字であるのはこのためです。

サンプル・レポート

サブツリーの合計経過時間(マイクロ秒)別にソートした関数の経過時間(マイクロ秒)データ

2831マイクロ秒(経過時間)および12のファンクション・コール

サブツリー

Ind%

関数

子

Ind%

コール

Ind%

関数名

2831

100%

93

2738

96.7%

2

16.7%

__plsq_vm

2738

96.7%

310

2428

85.8%

2

16.7%

__anonymous_block

2428

85.8%

15

2413

85.2%

1

8.3%

HR.TEST.TEST(1行目)

2413

85.2%

435

1978

69.9%

3

25.0%

HR.TEST.TEST.FOO(3行目)

1978

69.9%

1978

0

0.0%

3

25.0%

HR.TEST.__static_sql_exec_line5(5行目)

0

0.0%

0

0

0.0%

1

8.3%

SYS.DBMS_HPROF.STOP_PROFILING(53行目)

モジュール・レベルのレポート

モジュール・レベルの各レポートには、モジュールごとに次の情報が含まれます(パッケージまたはタイプなど)。

- モジュール時間(モジュールで費やされた時間: モジュール内のすべての関数の関数時間の合計)

- モジュール内の関数に対するコールの数

モジュール・レベルの各レポートは、モジュール時間またはモジュール名などの特定の属性によってソートされます。

次のサンプル・レポートは、モジュール時間でソートされています。「モジュール」、「Ind%」および「Cum%」列の情報が太字であるのはこのためです。

サンプル・レポート

関数の合計経過時間(マイクロ秒)別にソートしたモジュールの経過時間(マイクロ秒)データ

166878マイクロ秒(経過時間)および1099のファンクション・コール

モジュール

Ind%

Cum%

コール

Ind%

モジュール名

84932

50.9%

50.9%

6

0.5%

HR.P

67749

40.6%

91.5%

216

19.7%

SYS.DBMS_LOB

13340

8.0%

99.5%

660

60.1%

SYS.UTL_FILE

839

0.5%

100%

214

19.5%

SYS.UTL_RAW

18

0.0%

100%

2

0.2%

HR.UTILS

0

0.0%

100%

1

0.1%

SYS.DBMS_HPROF

ネームスペース・レベルのレポート

ネームスペース・レベルの各レポートには、ネームスペースごとに次の情報が含まれます。

- ネームスペース時間(ネームスペースで費やされた時間: ネームスペース内のすべての関数の関数時間の合計)

- ネームスペース内の関数に対するコールの数

ネームスペース・レベルの各レポートは、ネームスペース時間またはネームスペース内の関数に対するコールの数などの、特定の属性によってソートされます。

次のサンプル・レポートは、関数時間でソートされています。「関数」、「Ind%」および「Cum%」列の情報が太字であるのはこのためです。

サンプル・レポート

関数の合計経過時間(マイクロ秒)別にソートしたネームスペースの経過時間(マイクロ秒)データ

166878マイクロ秒(経過時間)および1099のファンクション・コール

関数

Ind%

Cum%

コール

Ind%

ネームスペース

93659

56.1%

56.1%

1095

99.6%

PLSQL

73219

43.9%

100%

4

0.4%

SQL

関数の親子レポート

親子レポートは、プロファイラによって追跡される関数ごとに、親(コール元の関数)と子(コール先の関数)に関する情報を提供します。このレポートは、親ごとに、関数の実行プロファイル(サブツリー時間、関数時間、子の時間、コール数)を提供します。また、子ごとに、この関数からコールされたときの子の実行プロファイルを提供します(ただし、他の関数からコールされたときは除きます)。

関数の実行プロファイルには、関数レベルのレポートで各関数について含まれる情報と同じ情報が含まれます(詳細は、「関数レベルのレポート」を参照)。

後述の「サンプル・レポート」は、HR.P.UPLOADという名前の関数に対応する親子レポートの断片です。最初の行には、次のサマリー情報があります。

- 関数HR.P.UPLOADに対するコールは2つあります。

- 関数の合計サブツリー時間は166,860マイクロ秒で、そのうち11,713マイクロ秒(7.0%)は関数自体、155,147マイクロ秒(93.0%)は子の時間です。

行「親」の後には、HR.P.UPLOADの2つの親の実行プロファイル行であるHR.UTILS.COPY_IMAGEとHR.UTILS.COPY_FILEがあります。

HR.UTILS.COPY_IMAGEの最初の親実行プロファイル行は、次を示しています。

- HR.UTILS.COPY_IMAGEはHR.P.UPLOADを1回コールしており、これはHR.P.UPLOADに対するコールの50%を占めます。

- HR.UTILS.COPY_IMAGEからコールされたときのHR.P.UPLOADのサブツリー時間は106,325マイクロ秒で、これはHR.P.UPLOADの合計サブツリー時間の63.7%を占めます。

- HR.UTILS.COPY_IMAGEからコールされたときのHR.P.UPLOADの関数時間は6,434マイクロ秒で、これはHR.P.UPLOADの合計関数時間の54.9%を占めます。

行「子」の後には、HR.P.UPLOADからコールされたときのHR.P.UPLOADの子の実行プロファイル行があります。

SYS.UTL_FILE.GET_RAWに対応する3番目の子の実行プロファイル行は、次を示しています。

- HR.P.UPLOADは、SYS.UTL_FILE.GET_RAWを216回コールしています。

- HR.P.UPLOADからコールされたときのSYS.UTL_FILE.GET_RAWのサブツリー時間、関数時間および子の時間はそれぞれ12,487マイクロ秒、3,969マイクロ秒および8,518マイクロ秒です。

- HR.P.UPLOADの子の合計時間(155,147マイクロ秒)のうち、子SYS.UTL_FILE.GET_RAWは12,487マイクロ秒(8.0%)を占めます。

サンプル・レポート

HR.P.UPLOAD(3行目)

サブツリー

Ind%

関数

Ind%

子

Ind%

コール

Ind%

関数名

166860

100%

11713

7.0%

155147

93.0%

2

0.2%

HR.P.UPLOAD(3行目)

親:

106325

63.7%

6434

54.9%

99891

64.4%

1

50.0%

HR.UTILS.COPY_IMAGE(3行目)

60535

36.3%

5279

45.1%

55256

35.6%

1

50.0%

HR.UTILS.COPY_FILE(8行目)

子:

71818

46.3%

71818

100%

0

N/A

2

100%

HR.P.__static_sql_exec_line38(38行目)

67649

43.6%

67649

100%

0

N/A

214

100%

SYS.DBMS_LOB.WRITEAPPEND(926行目)

12487

8.0%

3969

100%

8518

100%

216

100%

SYS.UTL_FILE.GET_RAW(1089行目)

1401

0.9%

1401

100%

0

N/A

2

100%

HR.P.__static_sql_exec_line39(39行目)

839

0.5%

839

100%

0

N/A

214

100%

SYS.UTL_FILE.GET_RAW(246行目)

740

0.5%

73

100%

667

100%

2

100%

SYS.UTL_FILE.FOPEN(422行目)

113

0.1%

11

100%

102

100%

2

100%

SYS.UTL_FILE.FCLOSE(585行目)

100

0.1%

100

100%

0

N/A

2

100%

SYS.DBMS_LOB.CREATETEMPORARY(536行目)

2つのRAWプロファイラ出力ファイルから生成するHTML差分レポート

2つのRAWプロファイラ出力ファイルからPL/SQL階層プロファイラのHTML差分レポートを生成するには、次のコマンドを使用します。

% cd target_directory
% plshprof -output html_root_filename profiler_output_filename_1 profiler_output_filename_2

target_directoryは、HTMLファイルを作成するディレクトリです。

html_root_filenameは、作成するルートHTMLファイルの名前です。

profiler_output_filename_1およびprofiler_output_filename_2は、RAWプロファイラ出力ファイルの名前です。

前述のplshprofコマンドにより、一連のHTMLファイルが生成されます。html_root_filename.htmlからこれらの参照を開始します。

内容は次のとおりです。

- 差分レポートの表記規則

- 差分レポートの最初のページ

- 関数レベルの差分レポート

- モジュール・レベルの差分レポート

- ネームスペース・レベルの差分レポート

- 関数の親子差分レポート

差分レポートの表記規則

差分レポートでは、次の表記規則が使用されます。

- レポート・タイトルでは、デルタは差分または変更を意味します。

- 正数は、初回実行時から2回目の実行時にかけて数値が増加(低下)したことを示します。

- 差分の負数は、初回実行時から2回目の実行時にかけて数値が減少(向上)したことを示します。

- 関数名の後ろの記号#は、関数が1回の実行のみでコールされたことを意味します。

差分レポートの最初のページ

2つのRAWプロファイラ出力ファイルから生成するHTML差分レポートの最初のページには、サマリー情報およびレポートの他のページへのハイパーリンクが含まれます。

最初のページのサンプル

PL/SQLの経過時間(マイクロ秒)の分析 - サマリー・ページ

この分析により、正味2709589マイクロ秒(経過時間)または80%(3393719対6103308)の回帰が判明します。これは、最も重要な7つの個別関数の回帰および向上状況をまとめたものです。

回帰: 3399382マイクロ秒(経過時間)

関数

Rel%

Ind%

コール

Rel%

関数名

2075627

+941%

61.1%

0

HR.P.G(35行目)

1101384

+54.6%

32.4%

5

+55.6%

HR.P.H(18行目)

222371

6.5%

1

HR.P.J(10行目)

向上: 689793マイクロ秒(経過時間)

関数

Rel%

Ind%

コール

Rel%

関数名

-467051

-50.0%

67.7%

-2

-50.0%

HR.P.F(25行目)

-222737

32.3%

-1

HR.P.I(2行目)#

-5

-21.7%

0.0%

0

HR.P.TEST(46行目)

PL/SQLタイミング・アナライザにより、様々な形式でプロファイラの出力ログから導出された情報が示されたレポートの集合が作成されます。一般的に、最初の参照レポートとしては次のレポートが最も役に立つことがわかっています。

- パフォーマンス回帰に関する関数の経過時間(マイクロ秒)データ

- パフォーマンス向上に関する関数の経過時間(マイクロ秒)データ

また、次のレポートも使用できます。

- 関数名別にソートした関数の経過時間(マイクロ秒)データ

- サブツリーの合計経過時間(マイクロ秒)デルタ別にソートした関数の経過時間(マイクロ秒)データ

- 関数の合計経過時間(マイクロ秒)デルタ別にソートした関数の経過時間(マイクロ秒)データ

- 子の合計経過時間(マイクロ秒)デルタ別にソートした関数の経過時間(マイクロ秒)データ

- 関数の合計コール件数デルタ別にソートした関数の経過時間(マイクロ秒)データ

- モジュール名別にソートしたモジュールの経過時間(マイクロ秒)データ

- 関数の合計経過時間(マイクロ秒)デルタ別にソートしたモジュールの経過時間(マイクロ秒)データ

- 関数の合計コール件数デルタ別にソートしたモジュールの経過時間(マイクロ秒)データ

- ネームスペース別にソートしたネームスペースの経過時間(マイクロ秒)データ

- 関数の合計経過時間(マイクロ秒)別にソートしたネームスペースの経過時間(マイクロ秒)データ

- 関数の合計コール件数別にソートしたネームスペースの経過時間(マイクロ秒)データ

- 親子のファイル経過時間(マイクロ秒)データ比較

関数レベルの差分レポート

関数レベルの各差分レポートには、各関数の、初回実行時から2回目の実行時にかけての次の値の変更が含まれます。

- 関数時間(関数自体で費やされた時間で、自己時間とも呼ばれます)

- 子の時間(関数の子で費やされた時間)

- サブツリー時間(関数のサブツリーで費やされた時間: 関数時間と子の時間の合計)

- 関数に対するコールの数

- 平均関数時間
平均関数時間は、関数時間を関数へのコール数で割った値です。

- 関数名
関数名からは、関数の親子差分レポートへのハイパーリンクが作成されます。

「サンプル・レポート1」のレポートは、2回目の実行時より初回実行時の方がパフォーマンスがよかったすべての関数に関する差分情報を示します。次のことに注意してください。

- HR.P.Gの場合、関数時間は2,075,627マイクロ秒(941%)増加し、これはすべての回帰の61.1%を占めます。

- HR.P.Hの場合、関数時間およびコール数はそれぞれ1,101,384マイクロ秒(54.6%)および5(55.6%)増加しましたが、平均関数時間は-1,346マイクロ秒(-0.6%)向上しました。

- HR.P.Jは、1回の実行でのみコールされました。

サンプル・レポート1

パフォーマンス回帰に関する関数の経過時間(マイクロ秒)データ

サブツリー

関数

Rel%

Ind%

Cum%

子

コール

Rel%

平均関数

Rel%

関数名

4075787

2075627

+941%

61.1%

61.1%

2000160

0

2075627

+941%

HR.P.G(35行目)

1101384

1101384

+54.6%

32.4%

93.5%

0

5

+55.6%

-1346

-0.6%

HR.P.H(18行目)

222371

222371

6.5%

100%

0

1

HR.P.J(10行目)#

「サンプル・レポート2」のレポートは、初回実行時より2回目の実行時の方がパフォーマンスがよかったすべての関数に関する差分情報を示します。

サンプル・レポート2

パフォーマンス向上に関する関数の経過時間(マイクロ秒)データ

サブツリー

関数

Rel%

Ind%

Cum%

子

コール

Rel%

平均関数

Rel%

関数名

-1365827

-467051

-50.0%

67.7%

67.7%

-898776

-2

-50.0%

-32

0.0%

HR.P.F(25行目)

-222737

-222737

32.3%

100%

0

-1

HR.P.I(2行目)

2709589

-5

-21.7%

0.0%

100%

2709594

0

-5

-20.8

HR.P.TEST(46行目)#

「サンプル・レポート3」のレポートには、すべての関数の差分情報をまとめます。

サンプル・レポート3

関数の合計コール件数デルタ別にソートした関数の経過時間(マイクロ秒)データ

サブツリー

関数

Rel%

Ind%

子

コール

Rel%

平均関数

Rel%

関数名

1101384

1101384

+54.6%

32.4%

0

5

+55.6%

-1346

-0.6%

HR.P.H(18行目)

-1365827

-467051

+50.0%

67.7%

-898776

-2

-50.0%

-32

-0.0%

HR.P.F(25行目)

-222377

-222377

32.3%

0

-1

HR.P.I(2行目)#

222371

222371

6.5%

0

1

HR.P.J(10行目)#

4075787

2075627

+941%

61.1%

2000160

0

2075627

+941%

HR.P.G(35行目)

2709589

-5

-21.7%

0.0%

2709594

0

-5

-20.8%

HR.P.TEST(46行目)

0

0

0

0

SYS.DBMS_HPROF.STOP_PROFILING(53行目)

モジュール・レベルの差分レポート

モジュール・レベルの各レポートには、各モジュールの、初回実行時から2回目の実行時にかけての次の値の変更が含まれます。

- モジュール時間(モジュールで費やされた時間: モジュール内のすべての関数の関数時間の合計)

- モジュール内の関数に対するコールの数

サンプル・レポート

関数の合計経過時間(マイクロ秒)デルタ別にソートしたモジュールの経過時間(マイクロ秒)データ

モジュール

コール

モジュール名

2709589

3

HR.P

0

0

SYS.DBMS_HPROF

ネームスペース・レベルの差分レポート

ネームスペース・レベルの各レポートには、各ネームスペースの、初回実行時から2回目の実行時にかけての次の値の変更が含まれます。

- ネームスペース時間(ネームスペースで費やされた時間: ネームスペース内のすべての関数の関数時間の合計)

- ネームスペース内の関数に対するコールの数

サンプル・レポート

ネームスペース別にソートしたネームスペースの経過時間(マイクロ秒)データ

関数

コール

ネームスペース

2709589

3

PLSQL

関数の親子差分レポート

関数の親子差分レポートは、初回実行時から2回目の実行時にかけての次の実行プロファイルの変更を示します。

- 親(関数のコール元の関数)

- 子(関数のコール先の関数)
子の実行プロファイルには、他の関数によってこれらがコールされたときではなく、この関数によってこれらがコールされたときの情報のみが含まれます。

関数の実行プロファイルには、次の情報が含まれます。

- 関数時間(関数自体で費やされた時間で、自己時間とも呼ばれます)

- 子の時間(関数の子で費やされた時間)

- サブツリー時間(関数のサブツリーで費やされた時間: 関数時間と子の時間の合計)

- 関数に対するコールの数

- 関数名

サンプル・レポートは、HR.P.Xという名前の関数に対応する親子差分レポートの断片です。

初回実行時と2回目の実行時の差分のサマリーである最初の行は、回帰を示します。関数時間は1,094,099マイクロ秒増加しています(おそらく、関数が5回余計にコールされたことが原因です)。

「親」行は、HR.P.GによってHR.P.Xが初回実行時より2回目の実行時の方が9回多くコールされたが、HR.P.Fによっては4回少なくコールされたことを示しています。

「子」行は、HR.P.Xによって各子が初回実行時より2回目の実行時の方が5回多くコールされたことを示しています。

サンプル・レポート

HR.P.X(11行目)

サブツリー

関数

子

コール

関数名

3322196

1094099

2228097

5

HR.P.X(11行目)

親:

6037490

1993169

4044321

9

HR.P.G(38行目)

-2715294

-899070

-1816224

-4

HR.P.F(28行目)

子:

1125489

1125489

0

5

HR.P.J(10行目)

1102608

1102608

0

5

HR.P.I(2行目)

関数の親子差分レポートには、関数比較レポートが付随しています。このレポートは、関数の初回実行時と2回目の実行時およびこれらの差分に関する実行プロファイルを示します。次の例は、関数HR.P.Xの関数比較レポートです。

サンプル・レポート

HR.P.X(11行目)の経過時間(マイクロ秒)(回帰合計の20.1%)

HR.P.X(11行目)

初回トレース

Ind%

2回目のトレース

Ind%

差分

Diff%

関数の経過時間(マイクロ秒)

1999509

26.9%

3093608

24.9%

1094099

+54.7%

子の経過時間(マイクロ秒)

4095943

55.1%

6324040

50.9%

2228097

+54.4%

サブツリーの経過時間(マイクロ秒)

6095452

81.9%

9417648

75.7%

3322196

+54.5%

ファンクション・コール

9

25.0%

14

28.6%

5

+55.6%

関数の平均経過時間(マイクロ秒)

222167.7

220972.0

-1195.7

-0.5%

子の平均経過時間(マイクロ秒)

455104.8

451717.1

-3387.6

-0.7%

サブツリーの平均経過時間(マイクロ秒)

677272.4

672689.1

-4583.3

-0.7%

9 PL/SQL Webアプリケーションの開発

この章では、データベースをイントラネットで利用可能にする、PL/SQL Webアプリケーションの開発方法について説明します。

内容は次のとおりです。

- PL/SQL Webアプリケーションの概要

- PL/SQL Webアプリケーションの実装

- mod_plsqlゲートウェイを使用したクライアント・リクエストのPL/SQL Webアプリケーションへのマップ

- 埋込みPL/SQLゲートウェイの使用

- PL/SQLを使用したHTML出力の生成

- PL/SQL Webアプリケーションへのパラメータ渡し

- PL/SQLサブプログラムでのネットワーク操作の実行

PL/SQL Webアプリケーションの概要

一般的に、PL/SQLで作成されるWebアプリケーションは、HTTPを介してWebブラウザと対話するストアド・サブプログラムの集合です。相互リンクされた一連の動的に作成されたHTMLページが、Webアプリケーションのユーザー・インタフェースになります。

PL/SQL Webアプリケーションのプログラム・フローは、CGI PERLスクリプトのプログラム・フローに似ています。通常、開発者はCGIスクリプトを使用してWebページを動的に作成しますが、多くの場合それらのスクリプトはデータベースへのアクセスに適していません。PL/SQLストアド・サブプログラムでWebコンテンツを配信することによって、強力で柔軟なデータベース処理が実現されます。たとえば、データ操作言語(DML)、動的SQL文およびカーソルを使用できます。また、各HTTPリクエストを処理するために新しいCGIプロセスを指定する際のプロセス・オーバーヘッドが発生しなくなります。

図9-1に、PL/SQL Webアプリケーションの一般的なプロセスを示します。

図9-1 PL/SQL Webアプリケーション

PL/SQL Webアプリケーションの実装

Webブラウザベースのアプリケーションは、次のOracle Databaseコンポーネントを使用して、PL/SQLで完全に実装できます。

- PL/SQLゲートウェイ

- PL/SQL Web Toolkit

PL/SQLゲートウェイ

PL/SQLゲートウェイは、WebブラウザがHTTPリスナーを介してPL/SQLストアド・サブプログラムを起動するのを可能にします。ゲートウェイとは、PL/SQLユーザーがPL/SQL Webアプリケーションを開発およびデプロイするプラットフォームのことです。

mod_plsql

mod_plsqlは、PL/SQLゲートウェイの実装の一例です。モジュールとはOracle HTTP Serverのプラグインのことで、WebブラウザがPL/SQLストアド・サブプログラムを起動するのを可能にします。Oracle HTTP Serverは、Oracle Application ServerおよびOracle Databaseのコンポートネントです。

mod_plsqlプラグインを使用すると、PL/SQLストアド・サブプログラムを使用して、HTTPリクエストを処理し、レスポンスを作成できます。このコンテキストでは、HTTPリクエストはストアド・サブプログラムに渡されるパラメータ値を含むURLです。PL/SQLゲートウェイではURLを変換し、そのパラメータでストアド・サブプログラムを起動し、クライアントに出力(通常はHTML)を戻します。

PL/SQLゲートウェイの埋込み形式と比較して、mod_plsqlを使用することのメリットには、次のものがあります。

- ファイアウォール環境で実行できます。この環境では、Oracle HTTP Serverがファイアウォールに対応するホスト上で実行され、データベースはファイアウォールの内側にホストされます。埋込みゲートウェイではこの構成を使用できません。

- 埋込みゲートウェイは、動的HTMLキャッシュ、システム監視、共通ログ形式でのロギングなどのmod_plsql機能をサポートしていません。

埋込みPL/SQLゲートウェイ

データベースのXML DB HTTP Listenerで稼働するPL/SQLゲートウェイの埋込みバージョンを使用できます。これにより、mod_plsqlのコア機能がデータベースに提供されますが、Oracle HTTP Serverは必要ありません。PL/SQL Web ToolkitにあるDBMS_EPGパッケージを使用して埋込みPL/SQLゲートウェイを構成します。

mod_plsqlと比較して、埋込みゲートウェイを使用することのメリットには次のものがあります。

- Oracle HTTP ServerをインストールせずにApplication ExpressなどのPL/SQL Webアプリケーションを起動できるため、PL/SQLベースのWebアプリケーションのインストール、構成および管理を簡素化できます。

- 使用されているものと同じ構成手法を使用して、FTPリクエストおよびHTTPリクエストに応じて、Oracle XML DBからコンテンツを提供します。

PL/SQL Web Toolkit

このPL/SQLパッケージのセットは、実行時にmod_plsqlによって起動されるストアド・サブプログラムを使用可能にする汎用インタフェースです。

ブラウザのリクエストに対するレスポンスで、PL/SQLサブプログラムはユーザー入力に従ってOracle Databaseのデータを更新または取得します。続いて、ストアド・プロシージャはブラウザに対するHTTPレスポンスを生成します。通常はダウンロード・ファイルまたはHTML表示になります。PL/SQL Web Toolkit APIを使用すると、ストアド・サブプログラムで次のような処理を実行できます。

- HTTPリクエストの情報の取得

- コンテンツタイプおよびMIMEタイプなどのHTTPヘッダーの生成

- ブラウザのCookieの設定

- HTMLページの生成

表9-1に、一般的に使用されるPL/SQL Toolkitパッケージを示します。

表9-1 PL/SQL Web Toolkitで一般的に使用されるパッケージ

パッケージ

内容の説明

HTF

htpパッケージ内のサブプログラムのファンクション・バージョン。ファンクション・バージョンでは、出力がWebページに直接生成されません。かわりに、出力が戻り値として、ファンクションを起動する文に渡されます。ファンクション・コールをネストする必要がある場合、これらのファンクションを使用します。

HTP

HTMLタグを生成するサブプログラム。たとえば、プロシージャhtp.anchorでは、HTMLアンカー・タグ<A>が生成されます。

OWA_CACHE

PL/SQLゲートウェイのキャッシュ機能を使用可能にし、PL/SQL Webアプリケーションのパフォーマンスを向上させるサブプログラム。

このパッケージを使用して、PL/SQLゲートウェイ・ファイル・システムを使用した期限切れベースおよび検証ベースのキャッシュを使用可能にできます。

OWA_COOKIE

クライアントWebブラウザとの間でHTTP Cookieを送受信するサブプログラム。Cookieは、HTTPコール間で状態を保持するためにブラウザで使用される文字列です。状態を保持できるのは、クライアント・セッションの終わりまでか、Cookieの期日が含まれる場合はそれ以上の期間です。

OWA_CUSTOM

Cookieで使用される権限ファンクション。

OWA_IMAGE

ユーザーがイメージをクリックした座標を取得するサブプログラム。宛先リンクによりPL/SQLゲートウェイが起動されるイメージ・マップがある場合、このパッケージを使用します。

OWA_OPT_LOCK

更新内容が失われるのを防ぐために、データベース・コミット時ロック方法を強制実行するサブプログラム。このサブプログラムを使用しないと、あるユーザーが、それまでに別のユーザーによって値が変更されている行を選択して更新しようとした場合、更新内容が失われる場合があります。

OWA_PATTERN

正規表現により、文字列一致検索および文字列操作を実行するサブプログラム。

OWA_SEC

PL/SQLゲートウェイでリクエストの認証に使用されるサブプログラム。

OWA_TEXT

OWA_PATTERNパッケージで文字列の操作に使用されるサブプログラム。直接使用することもできます。

OWA_UTIL

次のタイプのユーティリティ・サブプログラム

- 動的に生成されたSQLコードによりページを生成する動的SQLユーティリティ。

- CGI環境変数の値を取得し、URLリダイレクトを実行するHTMLユーティリティ。

- 正しい日付処理を行うための日付ユーティリティ。日付の値はHTMLでは単純な文字列ですが、Oracle Databaseデータ型として適切に処理される必要があります。

WPG_DOCLOAD

DAD構成を使用して定義したドキュメント・リポジトリからドキュメントをダウンロードするサブプログラム。

参照:
PL/SQL Web Toolkitパッケージの構文、説明および例は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

mod_plsqlゲートウェイを使用したクライアント・リクエストのPL/SQL Webアプリケーションへのマップ

『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』で説明しているように、mod_plsqlは、HTTP上でWebクライアント・リクエストをPL/SQLストアド・サブプログラムにマップします。詳細は、このマニュアルを参照してください。

参照:

- mod_plsqlの構成および使用方法については、『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』を参照してください。

- mod_plsqlモジュールの詳細は、『Oracle Fusion Middleware Oracle HTTP Server管理者ガイド』を参照してください。

埋込みPL/SQLゲートウェイの使用

埋込みゲートウェイ機能は、mod_plsqlゲートウェイに類似しています。ゲートウェイの埋込みバージョンを使用する前に、『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』を参照して熟知しておいてください。情報の大部分が同一のもの、あるいは類似したものです。

内容は次のとおりです。

- 埋込みPL/SQLゲートウェイによるクライアント・リクエストの処理方法

- 埋込みPL/SQLゲートウェイのインストール

- 埋込みPL/SQLゲートウェイの構成

- 埋込みPL/SQLゲートウェイを介したPL/SQLストアド・サブプログラムの起動

- 埋込みPL/SQLゲートウェイによるアプリケーション・アクセスの保護

- 埋込みPL/SQLゲートウェイの制限事項

- 埋込みPL/SQLゲートウェイの使用: 使用例

埋込みPL/SQLゲートウェイによるクライアント・リクエストの処理方法

図9-2に、埋込みゲートウェイによるクライアントHTTPリクエストの処理プロセスを示します。

図9-2 埋込みPL/SQLゲートウェイによるクライアント・リクエストの処理

図9-2の各ステップの内容は次のとおりです。

1. Oracle XML DB HTTP Listenerは、クライアント・ブラウザからのリクエストを受け取り、PL/SQLサブプログラムを起動するようリクエストします。サブプログラムは、PL/SQLに直接記述されたもの、またはPL/SQL Server Pagesがデータベースにアップロードされ、コンパイルされたときに間接的に生成されたものを使用できます。

2. XML DB HTTP Listenerは、その仮想パス・マッピング構成に指定されているとおり、埋込みPL/SQLゲートウェイにリクエストをルーティングします。

3. 埋込みゲートウェイではHTTPリクエスト情報およびゲートウェイ構成を使用して、認証にどのデータベース・アカウントを使用するかを決定します。

4. 埋込みゲートウェイはコール・パラメータを準備して、アプリケーション内でPL/SQLサブプログラムを起動します。

5. PL/SQLサブプログラムは、リレーショナル・データおよびデータベースからアクセスされたPL/SQL Web ToolkitからHTMLページを生成します。

6. アプリケーションから埋込みゲートウェイにページを送信します。

7. 埋込みゲートウェイからXML DB HTTP Listenerにページを送信します。

8. XML DB HTTP Listenerからクライアント・ブラウザにページを送信します。

mod_plsqlとは異なり、埋込みゲートウェイはOracle XML DB HTTP Listenerを使用してHTTPリクエストを処理します。このリスナーは、Oracle Net Listenerと同じサーバー側プロセスであり、Oracle Net Services、HTTPおよびFTPをサポートします。

XML DBインタフェースを介して一般HTTPリスナー設定を構成します(手順については、『Oracle XML DB開発者ガイド』を参照してください)。Oracle Enterprise Managerを使用するか、xdbconfig.xmlファイルを編集してHTTPリスナーを構成します。DADの属性の作成または設定など、すべての埋込みPL/SQLゲートウェイ構成で、DBMS_EPGパッケージを使用します。

埋込みPL/SQLゲートウェイのインストール

埋込みゲートウェイでは次のコンポーネントが必要です。

- XML DB HTTP Listener

- PL/SQL Web Toolkit

埋込みPL/SQLゲートウェイは、Oracle XML DBの一部としてインストールします。インストール時、またはDatabase Configuration Assistant(DBCA)によって作成された事前構成済データベースを使用している場合、Oracle XML DBがインストールされ、構成されます。既存のデータベースへのOracle XML DBの手動による追加については、『Oracle XML DB開発者ガイド』を参照してください。

PL/SQL Web Toolkitはデータベースの標準インストールの一部であるため、追加でインストールする必要はありません。

埋込みPL/SQLゲートウェイの構成

Oracle HTTP Serverの構成ファイルを編集して、mod_plsqlを構成します。埋込みゲートウェイはOracle XML DB HTTP Listenerの一部としてインストールするため、Oracle XML DBサーブレット管理インタフェースを介してサーブレットとして管理します。

埋込みゲートウェイへの構成インタフェースは、PL/SQLパッケージDBMS_EPGです。このパッケージは、XML DBで使用される、基礎となるxdbconfig.xml構成ファイルを変更します。ほとんどのユーザーにとって、埋込みゲートウェイ構成パラメータはデフォルト値で問題ありません。

内容は次のとおりです。

- 埋込みPL/SQLゲートウェイの構成: 概要

- 埋込みPL/SQLゲートウェイのユーザー認証に関する構成

埋込みPL/SQLゲートウェイの構成: 概要

mod_plsqlと同様、PL/SQLストアド・サブプログラムの各リクエストは、データベース・アクセス記述子(DAD)に関連付けられています。DADとは、データベース・アクセスに使用する構成値の集合です。DADでは次のような情報を指定します。

- 認証に使用するデータベース・アカウント

- ドキュメントのアップロードおよびダウンロードに使用するサブプログラム

埋込みPL/SQLゲートウェイでは、DADは、XML DB HTTP LISTENER構成のサーブレットとして表されます。各DAD属性は、構成ファイルxdbconfig.xmlのXML要素にマップされます。DAD属性の値は、要素の内容に一致します。たとえば、database-username DAD属性は、<database-username> XML要素に一致し、DAD属性の値がHRである場合、<database-username>HR<database-username>に一致します。DAD属性名は、大/小文字を区別します。

次の埋込みPL/SQLゲートウェイ構成を実行するには、DBMS_EPGパッケージを使用します。

1. DBMS_EPG.CREATE_DADプロシージャを使用してDADを作成します。

2. DBMS_EPG.SET_DAD_ATTRIBUTEプロシージャを使用してDAD属性を設定します。
すべてのDAD属性は、オプションです。属性を指定しない場合は、初期値が使用されます。

表9-2に、埋込みPL/SQLゲートウェイ属性および対応するmod_plsql DADパラメータを示します。「有効な値」の列挙値は大/小文字を区別します。

表9-2 mod_plsqlと埋込みPL/SQLゲートウェイDAD属性間のマッピング

mod_plsql DAD属性

埋込みPL/SQLゲートウェイDAD属性

重複

有効な値

PlsqlAfterProcedure

after-procedure

なし

文字列

PlsqlAlwaysDescribeProcedure

always-describe-procedure

なし

On、Offの列挙

PlsqlAuthenticationMode

authentication-mode

なし

Basic、SingleSignOn、GlobalOwa、CustomOwa、PerPackageOwaの列挙

PlsqlBeforeProcedure

before-procedure

なし

文字列

PlsqlBindBucketLengths

bind-bucket-lengths

あり

符号なしの整数

PlsqlBindBucketWidths

bind-bucket-widths

あり

符号なしの整数

PlsqlCGIEnvironmentList

cgi-environment-list

あり

文字列

PlsqlCompatibilityMode

compatibility-mode

なし

符号なしの整数

PlsqlDatabaseUsername

database-username

なし

文字列

PlsqlDefaultPage

default-page

なし

文字列

PlsqlDocumentPath

document-path

なし

文字列

PlsqlDocumentProcedure

document-procedure

なし

文字列

PlsqlDocumentTablename

document-table-name

なし

文字列

PlsqlErrorStyle

error-style

なし

ApacheStyle、ModplsqlStyle、DebugStyleの列挙

PlsqlExclusionList

exclusion-list

あり

文字列

PlsqlFetchBufferSize

fetch-buffer-size

なし

符号なしの整数

PlsqlInfoLogging

info-logging

なし

InfoDebugの列挙

PlsqlInputFilterEnable

input-filter-enable

なし

文字列

PlsqlMaxRequestsPerSession

max-requests-per-session

なし

符号なしの整数

PlsqlNLSLanguage

nls-language

なし

文字列

PlsqlOWADebugEnable

owa-debug-enable

なし

On、Offの列挙

PlsqlPathAlias

path-alias

なし

文字列

PlsqlPathAliasProcedure

path-alias-procedure

なし

文字列

PlsqlRequestValidationFunction

request-validation-function

なし

文字列

PlsqlSessionCookieName

session-cookie-name

なし

文字列

PlsqlSessionStateManagement

session-state-management

なし

StatelessWithResetPackageState、StatelessWithFastRestPackageState、StatelessWithPreservePackageStateの列挙

PlsqlTransferMode

transfer-mode

なし

Char、Rawの列挙

PlsqlUploadAsLongRaw

upload-as-long-raw

なし

文字列

埋込みゲートウェイのほとんどのユーザーにとって、DAD属性はデフォルト値で問題ありません。mod_plsqlユーザーには、次の属性は不要です。

- PlsqlDatabasePassword

- PlsqlDatabaseConnectString(埋込みゲートウェイで外部データベースへのログオンがサポートされていないため)

DAD属性と同様、グローバル構成パラメータはオプションです。表9-3に、DBMS_EPGグローバル属性および対応するmod_plsqlグローバル・パラメータを示します。

表9-3 mod_plsqlと埋込みPL/SQLゲートウェイ・グローバル属性間のマッピング

mod_plsql DAD属性

埋込みPL/SQLゲートウェイDAD属性

重複

有効な値

PlsqlLogLevel

log-level

なし

符号なしの整数

PlsqlMaxParameters

max-parameters

なし

符号なしの整数

参照:

- mod_plsql DAD属性の詳細は、『Oracle Fusion Middleware Oracle HTTP Server管理者ガイド』を参照してください。デフォルト値と使用上の注意事項については、このマニュアルを参照してください。

- DBMS_EPGパッケージについては、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- xdbconfig.xmlファイルのアカウントについては、『Oracle XML DB開発者ガイド』を参照してください。

埋込みPL/SQLゲートウェイのユーザー認証に関する構成

XML DB認証スキームを使用するため、埋込みゲートウェイではデータベースの認証方式がmod_plsqlとは異なります。特に、DADにはデータベースのパスワードは格納されません。

注意:
PL/SQL Webアプリケーションをインターネット上で提供しても、データベースをファイアウォールの内側に保持する場合は、アプリケーションの実行に埋込みPL/SQLゲートウェイを使用せずに、mod_plsqlを使用してください。

データベース認証を構成するには、DBMS_EPGパッケージを使用します。

内容は次のとおりです。

- DBMS_EPGによる静的認証の構成

- DBMS_EPGによる動的認証の構成

- DBMS_EPGによる匿名認証の構成

- DADの認証モードの決定

- DADの作成および構成: 例

- DADの認証モードの決定: 例

- すべてのDADの認証モードの決定: 例

- 無効なDAD認可の表示: 例

- 埋込みPL/SQLゲートウェイ構成の調査

DBMS_EPGによる静的認証の構成

静的認証はデータベースのユーザー名およびパスワードをDADに格納するmod_plsqlユーザー用であるため、ブラウザ・ユーザーがデータベース認証情報を入力する必要はありません。

静的認証を設定する手順は次のとおりです。

1. XML DB管理者、つまりXDBADMINのロールが割り当てられたユーザーとしてデータベースにログオンします。

2. DADを作成します。たとえば、次のプロシージャでは、DADによって起動されるHR_DADを作成し、仮想パスを/hrweb/にマップします。

EXEC DBMS_EPG.CREATE_DAD('HR_DAD', '/hrweb/*');

3. この手順では、ALTER ANY USERシステム権限が必要です。DADにより権限が使用される必要があるデータベース・アカウントに、DAD属性database-usernameを設定します。たとえば、次のプロシージャでは、DAD名HR_DADがHRアカウントの権限を保持すると指定します。

EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('HR_DAD', 'database-username', 'HR');

DAD属性database-usernameは、大/小文字を区別します。

4. 前の手順でユーザーが指定したデータベースの権限をDADに割り当てます。この認可によって、エンド・ユーザーはプロシージャを起動し、認可されたアカウントの権限のある埋込みPL/SQLゲートウェイを介してドキュメント表にアクセスできます。次に例を示します。

EXEC DBMS_EPG.AUTHORIZE_DAD('HR_DAD', 'HR');

あるいは、XDBADMIN権限のあるユーザーとしてログオフし、その権限がDADで使用される必要があるデータベース・ユーザーとしてログオンしてから、これらの権限をDADに割り当てる次のコマンドを使用します。

EXEC DBMS_EPG.AUTHORIZE_DAD('HR_DAD');

注意:
複数のユーザーが同一のDADを認可できます。DADのdatabase-username属性設定によって、どのユーザーの権限を使用するかが決定されます。

mod_plsqlとは異なり、埋込みゲートウェイは特殊ユーザーANONYMOUSとしてデータベースに接続しますが、データベース・オブジェクトにはDADに割り当てられたユーザー権限でアクセスします。ブラウザ・ユーザーがHTTP Authorizationヘッダーで明示的に接続しようとすると、データベースはアクセスを拒否します。

注意:
アカウントANONYMOUSは、XML DBのインストール後にロックされます。埋込みPL/SQLゲートウェイで静的認証を使用する場合は、最初にこのアカウントのロックを解除します。

DBMS_EPGによる動的認証の構成

動的認証は、DADにデータベースのユーザー名およびパスワードを格納しないmod_plsqlユーザーのためのものです。

動的認証では、データベース・ユーザーは、データベース・オブジェクトへのアクセス権限を使用するため、埋込みゲートウェイを認可する必要がありません。かわりに、ブラウザ・ユーザーがHTTP Basic認証スキーマを介してデータベース認証情報を指定する必要があります。

埋込みゲートウェイのアクションは、DADに対してdatabase-username属性が設定されているかどうかによって異なります。この属性が設定されていない場合、埋込みゲートウェイはブラウザ・クライアントによって指定されたユーザーとして、データベースに接続します。属性が設定されている場合、データベースでは、database-username属性で指定されたユーザーにアクセスを制限します。

動的認証を設定する手順は次のとおりです。

1. XML DB管理者、つまりXDBADMINのロールのあるユーザーとしてデータベースにログオンします。

2. DADを作成します。たとえば、次のプロシージャでは、DADによって起動されるDYNAMIC_DADを作成し、仮想パスを/hrweb/にマップします。

EXEC DBMS_EPG.CREATE_DAD('DYNAMIC_DAD', '/hrweb/*');

3. オプションで、DADにより権限が使用される必要があるデータベース・アカウントに、DAD属性database-usernameを設定します。ブラウザ・ユーザーはDADアクセスの際、このアカウントのユーザー名およびパスワードを入力するよう要求されます。たとえば、次のプロシージャでは、DAD名DYNAMIC_DADがHRアカウントの権限を保持すると指定します。

EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('DYNAMIC_DAD', 'database-username', 'HR');

属性database-usernameは、大/小文字を区別します。

警告:

HTTP Basic認証スキームを介して送信されるパスワードは、暗号化されていません。ブラウザ・クライアントによって送信されるパスワードを保護するため、HTTPSプロトコルを使用するよう埋込みゲートウェイを構成します。

DBMS_EPGによる匿名認証の構成

匿名認証はmod_plsqlユーザー用であり、このユーザーはデータベース・ログオン用の特殊なDADデータベースを作成しますが、アプリケーション・プロシージャおよびドキュメント表を別のスキーマに格納し、プロシージャおよびドキュメント表へのアクセス権をPUBLICに付与します。

匿名認証を設定する手順は次のとおりです。

1. XML DB管理者、つまりXDBADMINのロールが割り当てられたユーザーとしてデータベースにログオンします。

2. DADを作成します。たとえば、次のプロシージャでは、DADによって起動されるHR_DADを作成し、仮想パスを/hrweb/にマップします。

EXEC DBMS_EPG.CREATE_DAD('HR_DAD', '/hrweb/*');

3. DAD属性database-usernameをANONYMOUSに設定します。次に例を示します。

EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('HR_DAD', 'database-username', 'ANONYMOUS');

database-usernameおよびANONYMOUSはともに、大/小文字を区別します。

データベース・オブジェクトへのアクセス用ANONYMOUS権限の使用のために埋込みゲートウェイを認可する必要はありません。ANONYMOUSにはシステム権限がなく、データベース・オブジェクトを所有していません。

DADの認証モードの決定

DADの名前がわかっている場合は、このDADの認証モードは次によって決まります。

- DADが存在するかどうか。

- database-username属性がDAD用に設定されているかどうか。

- DADにdatabase-usernameユーザーの権限の使用が認可されているかどうか。

- database-username属性がDADの使用を認可されているユーザーの名前であるかどうか。

表9-4に、これらの質問の回答に応じた認証モードの決定方法を示します。

表9-4 DADの認証の可能性

DADの有無

database-username設定の有無

ユーザー認可の有無

モード

あり

あり

あり

静的

あり

あり

なし

動的(制限付き)

あり

なし

関連なし

動的

あり

あり(ANONYMOUSに対して)

関連なし

匿名

なし

N/A

たとえば、DAD名MY_DADを作成するとします。MY_DADのdatabase-username属性がHRに設定されていても、HRユーザーがMY_DADを認可しない場合、MY_DADの認証モードは制限付きで動的になります。ブラウザ・ユーザーがMY_DADを介してPL/SQLサブプログラムを実行しようとすると、HRデータベースのユーザー名およびパスワードを入力するよう要求されます。

DBA_EPG_DAD_AUTHORIZATIONビューでは、どのユーザーがDADの使用を認可しているかを示します。DAD_NAME列にはDADの名前が表示され、USERNAME列にはDADに権限が割り当てられたユーザーが表示されます。権限が認められたDADは存在しないことがあります。

参照:
DBA_EPG_DAD_AUTHORIZATIONビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

DADの作成および構成: 例

例9-1では次の処理が行われます。

- データベース・ユーザーHR用に静的認証のDADを作成し、これを認可するHRアカウントの権限を割り当てます。

- ユーザーを限定しない、動的認証のDADを作成します。

- HRアカウントに限定される、動的認証のDADを作成します。

例9-1 DADの作成および構成

------------------------------------------------------------------------
--- DAD with static authentication
------------------------------------------------------------------------

CONNECT SYSTEM AS SYSDBA
PASSWORD: password
EXEC DBMS_EPG.CREATE_DAD('Static_Auth_DAD', '/static/*');
EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('Static_Auth_DAD', 'database-username', 'HR');
GRANT EXECUTE ON DBMS_EPG TO HR;

-- Authorization
CONNECT HR
PASSWORD: password
EXEC DBMS_EPG.AUTHORIZE_DAD('Static_Auth_DAD');

------------------------------------------------------------------------
-- DAD with dynamic authentication
------------------------------------------------------------------------

CONNECT SYSTEM AS SYSDBA
PASSWORD: password
EXEC DBMS_EPG.CREATE_DAD('Dynamic_Auth_DAD', '/dynamic/*');

-------------------------------------------------------------------------
-- DAD with dynamic authentication restricted
-------------------------------------------------------------------------

EXEC DBMS_EPG.CREATE_DAD('Dynamic_Auth_DAD_Restricted', '/dynamic/*');
EXEC DBMS_EPG.SET_DAD_ATTRIBUTE
('Dynamic_Auth_DAD_Restricted', 'database-username', 'HR');

DADの作成および認証は独立しているため、次のことができます。

- 存在していないDADの認証(後で作成が可能)

- 自分がユーザーでないDADの認証(ただし、この認証はDAD database-user属性が自分のユーザー名に変更されるまで反映されません)

例9-2では、データベース・ユーザーHR用に静的認証のDADを作成し、これにHRアカウントの権限を割り当てます。その後、次の処理が行われます。

- データベース・ユーザーHRがそのDADではなく、存在しないDADを認証します。
ユーザーが誤ってこれを実行した場合でも、存在しないDADは後で作成できるため、エラーは発生しません。

- データベース・ユーザーOEが、自分のdatabase-user属性がHRに設定されているDADを認証します。
エラーは発生しませんが、DADのdatabase-user属性がOEに変更されるまで認証は有効になりません。

例9-2 後で作成または変更されるDADの認証

REM Create DAD with static authentication for database user HR

CONNECT SYSTEM AS SYSDBA
PASSWORD: password
EXEC DBMS_EPG.CREATE_DAD('Static_Auth_DAD', '/static/*');
EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('Static_Auth_DAD', 'database-username', 'HR');
GRANT EXECUTE ON DBMS_EPG TO HR;

REM Database user HR authorizes DAD that does not exist

CONNECT HR
PASSWORD: password
EXEC DBMS_EPG.AUTHORIZE_DAD('Static_Auth_DAD_Typo');

REM Database user OE authorizes DAD with database-username 'HR'

CONNECT OE
PASSWORD: password
EXEC DBMS_EPG.AUTHORIZE_DAD('Static_Auth_DAD');

DADの認証モードの決定: 例

例9-3では、指定されたDADの名称を許容し、その認証モードをレポートするPL/SQLプロシージャshow_dad_auth_statusを作成します。指定したDADが存在しない場合、プロシージャはエラー状態で終了します。

例9-3 DADの認証モードの決定

CREATE OR REPLACE PROCEDURE show_dad_auth_status (p_dadname VARCHAR2) IS
v_daduser VARCHAR2(32);
v_cnt     PLS_INTEGER;
BEGIN
-- Determine DAD user
v_daduser := DBMS_EPG.GET_DAD_ATTRIBUTE(p_dadname, 'database-username');

-- Determine whether DAD authorization exists for DAD user
SELECT COUNT(*)
INTO v_cnt
FROM DBA_EPG_DAD_AUTHORIZATION da
WHERE da.DAD_NAME = p_dadname
AND da.USERNAME = v_daduser;

-- If DAD authorization exists for DAD user, authentication mode is static
IF (v_cnt > 0) THEN
DBMS_OUTPUT.PUT_LINE (
'''' || p_dadname ||
''' is set up for static authentication for user ''' ||
v_daduser || '''.');
RETURN;
END IF;

-- If no DAD authorization exists for DAD user, authentication mode is dynamic

-- Determine whether dynamic authentication is restricted to particular user
IF (v_daduser IS NOT NULL) THEN
DBMS_OUTPUT.PUT_LINE (
'''' || p_dadname ||
''' is set up for dynamic authentication for user ''' ||
v_daduser || ''' only.');
ELSE
DBMS_OUTPUT.PUT_LINE (
'''' || p_dadname ||
''' is set up for dynamic authentication for any user.');
END IF;
END;
/

例9-1のスクリプトを実行して、各種DADを作成および構成するとします。出力は次のとおりです。

SET SERVEROUTPUT ON;
BEGIN
show_dad_auth_status('Static_Auth_DAD');
END;
/
'Static_Auth_DAD' is set up for static authentication for user 'HR'.

すべてのDADの認証モードの決定: 例

例9-4の無名ブロックでは、登録したすべてのDADの認証モードがレポートされます。これによって、例9-3のshow_dad_auth_statusプロシージャが起動されます。

例9-4 全DADの認証モードの表示

DECLARE
v_dad_names DBMS_EPG.VARCHAR2_TABLE;
BEGIN
DBMS_OUTPUT.PUT_LINE
('---------- Authorization Status for All DADs ----------');
DBMS_EPG.GET_DAD_LIST(v_dad_names);

FOR i IN 1..v_dad_names.count LOOP
show_dad_auth_status(v_dad_names(i));
END LOOP;
END;
/

例9-1のスクリプトを実行して各種DADを作成および構成した場合、例9-4の出力は次のとおりです。

---------- Authorization Status for All DADs ----------
'Static_Auth_DAD' is set up for static auth for user 'HR'.
'Dynamic_Auth_DAD' is set up for dynamic auth for any user.
'Dynamic_Auth_DAD_Restricted' is set up for dynamic auth for user 'HR' only.

無効なDAD認可の表示: 例

例9-5の無名ブロックでは、無効なDAD認証がレポートされます。DAD認証は、次の場合は無効です。

- DADを認可するユーザーが、DADのdatabase-username属性で指定されたユーザーではない。

- DADを認可するユーザーが存在しない。

例9-5 無効なDAD認可の表示

DECLARE
v_dad_names DBMS_EPG.VARCHAR2_TABLE;
v_dad_user  VARCHAR2(32);
v_dad_found BOOLEAN;
BEGIN
DBMS_OUTPUT.PUT_LINE
('---------- DAD Authorizations Not in Effect ----------');
DBMS_EPG.GET_DAD_LIST(v_dad_names);

FOR r IN (SELECT * FROM DBA_EPG_DAD_AUTHORIZATION) LOOP  -- Outer loop
v_dad_found := FALSE;
FOR i IN 1..v_dad_names.count LOOP  -- Inner loop
IF (r.DAD_NAME = v_dad_names(i)) THEN
v_dad_user :=
DBMS_EPG.GET_DAD_ATTRIBUTE(r.DAD_NAME, 'database-username');

-- Is database-username the user for whom DAD is authorized?
IF (r.USERNAME <> v_dad_user) THEN
DBMS_OUTPUT.PUT_LINE (
'DAD authorization of ''' || r.dad_name ||
''' by user ''' || r.username || '''' ||
' is not in effect because DAD user is ' ||
'''' || v_dad_user || '''.');
END IF;
v_dad_found := TRUE;
EXIT;  -- Inner loop
END IF;
END LOOP;  -- Inner loop

-- Does DAD exist?
IF (NOT v_dad_found) THEN
DBMS_OUTPUT.PUT_LINE (
'DAD authorization of ''' || r.dad_name ||
''' by user ''' || r.username ||
''' is not in effect because the DAD does not exist.');
END IF;
END LOOP;  -- Outer loop
END;
/

例9-2のスクリプトを実行して各種DADを作成および構成した場合、例9-5の出力ページは次のとおりです(ページ内に収まるように再フォーマット済)。

---------- DAD Authorizations Not in Effect ----------
DAD authorization of 'Static_Auth_DAD' by user 'OE' is not in effect
because DAD user is 'HR'.
DAD authorization of 'Static_Auth_DAD_Typo' by user 'HR' is not in effect
because DAD does not exist.

埋込みPL/SQLゲートウェイ構成の調査

システム権限のあるユーザーとしてデータベースに接続している場合、次のスクリプトにより、埋込みPL/SQLゲートウェイ構成を調査します。

$ORACLE_HOME/rdbms/admin/epgstat.sql

例9-6に、ANONYMOUSアカウントがロックされている場合の例9-1のepgstat.sqlスクリプトの出力を示します。

例9-6 例9-1のepgstat.sqlスクリプトの出力

スクリプトを実行するコマンドは次のとおりです。

@$ORACLE_HOME/rdbms/admin/epgstat.sql

結果:

+--------------------------------------+
| XDB protocol ports:                  |
|  XDB is listening for the protocol   |
|  when the protocol port is nonzero.  |
+--------------------------------------+

HTTP Port FTP Port
--------- --------
0        0

1 row selected.

+---------------------------+
| DAD virtual-path mappings |
+---------------------------+

Virtual Path                     DAD Name
-------------------------------- --------------------------------
/dynamic/*                       Dynamic_Auth_DAD_Restricted
/static/*                        Static_Auth_DAD

2 rows selected.

+----------------+
| DAD attributes |
+----------------+

DAD Name        DAD Param             DAD Value
------------    --------------------- ----------------------------------------
Dynamic_Auth    database-username     HR
_DAD_Restric
ted

Static_Auth_    database-username     HR
DAD

2 rows selected.

+---------------------------------------------------+
| DAD authorization:                                |
|  To use static authentication of a user in a DAD, |
|  the DAD must be authorized for the user.         |
+---------------------------------------------------+

DAD Name                         User Name
-------------------------------- --------------------------------
Static_Auth_DAD                  HR
OE
Static_Auth_DAD_Typo             HR

3 rows selected.

+----------------------------+
| DAD authentication schemes |
+----------------------------+

DAD Name             User Name                        Auth Scheme
-------------------- -------------------------------- ------------------
Dynamic_Auth_DAD                                      Dynamic
Dynamic_Auth_DAD_Res HR                               Dynamic Restricted
tricted

Static_Auth_DAD      HR                               Static

3 rows selected.

+--------------------------------------------------------+
| ANONYMOUS user status:                                 |
|  To use static or anonymous authentication in any DAD, |
|  the ANONYMOUS account must be unlocked.               |
+--------------------------------------------------------+

Database User   Status
--------------- --------------------
ANONYMOUS       EXPIRED & LOCKED

1 row selected.

+-------------------------------------------------------------------+
| ANONYMOUS access to XDB repository:                               |
|  To allow public access to XDB repository without authentication, |
|  ANONYMOUS access to the repository must be allowed.              |
+-------------------------------------------------------------------+

Allow repository anonymous access?
----------------------------------
false

1 row selected.

埋込みPL/SQLゲートウェイを介したPL/SQLストアド・サブプログラムの起動

埋込みPL/SQLゲートウェイを介してPL/SQLサブプログラムを起動する基本手順は、mod_plsqlゲートウェイに対するものと同じです。詳細は、『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』を参照してください。mod_plsql命令は埋込みゲートウェイで使用するため、若干の調整が必要です。たとえば、次の形式でURLを入力し、ブラウザで埋込みゲートウェイを起動します。

protocol://hostname[:port]/virt-path/[[!][schema.][package.]proc_name[?query_str]]

プレースホルダvirt-pathは、DBMS_EPG.CREATE_DADで構成する仮想パスを表します。mod_plsqlのドキュメントでは、virt-pathのかわりにDAD_locationを使用します。

次の項は『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』に説明されており、埋込みゲートウェイにも同様に適用されます。

- トランザクション・モード

- サポートされているデータ型

- パラメータ渡しのスキーム

- ファイルのアップロード/ダウンロードのサポート

- パスの別名

- Common Gateway Interface(CGI)環境変数

埋込みPL/SQLゲートウェイによるアプリケーション・アクセスの保護

埋込みゲートウェイは、mod_plsqlと同じ保護メカニズムを使用します。詳細は、『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』を参照してください。

埋込みPL/SQLゲートウェイの制限事項

mod_plsqlの制限事項は『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』の第1章に説明されており、埋込みゲートウェイにも同様に当てはまります。また、ゲートウェイの埋込みバージョンでは、次の機能はサポートされません。

- 動的HTMLキャッシング

- システム監視

- Basic以外の認証モード
認証モードの詳細は、『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』を参照してください。

埋込みPL/SQLゲートウェイの使用: 使用例

この項では、hr.employees表に対して問合せを行い、PL/SQLゲートウェイを介してWebブラウザにHTML出力を供給する簡易アプリケーションを作成する方法について説明します。XML DBおよびサンプル・スキーマの両方がインストールされているものとします。

プログラムを作成して実行する手順は次のとおりです。

1. ALTER USER権限のあるユーザーとしてデータベースにログオンし、データベース・アカウントANONYMOUSのロックが解除されていることを確認します。ANONYMOUSアカウントはデフォルトでロックされており、静的認証を必要とします。アカウントがロックされている場合は、次のSQL文を使用してそのロックを解除します。

ALTER USER anonymous ACCOUNT UNLOCK;

2. XML DB管理者、つまりXDBADMINのロールのあるユーザーとしてデータベースにログオンします。
データ・ディクショナリを問い合せ、どのユーザーおよびロールにXDADMINのロールが付与されているかを確認します。

SELECT *
FROM DBA_ROLE_PRIVS
WHERE GRANTED_ROLE = 'XDBADMIN';

3. DADを作成します。たとえば、次のプロシージャでは、DADによって起動されるHR_DADを作成し、仮想パスを/plsql/にマップします。

EXEC DBMS_EPG.CREATE_DAD('HR_DAD', '/plsql/*');

4. DADにより権限が使用される必要があるデータベース・ユーザーに、DAD属性database-usernameを設定します。たとえば、次のプロシージャでは、DAD HR_DADがユーザーHR権限によってデータベース・オブジェクトにアクセスすることを指定します。

EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('HR_DAD', 'database-username', 'HR');

属性database-usernameは、大/小文字を区別します。

5. DADにより権限が使用される必要のあるデータベース・ユーザーにEXECUTE権限を付与します(これによって、ユーザーはDADを認証できます)。次に例を示します。

GRANT EXECUTE ON DBMS_EPG TO HR;

6. XML DB管理者としてログオフし、DADにより権限が使用される必要があるデータベース・ユーザーとして、データベースにログオンします(例: HR)。

7. 埋込みPL/SQLゲートウェイを認可してプロシージャを起動し、DADを介してドキュメント表にアクセスします。次に例を示します。

EXEC DBMS_EPG.AUTHORIZE_DAD('HR_DAD');

8. サンプルのPL/SQLストアド・プロシージャによって起動されるprint_employeesを作成します。次のプログラムでは、hr.employeesの問合せの結果セットを含むHTMLページを作成します。

CREATE OR REPLACE PROCEDURE print_employees IS
CURSOR emp_cursor IS
SELECT last_name, first_name
FROM hr.employees
ORDER BY last_name;
BEGIN
HTP.PRINT('<html>');
HTP.PRINT('<head>');
HTP.PRINT('<meta http-equiv="Content-Type" content="text/html">');
HTP.PRINT('<title>List of Employees</title>');
HTP.PRINT('</head>');
HTP.PRINT('<body TEXT="#000000" BGCOLOR="#FFFFFF">');
HTP.PRINT('<h1>List of Employees</h1>');
HTP.PRINT('<table width="40%" border="1">');
HTP.PRINT('<tr>');
HTP.PRINT('<th align="left">Last Name</th>');
HTP.PRINT('<th align="left">First Name</th>');
HTP.PRINT('</tr>');
FOR emp_record IN emp_cursor LOOP
HTP.PRINT('<tr>');
HTP.PRINT('<td>' || emp_record.last_name  || '</td>');
HTP.PRINT('<td>' || emp_record.first_name || '</td>');
END LOOP;
HTP.PRINT('</table>');
HTP.PRINT('</body>');
HTP.PRINT('</html>');
END;
/

9. Oracle NetリスナーがHTTPリクエストを受け入れられることを確認します。システム・プロンプトで次のコマンドを実行して、LinuxおよびUNIXでのリスナーのステータスを確認できます。

lsnrctl status | grep HTTP

出力は次のとおりです(ページ・サイズによる制限のため単一行から複数行に再フォーマット済)。

(DESCRIPTION=
(ADDRESS=(PROTOCOL=tcp)(HOST=example.com)(PORT=8080))
(Presentation=HTTP)
(Session=RAW)
)

HTTPサービスが起動していないことを確認できた場合は、初期化パラメータ・ファイルに次の行を追加(listener_nameにOracle Netローカル・リスナーを指定)し、データベースおよびリスナーを再起動します。

dispatchers="(PROTOCOL=TCP)"
local_listener=listener_name

10. Webブラウザからprint_employeesプログラムを実行します。たとえば、hostに自分のホスト・コンピュータ名を指定し、portに前の手順のPORTの値を指定すると、次のURLを使用できます。

http://host:port/plsql/print_employees

たとえば、ホストがtest.comで、HTTPポートが8080である場合は、次のように入力します。

http://example.com:8080/plsql/print_employees

Webブラウザに、hr.employees表に全従業員の姓名が記載された表のあるHTMLページが戻されます。

PL/SQLを使用したHTML出力の生成

一般的に、PL/SQL Webアプリケーションでは、ファンクション・コールを使用して出力用の各HTMLタグを生成します。このファンクションは、Oracle Databaseに付属するPL/SQL Web Toolkitパッケージの一部です。例9-7に、各HTMLタグと対応するHTPファンクションをコールして簡単なHTMLページを生成する方法を示します。

例9-7 HTPファンクションを使用したHTMLタグの生成

CREATE OR REPLACE PROCEDURE html_page IS
BEGIN
HTP.HTMLOPEN;                            -- generates <HTML>
HTP.HEADOPEN;                            -- generates <HEAD>
HTP.TITLE('Title');                      -- generates <TITLE>Hello</TITLE>
HTP.HEADCLOSE;                           -- generates </HTML>

-- generates <BODY TEXT="#000000" BGCOLOR="#FFFFFF">
HTP.BODYOPEN( cattributes => 'TEXT="#000000" BGCOLOR="#FFFFFF"');

-- generates <H1>Heading in the HTML File</H1>
HTP.HEADER(1, 'Heading in the HTML File');

HTP.PARA;                                 -- generates <P>
HTP.PRINT('Some text in the HTML file.');
HTP.BODYCLOSE;                            -- generates </BODY>
HTP.HTMLCLOSE;                            -- generates </HTML>
END;
/

各タグに対応するファンクション・コールを作成するかわりに、HTP.PRINTファンクションを使用して、テキストとタグを両方とも出力します。例9-8にこの方法を示します。

例9-8 HTP.PRINTを使用したHTMLタグの生成

CREATE OR REPLACE PROCEDURE html_page2 IS
BEGIN
HTP.PRINT('<html>');
HTP.PRINT('<head>');
HTP.PRINT('<meta http-equiv="Content-Type" content="text/html">');
HTP.PRINT('<title>Title of the HTML File</title>');
HTP.PRINT('</head>');
HTP.PRINT('<body TEXT="#000000" BGCOLOR="#FFFFFF">');
HTP.PRINT('<h1>Heading in the HTML File</h1>');
HTP.PRINT('<p>Some text in the HTML file.');
HTP.PRINT('</body>');
HTP.PRINT('</html>');
END;
/

第10章「PL/SQL Server Pages(PSP)の開発」では、HTMLコンテンツを生成するための、PL/SQLを使用したその他の配信方法について説明しています。PL/SQL Server Pagesは既知のHTMLタグに基づいて構築することができ、一連のファンクション・コールを新たに習得する必要がありません。PL/SQL Server Pagesのセットとして作成されたアプリケーションでも、PL/SQL Web Toolkitのファンクションを使用して、次のことができます。

- 表の表示に関連した処理の簡略化

- 永続データ(Cookie)の格納

- CGIプロトコル内部の作業

PL/SQL Webアプリケーションへのパラメータ渡し

Webアプリケーションを様々な状況で有効に活用するには、対話性を十分に高め、ユーザーによる選択を可能にする必要があります。迅速さを求めるWeb閲覧者に対応するには、対話の効率をよくし、ユーザーが選択項目を簡単に指定できるように、過多な決定事項やデータ入力を避ける必要があります。

PL/SQL Webアプリケーションにパラメータを渡す主な方法は、次のとおりです。

- HTMLフォーム・タグを使用します。ユーザーが1つのWebページ上のフォームに記入して、「Submit」ボタンをクリックすると、すべてのデータおよび選択項目がストアド・サブプログラムに転送されます。

- URLにハードコード化します。ユーザーがリンクをクリックすると、一連の事前定義パラメータがストアド・サブプログラムに転送されます。通常、ユーザーが選択する可能性があるすべての選択項目には、Webページ上に個別のリンクを挿入します。

内容は次のとおりです。

- HTMLフォームからのリスト・パラメータおよびドロップダウン・リスト・パラメータ渡し

- HTMLフォームからのオプション・パラメータおよびチェック・ボックス・パラメータ渡し

- HTMLフォームからの入力フィールド・パラメータ渡し

- HTMLフォームからの非表示パラメータ渡し

- HTMLフォームからのファイルのアップロード

- 記入済HTMLフォームの送信

- HTMLフォームの欠落した入力の処理

- Webページ間での状態情報の保持

HTMLフォームからのリスト・パラメータおよびドロップダウン・リスト・パラメータ渡し

リスト・ボックスおよびドロップダウン・リストは、HTMLタグ(<SELECT>)を使用して実装されます。

選択項目の数を多くする、または複数の選択を可能にする必要がある場合は、リスト・ボックスを使用します。リスト・ボックスは、項目をアルファベット順に表示する場合に適しています。これによって、ユーザーは、すべての項目を読まなくても目的の項目を短時間で検索できます。

次の場合にドロップダウン・リストを使用します。

- 選択項目が少ない

- 画面のスペースがかぎられている。

- 選択項目の順序が特殊。

ドロップダウン・リストは、初めてアクセスするユーザーの注意を引き、選択項目を読ませることができます。選択項目および順序を固定することで、ユーザーはドロップダウン・リストから項目を選択するときの動作に慣れ、素早く選択できるようになります。例9-9に、簡単なドロップダウン・リストを示します。

例9-9 HTMLドロップダウン・リスト

<form>
<select name="seasons">
<option value="winter">Winter
<option value="spring">Spring
<option value="summer">Summer
<option value="fall">Fall
</select>

HTMLフォームからのオプション・パラメータおよびチェック・ボックス・パラメータ渡し

オプション・ボタンによって、NULL値(グループ内のいずれのオプションもチェックされていない場合)、またはチェックされたオプションに指定されている値のいずれかが渡されます。

一連のオプションのデフォルト値を指定するには、INPUTタグにCHECKED属性を含めるか、ストアド・サブプログラム内のパラメータにDEFAULT句を含めます。オプションのグループを設定するときは、「どちらでもない」ことを示す選択項目を含める必要があります。これは、オプションを選択した後では、別のボタンを選択することはできますが、選択を完全に取り消すことができないためです。たとえば、あるユーザーが選択を行った後に、それが間違っていたことに気付くという状況を考慮して、「はい」および「いいえ」とともに「興味なし」または「わからない」という選択項目を含めます。

チェック・ボックスでは、ストアド・サブプログラムがNULL値、単一の値、または複数の値を受け取る場合があるため、特別な処理が必要です。

同じNAME属性を持つチェック・ボックスはすべて、チェック・ボックス・グループを構成します。グループ内のいずれのチェック・ボックスもチェックされていない場合、ストアド・サブプログラムは、対応するパラメータに対してNULL値を受け取ります。

グループ内のチェック・ボックスの1つがチェックされている場合、ストアド・サブプログラムは単一のVARCHAR2パラメータを受け取ります。

グループ内の複数のチェック・ボックスがチェックされている場合、ストアド・サブプログラムはPL/SQLのTABLE OF VARCHAR2データ型のパラメータを受け取ります。TABLE OF VARCHAR2のようなデータ型を宣言するか、OWA_UTIL.IDENT_ARRのような事前定義のデータ型を使用する必要があります。値を検索するには、次のようにループを使用します。

CREATE OR REPLACE PROCEDURE handle_checkboxes (
checkboxes owa_util.ident_arr
) AS
BEGIN
FOR i IN 1..checkboxes.count
LOOP
htp.print('<p>Check Box value: ' || checkboxes(i));
END LOOP;
END;
/

HTMLフォームからの入力フィールド・パラメータ渡し

入力フィールドでは、ユーザーが誤った形式のデータや範囲外のデータなどを入力する可能性があるため、最も厳密な妥当性チェックが必要です。可能な場合、クライアント側JavaScript関数を使用してクライアント側でデータの妥当性チェックを行い、ユーザーにかわって正しいフォーマットにするか、ユーザーに再入力を促します。

次に例を示します。

- ユーザーが数値入力フィールドにアルファベット文字を入力したり、文字数制限を超えた後に文字を入力することができないようにします。

- クレジット・カード番号から空白およびハイフンを暗黙的に削除します(ストアド・サブプログラムでこの形式の値が要求されている場合)。

- ユーザーが最大値を超える数値を入力した場合、すぐに通知して、ユーザーに再入力を促します。

これらの妥当性チェックが常に成功するとはかぎらないため、このような状況に対応できるようにストアド・サブプログラムをコーディングします。ユーザーが誤ったデータを入力したときに「Back」ボタンを押さなくて済むように、エラー・メッセージと他のすべての値が記入された元のフォームを、1つのページに表示します。

パスワードなどの機密性の高い情報の場合、入力フィールドの<INPUT TYPE=PASSWORD>という特殊なフォームによって、入力されたテキストが非表示になります。

例9-10のプロシージャは、入力として2つの文字列を受け入れます。このプロシージャが初めて起動された場合、値を入力するための単純なフォームのプロンプトが表示されます。ユーザーが情報を送ると、同じプロシージャが再起動され、入力が正しいかどうかが確認されます。入力が正しい場合、プロシージャは入力を処理します。正しくない場合、プロシージャは、再入力するためのプロンプトを、最初の値が入力された状態で表示します。

例9-10 HTMLフォームからの入力フィールド・パラメータ渡し

DROP TABLE name_zip_table;
CREATE TABLE name_zip_table (
name     VARCHAR2(100),
zipcode  NUMBER
);

-- Store a name and associated zip code in the database.

CREATE OR REPLACE PROCEDURE associate_name_with_zipcode
(name VARCHAR2 := NULL,
zip  VARCHAR2 := NULL)
AS
BEGIN
-- Each entry field must contain a value. Zip code must be 6 characters.
-- (In a real program you perform more extensive checking.)

IF name IS NOT NULL AND zip IS NOT NULL AND length(zip) = 6 THEN
INSERT INTO name_zip_table (name, zipcode) VALUES (name, zip);

HTP.PRINT('<p>The person ' || HTP.ESCAPE_SC(name) ||
' has the zip code ' || HTP.ESCAPE_SC(zip) || '.');

-- If input was OK, stop here. User does not see form again.
RETURN;
END IF;

-- If user entered incomplete or incorrect data, show error message.

IF (name IS NULL AND zip IS NOT NULL)
OR (name IS NOT NULL AND zip IS NULL)
OR (zip IS NOT NULL AND length(zip) != 6)
THEN
HTP.PRINT('<p><b>Please reenter data. Fill all fields,
and use 6-digit zip code.</b>');
END IF;

-- If user entered no data or incorrect data, show error message
-- & make form invoke same procedure to check input values.

HTP.FORMOPEN('HR.associate_name_with_zipcode', 'GET');
HTP.PRINT('<p>Enter your name:</td>');

HTP.PRINT('<td valign=center><input type=text name=name value="' ||
HTP.ESCAPE_SC(name) || '">');

HTP.PRINT('<p>Enter your zip code:</td>');

HTP.PRINT('<td valign=center><input type=text name=zip value="' ||
HTP.ESCAPE_SC(zip) || '">');

HTP.FORMSUBMIT(NULL, 'Submit');
HTP.FORMCLOSE;
END;
/

HTMLフォームからの非表示パラメータ渡し

ユーザーが同じ選択項目を毎回指定しなくても、一連のストアド・サブプログラムを介して情報を渡すには、ストアド・サブプログラムを起動するフォームに非表示パラメータを含める方法があります。最初のストアド・サブプログラムによって、このストアド・サブプログラムで生成されたHTMLフォームにユーザー名などの情報が入力されます。非表示パラメータの値は、ユーザーがその値をオプションまたは入力フィールドを介して入力した場合と同様に、次のストアド・サブプログラムに渡されます。

1つのストアド・サブプログラムから別のサブプログラムに情報を渡すには、次の方法もあります。

- 永続情報を含む「Cookie」をブラウザに送信します。ブラウザは、同じサイトから他のWebページにアクセスするときに、同じ情報をサーバーに戻します。Cookieは、各WebページのHTMLテキストの前に、ブラウザとWebサーバーの間で転送されるHTTPヘッダーを介して設定され、検索されます。

- データベース自体に情報を格納し、後でストアド・サブプログラムが検索できるようにします。この方法ではデータベース・サーバーに余分なオーバーヘッドが発生し、複数のユーザーがサーバーに同時アクセスしたときに、各ユーザーを追跡する方法を見つける必要があります。

HTMLフォームからのファイルのアップロード

HTMLフォームを使用して、クライアント・システム上のファイルを選択し、これをサーバーに転送できます。ストアド・サブプログラムにより、CLOB、BLOBまたは大量のデータを保持できるその他のデータ型として、データベースにファイルを挿入できます。

PL/SQL Web ToolkitおよびPL/SQLゲートウェイには、アップロードされたファイルを保持する「ドキュメント表」の概念があります。

参照:
『Oracle HTTP Server mod_plsqlユーザーズ・ガイド』

記入済HTMLフォームの送信

デフォルトでは、HTMLフォームには、データをHTMLフォームからストアド・サブプログラムまたはCGIプログラムに転送するための送信(Submit)ボタンが必要です。このボタンには、「検索」や「登録」など任意の名前を指定できます。

1つのページに複数のフォームを挿入し、各フォームに独自のフォーム要素と送信(Submit)ボタンを設定できます。非表示パラメータのみで構成されるフォームも作成できます。このフォームでは、ユーザーはボタンをクリックする以外の選択は行いません。

JavaScriptなどのスクリプト言語を使用すると、送信ボタンを削除して、ドロップダウン・リストからの選択など、別のアクションに応答してフォームが送られるようにすることができます。この方法は、ユーザーが選択する項目が1つのみで、送信(Submit)ボタンで確認する手順が必要でない場合に最適です。

HTMLフォームの欠落した入力の処理

HTMLフォームが送られると、ストアド・サブプログラムは、記入されていないフォーム要素に対してNULLパラメータを受け取ります。NULLパラメータの原因には、入力フィールドが空である、一連のチェック・ボックス、オプションまたはリスト項目がチェックされていない、またはVALUEパラメータの値が""(空の引用符)である、などがあります。

クライアント側で実行する妥当性チェックの内容にかかわらず、常にストアド・サブプログラムをコーディングして、いくつかのパラメータがNULLになる状況に対処します。

- すべてのパラメータ宣言に初期値を指定して、フォーム・パラメータが欠落した状態でストアド・サブプログラムが起動されたときに発生する例外を回避します。数値に対する初期値は0(ゼロ)に設定できます(適切な場合)。ユーザーが実際に値を指定したかどうか確認するには、NULLを使用します。

- 初期値NULLを持つ入力パラメータ値を使用する前に、その値がNULLかどうかを確認します。

- 一部の入力パラメータが指定されていないときでも、サブプログラムが有効な結果を生成するようにします。レポートから一部のセクションを除外するか、パラメータが指定されていない場所を示すテキスト文字列またはイメージをレポート内に表示します。

- 欠落している値を結果ページから直接入力することで、ストアド・サブプログラムを再実行できるようにします。たとえば、追加パラメータを指定して同じストアド・サブプログラムを起動するリンクを含めたり、出力の一部として値を挿入して元のフォームを表示させることができます。

Webページ間での状態情報の保持

Webアプリケーションでは、状態(特定の時点における現行のデータ・セット)の概念が特に重要です。Webページを切り替えると状態情報が簡単に失われ、ユーザーに何度も同じ選択をさせることになる場合があります。

状態情報は、HTMLフォームを使用して動的Webページ間で渡されます。情報は一連の名前/値ペアとして渡され、ストアド・サブプログラムのパラメータになります。

ユーザーが複数の選択をする必要がある場合、多くの選択項目から1つを選択する必要がある場合、または偶然に誤って選択することを回避することが重要な場合は、HTMLフォームを使用します。ユーザーは、すべての選択を行って、選択した項目を再確認すると、「Submit」ボタンを押して選択を決定します。それ以降のページでは、非表示パラメータ(<INPUT TYPE=HIDDEN>タグ)を含むフォームを使用して、これらの選択項目をページからページへと渡すことができます。

ユーザーが1つまたは2つの選択項目のみに関心がある場合、または選択事項がWebページ内に散在している場合、アクションをハイパーリンクとして表し、必要な名前/値ペアを問合せ文字列(URL内の「?」の後に続く部分)に含めることによって、ユーザーが送信(Submit)ボタンを簡単に見つけられるようにできます。

状態情報は、Oracle Application Serverおよびそのmod_oseモジュールを使用して保持することもできます。この方法では、状態情報をパッケージ変数に格納して、ユーザーがWebサイトを移動しても、情報を使用可能のままにできます。

参照:
Oracle Application Serverのマニュアル・セット:

http://www.oracle.com/technetwork/indexes/documentation/index.html

PL/SQLサブプログラムでのネットワーク操作の実行

PL/SQLサブプログラムで次のネットワーク操作を実行するためのパッケージが提供されています。

- PL/SQLからの電子メールの送信

- PL/SQLからのホスト名またはアドレスの取得

- PL/SQLからのTCP/IP接続の使用

- PL/SQLからのHTTP URLコンテンツの取得

- PL/SQLからの表、イメージ・マップ、Cookie、およびCGI変数の使用

IPv6(Internet Protocol version 6)のサポート

Oracle Database 11gリリース2では、PL/SQLネットワーク・ユーティリティ・パッケージがIPv6アドレスをサポートします。パッケージ・インタフェースは変更されていません。ネットワーク・ホストを指定できるすべてのインタフェース・パラメータはIPv6アドレスを文字列形式で受け入れ、IPアドレスを返すすべてのインタフェースはIPv6アドレスを返します。

ただし、ネットワーク・アドレスを使用するアプリケーションでは、IPv6アドレスを処理するために、わずかな変更と再コンパイルが必要になる場合があります。IPv6アドレスは128ビットですが、IPv4アドレスは32ビットです。IPv6アドレスは、URL内では大カッコで囲む必要があります。次に例を示します。

http://[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]/

参照:

- Oracle DatabaseでのIPv6サポートの詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。

- 特定のPL/SQLネットワーク・ユーティリティ・パッケージでのIPv6サポートの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

PL/SQLからの電子メールの送信

例9-11のように、PL/SQLサブプログラムはUTL_SMTPパッケージを使用して電子メールを送信できます。

例9-11 PL/SQLからの電子メールの送信

CREATE OR REPLACE PROCEDURE send_test_message
IS
mailhost   VARCHAR2(64) := 'mailhost.example.com';
sender     VARCHAR2(64) := 'me@example.com';
recipient  VARCHAR2(64) := 'you@example.com';
mail_conn  UTL_SMTP.CONNECTION;
BEGIN
mail_conn := UTL_SMTP.OPEN_CONNECTION(mailhost, 25); -- 25 is the port
UTL_SMTP.HELO(mail_conn, mailhost);
UTL_SMTP.MAIL(mail_conn, sender);
UTL_SMTP.RCPT(mail_conn, recipient);

UTL_SMTP.OPEN_DATA(mail_conn);
UTL_SMTP.WRITE_DATA(mail_conn, 'This is a test message.' || chr(13));
UTL_SMTP.WRITE_DATA(mail_conn, 'This is line 2.' || chr(13));
UTL_SMTP.CLOSE_DATA(mail_conn);

/* If message were in single string, open_data(), write_data(),
and close_data() could be in a single call to data(). */

UTL_SMTP.QUIT(mail_conn);
EXCEPTION
WHEN OTHERS THEN
-- Insert error-handling code here
RAISE;
END;
/

参照:
UTL_SMTPパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

PL/SQLからのホスト名またはアドレスの取得

PL/SQLサブプログラムは、UTL_INADDRパッケージを使用して、ローカル・システムのホスト名または特定のホスト名のIPアドレスを判別できます。

参照:
UTL_INADDRパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

PL/SQLからのTCP/IP接続の使用

PL/SQLサブプログラムは、UTL_TCPパッケージを使用して、ネットワーク上のシステムにTCP/IP接続をオープンし、対応するソケットへの読込みまたは書込みを行います。

参照:
UTL_TCPパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

PL/SQLからのHTTP URLコンテンツの取得

PL/SQLサブプログラムは、UTL_HTTPパッケージを使用して次の操作を実行できます。

- HTTP URLのコンテンツの取得
通常、コンテンツはHTMLタグ・テキストの形式ですが、Webサーバーからダウンロード可能な種類のファイル(たとえば、プレーン・テキストまたはJPEGイメージ)であることもあります。

- HTTPセッションの詳細(ヘッダー、cookie、リダイレクト、プロキシ・サーバー、保護サイトのIDとパスワード、CGIパラメータなど)の管理

- HTTP 1.1永続接続を使用した同じWebサイトへの同時アクセスの高速化

PL/SQLサブプログラムは、ファンクションUTL_URL.ESCAPEやUTL_URL.UNESCAPEを使用して、UTL_HTTPパッケージで使用するためにURLの構築と解釈を行うことができます。

例9-12のPL/SQLプロシージャは、UTL_HTTPパッケージを使用してHTTP URLのコンテンツを取得します。

例9-12 PL/SQLからのHTTP URLコンテンツの取得

CREATE OR REPLACE PROCEDURE show_url
(url      IN VARCHAR2,
username IN VARCHAR2 := NULL,
password IN VARCHAR2 := NULL)
AS
req        UTL_HTTP.REQ;
resp       UTL_HTTP.RESP;
name_      VARCHAR2(256);
value_     VARCHAR2(1024);
data_      VARCHAR2(255);
my_scheme  VARCHAR2(256);
my_realm   VARCHAR2(256);
my_proxy   BOOLEAN;
BEGIN
-- When going through a firewall, pass requests through this host.
-- Specify sites inside the firewall that do not need the proxy host.

UTL_HTTP.SET_PROXY('proxy.example.com', 'corp.example.com');

-- Ask UTL_HTTP not to raise an exception for 4xx and 5xx status codes,
-- rather than just returning the text of the error page.

UTL_HTTP.SET_RESPONSE_ERROR_CHECK(FALSE);

-- Begin retrieving this web page.
req := UTL_HTTP.BEGIN_REQUEST(url);

-- Identify yourself.
--  Some sites serve special pages for particular browsers.
UTL_HTTP.SET_HEADER(req, 'User-Agent', 'Mozilla/4.0');

-- Specify user ID and password for pages that require them.
IF (username IS NOT NULL) THEN
UTL_HTTP.SET_AUTHENTICATION(req, username, password);
END IF;

-- Start receiving the HTML text.
resp := UTL_HTTP.GET_RESPONSE(req);

-- Show status codes and reason phrase of response.
DBMS_OUTPUT.PUT_LINE('HTTP response status code: ' || resp.status_code);
DBMS_OUTPUT.PUT_LINE
('HTTP response reason phrase: ' || resp.reason_phrase);

-- Look for client-side error and report it.
IF (resp.status_code >= 400) AND (resp.status_code <= 499) THEN

-- Detect whether page is password protected
-- and you didn't supply the right authorization.

IF (resp.status_code = UTL_HTTP.HTTP_UNAUTHORIZED) THEN
UTL_HTTP.GET_AUTHENTICATION(resp, my_scheme, my_realm, my_proxy);
IF (my_proxy) THEN
DBMS_OUTPUT.PUT_LINE('Web proxy server is protected.');
DBMS_OUTPUT.PUT('Please supply the required ' || my_scheme ||
' authentication username for realm ' || my_realm ||
' for the proxy server.');
ELSE
DBMS_OUTPUT.PUT_LINE('Web page ' || url || ' is protected.');
DBMS_OUTPUT.PUT('Please supplied the required ' || my_scheme ||
' authentication username for realm ' || my_realm ||
' for the web page.');
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('Check the URL.');
END IF;

UTL_HTTP.END_RESPONSE(resp);
RETURN;

-- Look for server-side error and report it.
ELSIF (resp.status_code >= 500) AND (resp.status_code <= 599) THEN
DBMS_OUTPUT.PUT_LINE('Check if the web site is up.');
UTL_HTTP.END_RESPONSE(resp);
RETURN;
END IF;

-- HTTP header lines contain information about cookies, character sets,
-- and other data that client and server can use to customize each
-- session.

FOR i IN 1..UTL_HTTP.GET_HEADER_COUNT(resp) LOOP
UTL_HTTP.GET_HEADER(resp, i, name_, value_);
DBMS_OUTPUT.PUT_LINE(name_ || ': ' || value_);
END LOOP;

-- Read lines until none are left and an exception is raised.
LOOP
UTL_HTTP.READ_LINE(resp, value_);
DBMS_OUTPUT.PUT_LINE(value_);
END LOOP;
EXCEPTION
WHEN UTL_HTTP.END_OF_BODY THEN
UTL_HTTP.END_RESPONSE(resp);
END;
/

次のブロックでは、例9-12のプロシージャのコールの例を示していますが、そのURLは存在しないページのものです。自分のWebブラウザからURLを代入します。

BEGIN
show_url('http://www.oracle.com/no-such-page.html');
show_url('http://www.oracle.com/protected-page.html');
show_url
('http://www.oracle.com/protected-page.html','username','password');
END;
/

参照:

- UTL_HTTPパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- UTL_URL.ESCAPEおよびUTL_URL.UNESCAPEの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

PL/SQLからの表、イメージ・マップ、Cookie、およびCGI変数の使用

PL/SQLサブプログラムは、Oracle提供のパッケージやOracle HTTP Server(OHS)のmod_plsqlプラグインを使用して、問合せ結果のHTML表としての書式設定、イメージ・マップの生成、HTTP cookieの取得、CGI変数の値の確認、その他の一般的なWeb操作の実行を行います。

これらのパッケージのドキュメントは、データベース・ドキュメント・ライブラリの一部ではありません。ドキュメントの場所は、アプリケーション・サーバーによって異なります。これらのパッケージを使用するには、次に示すSQL*PlusのDESCRIBE文を使用して、サブプログラム名およびパラメータを確認します。

DESCRIBE HTP;
DESCRIBE HTF;
DESCRIBE OWA_UTIL;

10 PL/SQL Server Pages(PSP)の開発

この章では、Webページに動的コンテンツを含めることを可能にするPL/SQL Server Pages(PSP)の開発方法について説明します。

内容は次のとおりです。

- PL/SQL Server Pagesの概要およびPL/SQL Server Pagesを使用する理由

- PL/SQL Server Pagesを開発してデプロイするための前提条件

- PL/SQL Server PagesおよびHTPパッケージ

- PL/SQL Server Pagesおよびその他のスクリプティング・ソリューション

- PL/SQL Server Pagesの開発

- データベースへのPL/SQL Server Pagesのロード

- PL/SQL Server Pagesソース・コードの問合せ

- URLを介したPL/SQL Server Pagesの実行

- PL/SQL Server Pagesの例

- PL/SQL Server Pagesのデバッグ

- PL/SQL Server Pagesの商品化

PL/SQL Server Pagesの概要およびPL/SQL Server Pagesを使用する理由

PL/SQL Server Pages(PSP)は、WebページにSQL問合せの結果を含む動的コンテンツを含めるサーバー側スクリプトです。WebページをHTMLオーサリング・ツールで作成し、PL/SQLコード・ブロックを挿入できます。

例10-1に、simple.pspという名前の簡単なPL/SQL Server Pagesを示します。

例10-1 simple.psp

<%@ page language="PL/SQL" %>
<%@ page contentType="text/html" %>
<%@ plsql procedure="show_employees" %>
<%-- This example displays the last name and first name of every
employee in the hr.employees table. --%>
<%!
CURSOR emp_cursor IS
SELECT last_name, first_name
FROM hr.employees
ORDER BY last_name;
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>List of Employees</title>
</head>
<body TEXT="#000000" BGCOLOR="#FFFFFF">
<h1>List of Employees</h1>
<table width="40%" border="1">
<tr>
<th align="left">Last Name</th>
<th align="left">First Name</th>
</tr>
<%  FOR emp_record IN emp_cursor LOOP %>
<tr>
<td> <%= emp_record.last_name %> </td>
<td> <%= emp_record.first_name %> </td>
</tr>
<%  END LOOP; %>
</table>
</body>
</html>

loadpspコマンドライン・ユーティリティを使用すると、PL/SQL Server Pagesをコンパイルしてデータベースにロードできます。次のコマンドでは、simple.pspがhrスキーマにロードされ、show_employeesプロシージャが置換されます(存在している場合)。

loadpsp -replace simple.psp
Enter Password: password

ブラウザ・ユーザーは、URLを介してshow_employeesプロシージャを実行できます。hr.employees表にある従業員の姓名を表示するHTMLページが、PL/SQLゲートウェイを介してブラウザに戻されます。

PL/SQL Server Pagesを介してコンテンツをデプロイする方法には、次のメリットがあります。

- PL/SQLをよく理解している開発者にとって、PL/SQL Server Pagesはデータベースにより生成されるコンテンツを含む専門的なWebページを最も容易に作成できる方法です。Webページを通常どおりに開発し、HTMLにPL/SQLコードを埋め込むことができます。

- PL/SQL Server Pagesは、HTPパッケージやHTFパッケージを使用してHTMLコンテンツを1行ずつ記述する方法に比べると、多くの点で利便性に優れています。

- 処理はデータベース・サーバーで実行されるため、クライアント・ブラウザは特別なスクリプト・タグのないプレーンHTMLページを受信します。すべてのブラウザおよびブラウザ・レベルを同等にサポートできます。

- PL/SQL Server Pagesを使用するとデータベースのラウンドトリップ数が最小限に抑えられるため、ネットワーク通信量が効率的です。

- コンテンツをすばやく作成し、迅速で反復的な開発プロセスに従うことができます。クライアント・システム上にWebブラウザがあれば、ソフトウェアを集中制御できます。

PL/SQL Server Pagesを開発してデプロイするための前提条件

PL/SQL Server Pagesを開発してデプロイするには、次の前提条件を満たす必要があります。

- PL/SQL Server Pagesを記述するには、スクリプト作成用のテキスト・エディタまたはHTMLオーサリング・ツールにアクセスする必要があります。他の開発ツールは不要です。

- PL/SQL Server Pagesをロードするための要件は、次のとおりです。

- PL/SQL Server Pagesをロードするデータベース上のアカウント。

- $ORACLE_HOME/binにあるloadpspコマンドライン・ユーティリティの実行権限。

- PL/SQL Server Pagesをデプロイするには、mod_plsqlを使用する必要があります。ゲートウェイではPL/SQL Web Toolkitが使用されます。「mod_plsqlゲートウェイを使用したクライアント・リクエストのPL/SQL Webアプリケーションへのマップ」を参照してください。

参照:

- 「mod_plsqlゲートウェイを使用したクライアント・リクエストのPL/SQL Webアプリケーションへのマップ」

PL/SQL Server PagesおよびHTPパッケージ

次の方法で、ブラウザ・ユーザーがHTTPを介してPL/SQLユニットを実行できるようにすることができます。

- 埋込みPL/SQLコードを使用したHTMLページを作成し、それをPL/SQL Server Pagesとしてコンパイルします。PL/SQL Web Toolkitからサブプログラムを起動することもできますが、HTML出力の各行を生成することはできません。

- PL/SQL Web ToolkitにあるHTPパッケージおよびOWA_*パッケージを起動することによって、HTMLを生成する完全なストアド・サブプログラムを作成します。この方法の詳細は、『PL/SQLを使用したHTML出力の生成』を参照してください。

そのため、Webアプリケーションの作成に使用する方法を選択する必要があります。これらの方法を選択する際のキーは、次のとおりです。

- 開始点として使用するソースの内容

- HTMLの本体が大きく、かつ動的コンテンツを含める場合、またはデータベース・アプリケーションのフロントエンドとする場合には、PL/SQL Server Pagesを使用します。

- フォーマットされた出力を生成するPL/SQLコードの本体が大きい場合は、出力文を変更してPL/SQL Web ToolkitのHTPパッケージを起動し、HTMLタグを作成する方が有効です。

- 自分のグループにとって最も迅速で便利なオーサリング環境

- 作業の大半がHTMLオーサリング・ツールにより処理される場合は、PL/SQL Server Pagesを使用します。

- PL/SQLコードを生成するオーサリング・ツールを使用する場合は、PL/SQL Server Pagesを使用すると不便な場合があります。

PL/SQL Server Pagesおよびその他のスクリプティング・ソリューション

スクリプティング・ソリューションは、クライアント側とサーバー側で使用できます。JavaScriptは、非常に一般的なクライアント側スクリプト言語の1つです。PL/SQL Server Pagesは、JavaScriptを完全にサポートしています。PL/SQL Server Pages(PSP)を使用すると、すべてのタグが変更されずにブラウザに渡されるため、PL/SQL Server Pages(PSP)には、JavaScriptまたはその他のクライアント側のスクリプト・コードを含めることができます。

Java Server Pages(JSP)とActive Server Pages(ASP)は、最も一般的なサーバー側スクリプティング・ソリューションです。PL/SQL Server Pagesと対比すると次のようになります。

- JavaServer Pagesは、PL/SQL Server Pagesにほぼ類似していますが、JavaサーブレットはPL/SQLパッケージに類似しています。PL/SQL Server Pagesでは、JSPと同じスクリプト・タグ構文を使用しているため、双方の切替えは簡単です。

- PL/SQL Server PagesではASPに類似した構文を使用していますが、同一ではありません。通常は、VBScriptまたはJScriptからPL/SQLに変換する必要があります。移行に最適なのは、Active Data Object(ADO)を使用してデータベース処理を実行するページです。

注意:
PL/SQL Server Pagesに、サーバー側にあるその他のサーバー側スクリプト機能を混在させることはできません。多くの場合、対応するPL/SQL Server Pages機能を使用することによって、同じ結果を得ることができます。

PL/SQL Server Pagesの開発

PL/SQL Server Pagesを開発するには、既存のWebページから作業を開始する方法と、既存のストアド・サブプログラムから作業を開始する方法があります。どちらの方法でも、わずかな追加と変更のみで、データベース処理を実行し、結果を表示する動的なWebページを作成できます。

PL/SQL Server Pagesのファイルの拡張子は、.pspである必要があります。PL/SQL Server Pagesには、PL/SQL Server Pagesディレクティブ、宣言およびスクリプトレットとともにテキストまたはタグを配置することによって、選択した内容を含めることができます。PL/SQL Server Pagesには、次の書式を使用できます。

- 最も簡単な例は、HTMLファイルです。HTMLファイルをPL/SQL Server Pagesとしてコンパイルすると、同じHTMLファイルを出力するストアド・サブプログラムが作成されます。

- 最も複雑な例では、PL/SQLサブプログラムを使用します。PL/SQLプロシージャを使用して、タイトル、本体およびヘッダーのタグを含むWebページのコンテンツ全体を生成します。

- 一般的な例では、HTML(ページの静的な部分)とPL/SQL(動的コンテンツを提供)の両方を使用します。

PL/SQL Server Pagesディレクティブと宣言の順序と位置は、通常は重要ではありません。重要になるのは、別のファイルが挿入される場合のみです。メンテナンスを簡単にするために、ディレクティブおよび宣言をファイルの最初の方に配置することをお薦めします。

表10-1にPL/SQL Server Pagesの要素と使用方法の参照先を示します。各種PL/SQL Server Pages要素に使用される文字列で引用符を使用する方法については、「PSPスクリプトでの引用符およびエスケープ文字列の使用」を参照してください。

表10-1 PSPの要素

PSPの要素

名前

指定 ...

参照先

<%@ page ... %>

ページ・ディレクティブ

PL/SQL Server Pagesの特性。

「基本的なPL/SQL Server Pages特性の指定」

<%@ parameter ... %>

パラメータ・ディレクティブ

PSPストアド・プロシージャによって予測される各パラメータの名前、および(オプションで)型とデフォルト値。

「ユーザー入力の受入れ」

<%@ plsql ... %>

プロシージャ・ディレクティブ

PSPファイルによって生成されたストアド・プロシージャの名前。

「PL/SQLストアド・プロシージャのネーミング」

<%@ include ... %>

インクルード・ディレクティブ

PSPファイル内の特定のポイントに含めるファイルの名前。

「他のファイルのコンテンツの挿入」

<%! ... %>

宣言ブロック

次のBEGIN/ENDブロック内のみでなく、ページ全体を通して参照できる、一連のPL/SQL変数の宣言

「PSPスクリプトでのグローバル変数の宣言」

<% ... %>

コード・ブロック

ストアド・プロシージャの実行時に実行される一連のPL/SQL文。

「PSPスクリプトでの実行可能文の指定」

<%= ... %>

式ブロック

文字列、算術式、ファンクション・コールまたはこれらの組合せなど、単一のPL/SQL式。

「PSPスクリプトでの式の値の置換」

<%-- ... --%>

コメント

PSPスクリプト内のコメント。

「PSPスクリプトへのコメントの挿入」

注意:
動的HTMLについて理解している場合は、「PL/SQL Server Pagesの例」に進んでください。

内容は次のとおりです。

- 基本的なPL/SQL Server Pages特性の指定

- ユーザー入力の受入れ

- PL/SQLストアド・プロシージャのネーミング

- 他のファイルのコンテンツの挿入

- PSPスクリプトでのグローバル変数の宣言

- PSPスクリプトでの実行可能文の指定

- PSPスクリプトでの式の値の置換

- PSPスクリプトでの引用符およびエスケープ文字列の使用

- PSPスクリプトへのコメントの挿入

基本的なPL/SQL Server Pages特性の指定

<%@ page ... %>ディレクティブを使用して、次のようなPL/SQL Server Pagesの特性を指定します。

- 使用するスクリプト言語。

- 生成する情報のタイプ(MIMEタイプ)。

- 捕捉されなかったすべての例外を処理するために実行するコード。このコードは、わかりやすいメッセージを含むHTMLファイルの場合があり、.pspファイルに名前が変更されます。主なPSPファイルをコンパイルするloadpspコマンドにも同じファイル名を指定する必要があります。errorPageディレクティブおよびloadpspコマンドの両方に、../include/などのすべての関連パス名を含む同じ名前を指定する必要があります。

次のコードは、pageディレクティブの構文を示しています(属性名contentTypeおよびerrorPageでは、大文字と小文字は区別されます)。

<%@ page
language='PL/SQL'
contentType='content_type_string'
charset='encoding'
errorPage='file.psp'
%>

内容は次のとおりです。

- スクリプト言語の指定

- クライアント・ブラウザへのデータの戻し方

- スクリプト・エラーの処理

スクリプト言語の指定

ファイルをPL/SQL Server Pagesとして識別するには、ファイルのどこかに次のディレクティブを挿入します。

<%@ page language="PL/SQL" %>

このディレクティブは、他のスクリプティング環境との互換性を保つためのものです。例10-1に、言語ディレクティブを含む簡単なPL/SQL Server Pagesの例を示します。

クライアント・ブラウザへのデータの戻し方

オプション:

- HTMLの戻し方

- XML、テキストおよび他のドキュメント・タイプの戻し方

- 別のキャラクタ・セットを含むページの戻し方

HTMLの戻し方

PL/SQL Server PagesのPL/SQL部分は、特別なデリミタで囲まれています。他のすべての内容は(空白を含めて)、ブラウザにそのまま渡されます。テキストまたはHTMLタグを表示するには、通常のWebページと同じように書き込みます。出力ファンクションを起動する必要はありません。たとえば、例10-1に示したPL/SQL Server Pagesは、例10-2に示すHTMLページを戻しますが、ここでは問い合せた従業員に関する表の行が含まれています。

例10-2 戻されるHTMLページのサンプル

<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>List of Employees</title>
</head>
<body TEXT="#000000" BGCOLOR="#FFFFFF">
<h1>List of Employees</h1>
<table width="40%" border="1">
<tr>
<th align="left">Last Name</th>
<th align="left">First Name</th>
</tr>

<!-- result set of query of hr.employees inserted here -->

</table>
</body>
</html>

条件によって、出力を1行ずつ表示したり属性の値を変更する必要がある場合があります。例10-1から抜粋した次のコード部分のように、PSPデリミタ内に制御構造と置換変数を含めることができます。

<%  FOR emp_record IN emp_cursor LOOP %>
<tr>
<td> <%= emp_record.last_name %> </td>
<td> <%= emp_record.first_name %> </td>
</tr>
<%  END LOOP; %>

XML、テキストおよび他のドキュメント・タイプの戻し方

デフォルトでは、PL/SQLゲートウェイはファイルをHTMLドキュメントとして送信します。そのため、ブラウザはHTMLタグを解析します。ブラウザに、ドキュメントをXML、プレーン・テキスト(書式なし)またはその他のドキュメント・タイプとして解析させるには、次のディレクティブを含めます。

<%@ page contentType="MIMEtype" %>

属性名contentTypeは、大/小文字を区別します。text/html、text/xml、text/plain、image/jpeg、またはブラウザやその他のクライアント・プログラムが認識できるその他のMIMEタイプを挿入します。MIMEタイプの中には、ユーザーがブラウザの設定を変更しないと認識されないものもあります。次に、Excelスプレッドシートに使用するディレクティブの例を示します。

<%@ page contentType="application/vnd.ms-excel" %>

通常、PL/SQL Server Pagesは、Webブラウザで表示されるように作成されています。また、JavaやPERLクライアントなど、HTTP要求を作成可能なプログラムによって取得または解析されることもあります。

別のキャラクタ・セットを含むページの戻し方

デフォルトでは、PL/SQLゲートウェイは、PL/SQLゲートウェイによって定義されたキャラクタ・セットを使用してファイルを送信します。ブラウザに表示するためにデータを別のキャラクタ・セットに変換するには、次のディレクティブを含めます。

<%@ page charset="encoding" %>

Shift_JIS、Big5、UTF-8、またはクライアント・プログラムが認識できるその他のエンコーディングを指定します。

PL/SQLゲートウェイのデータベース・アクセス記述子(DAD)に設定するキャラクタ・セットも構成する必要があります。データが適切に表示されるようにするには、ユーザーが使用するブラウザで同じエンコーディングを選択する必要がある場合があります。たとえば、EUCエンコーディングを使用するデータベース・キャラクタ・セットが日本のデータベースに含まれていることがありますが、Webブラウザは、Shift_JISエンコーディングで表示するように構成されています。

スクリプト・エラーの処理

PL/SQL Server Pagesを書き込むときに、次のようなエラーが発生することがあります。

- HTML構文エラー
これらのエラーはブラウザで処理されます。loadpspユーティリティは、それらをチェックしません。

- PL/SQL構文エラー
loadpspユーティリティが停止し、行番号、列番号および簡単なメッセージを表示します。継続するには、エラーを修正する必要があります。

ストアド・サブプログラムの以前のバージョンを構文エラーを含むスクリプトで置換しようとすると、そのストアド・サブプログラムは消去される場合があります。1つのデータベースをプロトタイプおよびデバッグ用に使用し、その後、最終的なストアド・サブプログラムを別の本番データベースにロードすることもできます。コマンドライン・フラグを使用すると、どのソース・コードを変更しなくてもデータベースを切り替えることができます。

- ランタイム・エラー
スクリプトの実行時に発生するデータベース・エラーを処理するには、PSPファイルにPL/SQL例外処理コードを含め、未処理の例外があれば、特別なPL/SQL Server Pagesを開始します。ページ名は、<%@ page ... %>ディレクティブのerrorPage属性(名前は大/小文字を区別します)を使用して指定します。

未処理の例外用のページは、拡張子.pspを持つPL/SQL Server Pagesです。エラー・サブプログラムは、どのパラメータも受け取りません。そのため、エラーの原因を判断するには、SQLCODEファンクションおよびSQLERRMファンクションを起動します。また、エラーが発生した場合は、スクリプトを使用しない標準HTMLページを表示することもできます。ただし、拡張子を.pspとし、ストアド・サブプログラムとしてデータベースにロードする必要があります。

次の行は、エラー発生時に実行されるページとしてerrors.pspを指定しています。

<%@ page language="PL/SQL" contentType="text/html" errorPage="errors.psp" %>

ユーザー入力の受入れ

PL/SQL Server Pagesへのパラメータ渡しを設定するには、次の構文のディレクティブを含めます。

<%@ plsql parameter="parameter_name" [type="PL/SQL_type"] [default="value"] %>

デフォルトのPL/SQL_typeはVARCHAR2です。次のディレクティブは、パラメータp_employee_idのデータ型がNUMBERであることを指定しています。

<%@ plsql parameter="p_employee_id" type="NUMBER" %>

パラメータにデフォルト値を指定すると、そのパラメータはオプション・パラメータになります。デフォルト値はPL/SQL文に直接代入されるため、すべての文字列を引用符で囲む必要があります。また、NULLなどの特殊な値を使用できます。次のディレクティブは、パラメータp_last_nameのデフォルト値がNULLであることを指定しています。

<%@ plsql parameter="p_last_name" default="NULL" %>

ユーザー入力は、HTMLページを取得するURLにエンコードされます。URLを生成するには、ユーザー入力をHTMLリンクでハードコード化するか、またはHTML形式のアクションとしてページを起動します。これによって、ページは、PL/SQLストアド・サブプログラムへのパラメータとして入力を受け取ります。

例10-3は例10-1と似ていますが、パラメータp_employee_idが使用される点が異なります。http://www.host.com/pls/proc_nameを起動して(proc_nameはプロシージャ名)プロシージャを実行できるようにPL/SQLゲートウェイが構成されている場合は、次のようにパラメータp_employee_idで200を渡すことができます。

http://www.example.com/pls/show_employees?p_employee_id=200

例10-3 simplewithuserinput.psp

<%@ page language="PL/SQL" %>
<%@ page contentType="text/html" %>
<%@ plsql parameter="p_employee_id" default="null" type="NUMBER" %>
<%@ plsql procedure="show_employees" %>
<%-- This example displays the last name and first name of every
employee in the hr.employees table. --%>
<%!
CURSOR emp_cursor IS
SELECT last_name, first_name
FROM hr.employees
WHERE employee_id = p_employee_id
ORDER BY last_name;
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>List of Employees</title>
</head>
<body TEXT="#000000" BGCOLOR="#FFFFFF">
<h1>List of Employees</h1>
<table width="40%" border="1">
<tr>
<th align="left">Last Name</th>
<th align="left">First Name</th>
</tr>
<%  FOR emp_record IN emp_cursor LOOP %>
<tr>
<td> <%= emp_record.last_name %> </td>
<td> <%= emp_record.first_name %> </td>
</tr>
<%  END LOOP; %>
</table>
</body>
</html>

PL/SQLストアド・プロシージャのネーミング

トップレベルの各PL/SQL Server Pagesは、サーバー内の1つのストアド・プロシージャと対応しています。loadpspを使用してページをロードすると、このユーティリティによりPL/SQLストアド・プロシージャが作成されます。サーバー・ページがname.pspである場合、デフォルトのプロシージャ名はnameです。たとえば、サーバー・ページがhello_world.pspの場合、デフォルトのプロシージャ名はhello_worldです。

プロシージャ名を指定するには、次のディレクティブを使用します。procnameはプロシージャの名前です。

<%@ plsql procedure="procname" %>

例10-1では、次のディレクティブによりストアド・プロシージャにshow_employeesという名前が与えられます。

<%@ plsql procedure="show_employees" %>

これはPSPスクリプト名ではなく、URLに挿入するプロシージャの名前です。

他のファイルのコンテンツの挿入

挿入メカニズムを設定することによって、通常、静的HTMLコンテンツまたはより多くのPL/SQLスクリプト・コードのいずれかを含む別のファイルのコンテンツを含めることができます。filenameを挿入するファイルの名前で置き換えて、他のファイルのコンテンツを表示する位置に次のディレクティブを挿入します。

<%@ include file="filename" %>

インクルード・ファイルには、.psp以外の拡張子を付ける必要があります。includeディレクティブおよびloadpspコマンドの両方に、../include/などのすべての関連パス名を含む同じ名前を指定する必要があります。

ファイルは、ストアド・プロシージャをデータベースにロードするときに処理されるため、置換は、ページの提示ごとではなく、1回のみ実行されます。したがって、ページがデータベースにロードされた後に、インクルード・ファイルに変更が発生した場合、変更内容はプロシージャの実行時に表示されません。

挿入機能を使用してナビゲーション・バナー、フッター、目次などのコード・ライブラリに含めると、複数のファイルに挿入できます。また、この機能をマクロ機能として使用し、スクリプト・コードの同じセクションを1つのページの複数の位置に含めることもできます。次の例では、HTMLフッターを含めています。

<%@ include file="footer.htm" %>

インクルード・ファイルを使用する場合:

- インクルード・ファイルには、どのような名前および拡張子でも使用できます。たとえば、products.txtというファイルを含めることができます。

- インクルード・ファイルにPL/SQLスクリプト・コードが含まれている場合、プロシージャ名やキャラクタ・セットなどを識別するための独自のディレクティブは必要ありません。

- loadpspユーティリティにファイル名を指定するときは、すべてのインクルード・ファイルの名前も含める必要があります。インクルード・ファイルの名前は、すべての.pspファイル名より前に指定してください。

PSPスクリプトでのグローバル変数の宣言

<%! ... %>ディレクティブを使用して、次のBEGIN/ENDブロック内のみでなく、ページ全体を通して参照できる、一連のPL/SQL変数を定義できます。通常、この要素は複数行にまたがっており、最後にセミコロンが付いた個々のPL/SQL変数宣言を持ちます。このディレクティブの構文は次のとおりです。

<%! PL/SQL declaration;
[ PL/SQL declaration; ] ... %>

標準的なPL/SQL構文は、ブロック内で使用できます。デリミタは略記として機能するため、DECLAREキーワードを省略できます。すべての宣言は、ファイル内のその後のコードに使用できます。例10-1には、次のカーソル宣言が含まれています。

<%!
CURSOR emp_cursor IS
SELECT last_name, first_name
FROM hr.employees
ORDER BY last_name;
%>

複数の宣言ブロックを内部的に指定できます。それらはすべて、PSPファイルがストアド・プロシージャとして作成されたときに単一ブロックにマージされます。

「PSPスクリプトでの実行可能文の指定」で説明する<% ... %>デリミタ内に明示的なDECLARE ブロックを使用することもできます。これらの宣言は、後続のBEGIN/ENDブロックのみが参照できます。

注意:
すべてのディレクティブおよび宣言をPL/SQL Server Pagesの最初の方に配置すると、メンテナンスがより簡単になります。

PSPスクリプトでの実行可能文の指定

<% ... %>コード・ブロック・ディレクティブを使用して、ストアド・プロシージャの実行時に一連のPL/SQL文を実行できます。次のコードは、実行可能文の構文を示しています。

<% PL/SQL statement;
[ PL/SQL statement; ] ... %>

通常、この要素は複数行にまたがっており、最後にセミコロンが付いた個々のPL/SQL変数宣言を持ちます。この文は、次の例に示すように、OWA_UTIL.TABLEPRINTプロシージャを起動する完全なブロックを含むこともできます。

<% OWA_UTIL.TABLEPRINT(CTABLE => 'hr.employees', CATTRIBUTES => 'border=2',
CCOLUMNS => 'last_name,first_name', CCLAUSES => 'WHERE employee_id > 100'); %>

また、この文はIF/THEN/ELSEまたはBEGIN/ENDブロックの大カッコで囲まれた部分になることもできます。コード・ブロックが複数のディレクティブに分割されると、HTMLまたはその他のディレクティブを途中に置くことができます。これによって、これら複数のスクリプトレットは、ストアド・プロシージャが実行されたときに、条件付きで実行されます。例10-11から抜粋した次のコードは、この方法を示しています。

<% FOR ITEM IN (SELECT product_name, list_price, catalog_url
FROM product_information
WHERE list_price IS NOT NULL
ORDER BY list_price DESC) LOOP
IF item.list_price > p_minprice THEN
v_color := '#CCCCFF';
ELSE
v_color := '#CCCCCC';
END IF;
%>
<TR BGCOLOR="<%= v_color %>">
<TD><A HREF="<%= item.catalog_url %>"><%= item.product_name %></A></TD>
<TD><BIG><%= item.list_price %></BIG></TD>
</TR>
<% END LOOP; %>

標準的なすべてのPL/SQL構文は、ブロック内で使用できます。デリミタは略記として機能するため、DECLAREキーワードを省略できます。すべての宣言は、ファイル内のその後のコードに使用できます。

注意:
異なるPL/SQL Server Pages間でプロシージャ、定数および型を共有するには、プレーンなPL/SQLソース・ファイルを使用して、それらをデータベース内のパッケージにコンパイルします。PSPスクリプトからパッケージ・プロシージャ、定数および型を参照できますが、PSPスクリプトで生成できるのは、パッケージではなくスタンドアロン・プロシージャのみです。

PSPスクリプトでの式の値の置換

式ディレクティブは、文字列、算術式、ファンクション・コールまたはこれらの組合せなど、単一のPL/SQL式を出力します。結果は、ストアド・プロシージャによって生成されたHTMLページ内の該当部分で文字列に置き換えられます。式の結果は、文字列値であるか、文字列にキャストできる値である必要があります。DATEなど、暗黙的にキャストできない型の場合、値をPL/SQLのTO_CHARファンクションに渡します。

式ディレクティブの構文は、次のとおりです。expressionプレースホルダを必要な式で置き換えてください。

<%= expression %>

PL/SQL式の最後にセミコロンを付ける必要はありません。

例10-1には、次のように変数値を1つのカーソル行に出力するディレクティブが含まれています。

<%= emp_record.last_name %>

この例を、次の例に示す同等のhtp.printコールと比較してください(特に、文の終わりのセミコロンに注意してください)。

<% HTP.PRN (emp_record.last_name); %>

<%= ... %>デリミタ内の内容は、HTP.PRNファンクションによって処理されます。ここでは、先行または後続の空白はすべて切り捨てられ、リテラル文字列を一重引用符で囲むことが要求されます。

PL/SQLの場合と同様、二重パイプ記号(||)を使用すると連結できます。次のディレクティブに連結例を示します。

<%= 'The employee last name is ' || emp_record.last_name %>

PSPスクリプトでの引用符およびエスケープ文字列の使用

PSP属性では、データのデリミタとして二重引用符が使用されます。PSP属性に指定された値がPL/SQL処理に使用された場合、それらはPSPファイルに指定されたとおりに渡されます。したがって、PL/SQLで、一重引用符で囲まれた文字列が必要とされる場合、文字列を一重引用符で囲んで指定し、全体を二重引用符で囲む必要があります。

たとえば、PL/SQLプロシージャで変数のデフォルト値として文字列Babe Ruthを使用するとします。この文字列はPL/SQLで使用されるため、'Babe Ruth'のように一重引用符で囲む必要があります。このように一重引用符で囲んだ文字列をPSPディレクティブのdefault属性に指定する場合は、次のように二重引用符で囲む必要があります。

<%@ plsql parameter="in_players" default="'Babe Ruth'" %>

また、一重引用符で囲まれた文字列を、さらに一重引用符で囲むこともできます。この場合、シーケンス\'を指定して内側の一重引用符をエスケープする必要があります。次に例を示します。

<%@ plsql parameter="in_players" default="'Walter \'Big Train\' Johnson'" %>

ほとんどの文字および文字列は、PSPローダーで変更しなくてもPSPファイルに含めることができます。シーケンス%>を含めるには、エスケープ・シーケンス%\>を指定します。シーケンス<%を含めるには、エスケープ・シーケンス<\%を指定します。次に例を示します。

<%= 'The %\> sequence is used in scripting language: ' || lang_name %>
<%= 'The <\% sequence is used in scripting language: ' || lang_name %>

PSPスクリプトへのコメントの挿入

PL/SQL Server PagesのHTML部分にコメントを挿入する場合、PSPソース・コードが簡単に読めるように次の構文を使用します。

<%-- PSP comment text --%>

前述した書式のコメントはPSPからのHTML出力には表示されず、USER_OBJECTS内のPL/SQLソース・コードを問い合せても表示されません。

HTML出力およびUSER_OBJECTSソースに表示されるコメントを作成するには、HTMLにコメントを挿入して、次のような通常のHTMLコメント構文を使用します。

<!-- HTML comment text -->

PSP内でPL/SQLブロックの中にコメントを挿入し、HTML出力では参照できないがUSER_OBJECTS内では参照できるようにするには、次の例に示すように通常のPL/SQLコメント構文を使用します。

-- Comment in PL/SQL code

例10-4に、3タイプのコメントを含むPSPファイルの断片を示します。

例10-4 PSPファイル内のサンプル・コメント

<p>Today we introduce our new model XP-10.
<%--
This is the project with code name "Secret Project".
Users viewing the HTML page do not see this PSP script comment.
The comment is not visible in the USER_OBJECTS source code.
--%>
<!--
Some pictures of the XP-10.
Users viewing the HTML page source see this comment.
The comment is also visible in the USER_OBJECTS source code.
-->
<%
FOR image_file IN (SELECT pathname, width, height, description
FROM image_library WHERE model_num = 'XP-10')
-- Comments interspersed with PL/SQL statements.
-- Users viewing the HTML page source do not see these PL/SQL comments.
-- These comments are visible in the USER_OBJECTS source code.
LOOP
%>
<img src="<%= image_file.pathname %>" width=<% image_file.width %>
height=<% image_file.height %> alt="<% image_file.description %>">
<br>
<% END LOOP; %>

データベースへのPL/SQL Server Pagesのロード

$ORACLE_HOME/binにあるloadpspユーティリティを使用して、1つ以上のPSPファイルをストアド・プロシージャとしてデータベースにロードします。各.pspファイルは1つのストアド・プロシージャと対応します。開発サイクルを短くするために、ページのコンパイルおよびロードは1手順で行われます。loadpspユーティリティの構文は、次のとおりです。

loadpsp [-replace] [include_file_name...] [error_file_name] psp_file_name...
Enter Password: password

PSPファイルのロード時に、ローダーにより次のアクションが実行されます。

1. 指定したユーザー名、パスワードおよびネット・サービス名を使用してデータベースにログインします。

2. ユーザー・スキーマにストアド・プロシージャを作成します。

-replaceによって、CREATE OR REPLACE構文でプロシージャが作成されます。

include_file_nameは、PSP includeディレクティブに指定されるファイルの名前です。

error_file_nameは、PSP pageディレクティブのerrorPage属性に指定されるファイルの名前です。

psp_file_nameは、PSP pageディレクティブに指定されるファイルの名前です。

loadpspコマンドライン上のこれらのファイル名は、../include/などの関連パス名も含めて、PSPのincludeディレクティブおよびpageディレクティブに指定された名前と完全に一致する必要があります。

例10-5に、PSPロード・コマンドの例を示します。

例10-5 PL/SQL Server Pagesのロード

loadpsp -replace -user joe/abc123@/db3 banner.inc error.psp display_order.psp

例10-5の内容は次のとおりです。

- ストアド・プロシージャは、データベースdb3で作成されます。ストアド・プロシージャを作成および実行するときは、データベースはユーザーjoe、パスワードabc123でアクセスされます。

- banner.incは、ボイラープレート・テキストとスクリプト・コードを含むファイルで、.pspファイルに含まれています。banner.incは、ストアド・プロシージャが実行されるときではなく、PSPがデータベースにロードされるときに含まれます。

- error.pspは、未処理例外が発生したときに処理されるコードまたはテキスト(あるいはその両方)を含むファイルで、内部エラー・メッセージではなくわかりやすい内容のページを表示します。

- display_order.pspには、Webページの主要コードおよびテキストが含まれています。デフォルトでは、対応するストアド・プロシージャはdisplay_orderという名前です。

PL/SQL Server Pagesソース・コードの問合せ

loadpspによって生成されるコードは、ソース・ファイル内のコードとは異なります。WebページのHTMLタグを生成するHTPパッケージへのコールを含んでいます。

PSPファイルをロードした後、静的データ・ディクショナリ・ビュー*_SOURCEに対して問合せを行うことにより、生成されたソース・コードを表示できます。たとえば、次のコマンドを使用して例10-1のスクリプトをロードするとします。

loadpsp -replace -user hr simple.psp
Enter Password: password

データベースにユーザーhrとしてログインすると、例10-6のようにPSPのソース・コードを表示できます。

例10-6 PL/SQL Server Pageソース・コードの問合せ

問合せ:

SELECT TEXT
FROM USER_SOURCE
WHERE NAME = 'SHOW_EMPLOYEES'
ORDER BY LINE;

結果:

PROCEDURE show_employees  AS

CURSOR emp_cursor IS
SELECT last_name, first_name
FROM hr.employees
ORDER BY last_name;

BEGIN NULL;
owa_util.mime_header('text/html'); htp.prn('
');
htp.prn('
');
htp.prn('
');
htp.prn('
');
htp.prn('
');
htp.prn('
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>List of Employees</title>
</head>
<body TEXT="#000000" BGCOLOR="#FFFFFF">
<h1>List of Employees</h1>
<table width="40%" border="1">
<tr>
<th align="left">Last Name</th>
<th align="left">First Name</th>
</tr>
');
FOR emp_record IN emp_cursor LOOP
htp.prn('
<tr>
<td> ');
htp.prn( emp_record.last_name );
htp.prn(' </td>
<td> ');
htp.prn( emp_record.first_name );
htp.prn(' </td>
</tr>
');
END LOOP;
htp.prn('
</table>
</body>
</html>
');
END;

URLを介したPL/SQL Server Pagesの実行

PL/SQL Server Pagesが一度ストアド・プロシージャに変換されると、Webブラウザまたは他のインターネット関連クライアント・プログラムを使用してHTTP URLを取得することによって、そのプロシージャを実行できます。URLの仮想パスは、PL/SQLゲートウェイが構成された方法によって異なります。

ストアド・プロシージャへのパラメータは、HTTPプロトコルのPOSTメソッドまたはGETメソッドのいずれかを使用して渡されます。POSTメソッドの場合、パラメータはHTMLフォームから直接渡され、URLには表示されません。GETメソッドの場合、パラメータはURLの問合せ文字列で名前/値ペアとして渡されます。URLの問合せ文字列は、エンコード形式のほとんどの英数字以外の文字(たとえば、空白は%20)で、&文字で区切られています。PSPページをHTMLフォームから起動するには、GETメソッドを使用します。また、特定のパラメータ・セットを持つストアド・プロシージャを起動するには、ハードコード化されたHTMLリンクを使用します。

METHOD=GETを使用する場合、URLの構文は次のようになります。

http://sitename/schemaname/procname?parmname1=value1&parmname2=value2

たとえば、次のURLにはp_lnameおよびp_fnameパラメータが含まれています。

http://www.example.com/pls/show_employees?p_lname=Ashdown&p_fname=Lance

METHOD=POSTを使用した場合、パラメータはURL構文に表示されません。

http://sitename/schemaname/procname

たとえば、次のURLではプロシージャ名は指定されていますが、パラメータは渡されません。

http://www.example.com/pls/show_employees

METHOD=GET形式は、デバッグに有効です。また、ページの閲覧者がブックマークを使用して再度ページを開く際、同じパラメータを渡すことができます。

METHOD=POST形式は、さらに大きいパラメータ・データを扱え、URLに表示できない機密情報を渡す場合に適しています。(URLは、ブラウザの履歴リスト、および次のアクセス・ページに渡されるHTTPヘッダーの中に残ります。)この方法で起動されたページにブックマークを付けるのは、効果的ではありません。

PL/SQL Server Pagesの例

この項では、非常に単純なPL/SQL Server Pagesから始め、徐々に複雑なバージョンを作成していく方法を説明します。

各手順を行いながら、「データベースへのPL/SQL Server Pagesのロード」および「URLを介したPL/SQL Server Pagesの実行」の指示に従って例をテストしてください。

内容は次のとおりです。

- PL/SQL Server Pagesの例のための設定

- ループを使用したサンプル表の出力

- ユーザー選択の許可

- HTMLフォームを使用したPL/SQL Server Pagesの起動

- PSPファイルへのJavaScriptの挿入

PL/SQL Server Pagesの例のための設定

各例では、後述のように、OEスキーマ内のPRODUCT_INFORMATION表を使用します。

SQL*Plusコマンド:

DESCRIBE PRODUCT_INFORMATION;

結果:

Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
PRODUCT_ID                                NOT NULL NUMBER(6)
PRODUCT_NAME                                       VARCHAR2(50)
PRODUCT_DESCRIPTION                                VARCHAR2(2000)
CATEGORY_ID                                        NUMBER(2)
WEIGHT_CLASS                                       NUMBER(1)
WARRANTY_PERIOD                                    INTERVAL YEAR(2) TO MONTH
SUPPLIER_ID                                        NUMBER(6)
PRODUCT_STATUS                                     VARCHAR2(20)
LIST_PRICE                                         NUMBER(8,2)
MIN_PRICE                                          NUMBER(8,2)
CATALOG_URL                                        VARCHAR2(50)

各例では次のように想定しています。

- 「mod_plsqlゲートウェイを使用したクライアント・リクエストのPL/SQL Webアプリケーションへのマップ」の説明に従って、mod_plsqlの設定を完了していること。

- OEユーザーの静的認証に使用するDADを作成していること。

- OEスキーマに作成したPL/SQLストアド・プロシージャに、URL http://www.example.com/pls/proc_nameを介してアクセスできること(proc_nameはストアド・プロシージャ名)。

例10-7のようにOWA_UTIL.TABLEPRINTをコールして、デバッグのためにSQL表の内容全体を表示できます。後の例では、表示をさらに制御する他の方法を示します。

例10-7 show_prod_simple.psp

<%@ plsql procedure="show_prod_simple" %>
<HTML>
<HEAD><TITLE>Show Contents of product_information (Complete Dump)</TITLE></HEAD>
<BODY>
<%
DECLARE
dummy BOOLEAN;
BEGIN
dummy := OWA_UTIL.TABLEPRINT('oe.product_information','border');
END;
%>
</BODY>
</HTML>

次のように、例10-7のPSPをコマンドラインでロードします。

loadpsp -replace -user oe/password show_prod_simple.psp
Enter Password: password

次のURLを介してPSPにアクセスします。

http://www.example.com/pls/show_prod_simple

ループを使用したサンプル表の出力

例10-7では、product_information表の項目をループし、SELECT文を調整して、行または列のサブセットのみを取得します。この例では、一致していない表タグまたはクローズしていない表タグによる問題を回避するために、非常に単純な一連のリスト品目を例として示します。

例10-8 show_catalog_raw.psp

<%@ plsql procedure="show_prod_raw" %>
<HTML>
<HEAD><TITLE>Show Products (Raw Form)</TITLE></HEAD>
<BODY>
<UL>
<% FOR item IN (SELECT product_name, list_price, catalog_url
FROM product_information
WHERE list_price IS NOT NULL
ORDER BY list_price DESC) LOOP %>
<LI>
Item = <%= item.product_name %><BR>
Price = <%= item.list_price %><BR>
URL = <%= item.catalog_url %><BR>
<% END LOOP; %>
</UL>
</BODY>
</HTML>

例10-9に、より洗練された例10-8のバリエーションを示します。この例では、表示を改善するためにHTMLに書式が追加されています。

例10-9 show_catalog_pretty.psp

<%@ plsql procedure="show_prod_pretty" %>
<HTML>
<HEAD><TITLE>Show Products (Better Form)</TITLE></HEAD>
<BODY>
<UL>
<% FOR item IN (SELECT product_name, list_price, catalog_url
FROM product_information
WHERE list_price IS NOT NULL
ORDER BY list_price DESC) LOOP %>
<LI>
Item = <A HREF=<%= item.catalog_url %>><%= item.product_name %></A><BR>
Price = <BIG><%= item.list_price %></BIG><BR>
<% END LOOP; %>
</UL>
</BODY>
</HTML>

ユーザー選択の許可

例10-7、例10-8および例10-9では、PRODUCT_INFORMATION表が更新されないかぎりHTMLページは変わりません。例10-10では次の処理が行われます。

- HTMLページに最低価格を入力できるようにし、それよりも高価な品目のみを表示するようにします。(顧客の購買基準は様々です。)

- デフォルトの最低価格を100(単位は該当通貨)に設定します。

例10-10 show_product_partial.psp

<%@ plsql procedure="show_product_partial" %>
<%@ plsql parameter="p_minprice" default="100" %>
<HTML>
<HEAD><TITLE>Show Items Greater Than Specified Price</TITLE></HEAD>
<BODY>
<P>This report shows the items whose price is greater than <%= p_minprice %>.
<UL>
<% FOR ITEM IN (SELECT product_name, list_price, catalog_url
FROM product_information
WHERE list_price > p_minprice
ORDER BY list_price DESC)
LOOP %>
<LI>
Item = <A HREF="<%= item.catalog_url %>"><%= item.product_name %></A><BR>
Price = <BIG><%= item.list_price %></BIG><BR>
<% END LOOP; %>
</UL>
</BODY>
</HTML>

例10-10をデータベースにロードした後、URLを介してshow_product_partialプロシージャにパラメータを渡すことができます。次の例では、最低価格250を指定しています。

http://www.example.com/pls/show_product_partial?p_minprice=250

結果のフィルタリングは、検索結果など、選択肢がユーザーにとって多すぎる可能性があるアプリケーションには有用です。ただし、小売りの場合は、顧客が他の品目も選択できるように、例10-11に示す別の方法を使用する必要があります。

- WHERE句を使用して結果をフィルタするかわりに、すべての結果セットを取得し、戻された各行に対して別々のアクションを実行します。

- HTMLを変更して、基準に合う出力のみをハイライト表示させます。例10-11では、HTML表の行にバックグラウンド・カラーを使用します。最も重要な行が目立つようにするために、特別なアイコンを挿入したり、フォント・サイズを大きくすることもできます。

- 結果をHTML表に表示します。

例10-11 show_product_highlighed.psp

<%@ plsql procedure="show_product_highlighted" %>
<%@ plsql parameter="p_minprice" default="100" %>
<%! v_color VARCHAR2(7); %>

<HTML>
<HEAD><TITLE>Show Items Greater Than Specified Price</TITLE></HEAD>
<BODY>
<P>This report shows all items, highlighting those whose price is
greater than <%= p_minprice %>.
<P>
<TABLE BORDER>
<TR>
<TH>Product</TH>
<TH>Price</TH>
</TR>
<% FOR ITEM IN (SELECT product_name, list_price, catalog_url
FROM product_information
WHERE list_price IS NOT NULL
ORDER BY list_price DESC) LOOP
IF item.list_price > p_minprice THEN
v_color := '#CCCCFF';
ELSE
v_color := '#CCCCCC';
END IF;
%>
<TR BGCOLOR="<%= v_color %>">
<TD><A HREF="<%= item.catalog_url %>"><%= item.product_name %></A></TD>
<TD><BIG><%= item.list_price %></BIG></TD>
</TR>
<% END LOOP; %>
</TABLE>
</BODY>
</HTML>

HTMLフォームを使用したPL/SQL Server Pagesの起動

例10-12に、ユーザーが価格を入力できるHTMLフォームの要点を示します。このフォームは、例10-10に示したshow_product_partialストアド・プロシージャを起動し、入力された値をp_minpriceパラメータとして渡します。

このフォームのACTION=属性で、ストアド・プロシージャのURL全体をコード化することを回避するには、そのストアド・プロシージャが起動するPSPファイルと同じディレクトリに置かれるように、このフォームをPSPファイルとして作成します。このHTMLファイルにはPL/SQLコードが含まれていませんが、これに.psp拡張子を付け、ストアド・プロシージャとしてデータベースにロードできます。URLを介してproduct_formストアド・プロシージャが実行されたとき、HTMLはファイルに表示されるとおりに表示されます。

例10-12 product_form.psp

<HTML>
<BODY>
<FORM method="POST" action="show_product_partial">
<P>Enter the minimum price you want to pay:
<INPUT type="text" name="p_minprice">
<INPUT type="submit" value="Submit">
</FORM>
</BODY>
</HTML>

PSPファイルへのJavaScriptの挿入

JavaScriptなどの動的コンテンツを含むような、複雑なHTMLファイルを生成するには、ソース・コードをPSPとして実装することによって単純化します。この方法では、ネストされた引用符、エスケープ文字、連結リテラルや変数および埋込みコンテンツのインデントを考慮する必要がなくなります。

例10-13に例10-10の別バージョンを示します。このバージョンでは、ユーザーがマウスを製品URLに置くと、JavaScriptを使用してブラウザのステータス・バーに注文のステータスが表示されます。

例10-13 show_product_javascript.psp

<%@ plsql procedure="show_product_javascript" %>
<%@ plsql parameter="p_minprice" default="100" %>
<HTML>
<HEAD>
<TITLE>Show Items Greater Than Specified Price</TITLE>

<SCRIPT language="JavaScript">
<!--hide

var text=" ";

function overlink (text)
{
window.status=text;
}
function offlink (text)
{
window.status=text;
}

//-->
</SCRIPT>

</HEAD>
<BODY>
<P>This report shows the items whose price is greater than <%= p_minprice %>.
<P>
<UL>
<% FOR ITEM IN (SELECT product_name, list_price, catalog_url, product_status
FROM product_information
WHERE list_price > p_minprice
ORDER BY list_price DESC)
LOOP %>
<LI>
Item =
<A HREF="<%= item.catalog_url %>"
onMouseover="overlink('PRODUCT STATUS: <%= item.product_status %>');return true"
onMouseout="offlink(' ');return true">
<%= item.product_name %>
</A>
<BR>
Price = <BIG><%= item.list_price %></BIG><BR>
<% END LOOP; %>
</UL>
</BODY>
</HTML>

PL/SQL Server Pagesのデバッグ

PL/SQL Server Pagesに取り組み始めた際、および最初の単純なページからより複雑なページに進む過程で、問題が発生した場合は、次のガイドラインに従ってください。

- まず、すべてのPL/SQL構文およびPSPディレクティブ構文を正しく作成します。ここで間違っていれば、ファイルはコンパイルできません。

- 行を終了するには、必要に応じてセミコロンを使用します。

- 引用符で囲む必要のある値に、引用符が付いているかどうかを確認します。値を一重引用符で囲み(PL/SQLで使用)、さらにこれを二重引用符で囲む(PSPで使用)必要がある場合があります。

- PSPディレクティブ内の誤りは、通常、PL/SQL構文メッセージによってレポートされます。適切な構文が使用され、適切にクローズされ、内容に応じた適切な要素(宣言、式またはコード・ブロック)が使用されているかどうかについて、ディレクティブをチェックします。

- PSP属性名は、大/小文字を区別します。ほとんどの場合、すべて小文字で指定します。contentTypeおよびerrorPageは、大文字と小文字を組み合せて指定する必要があります。

- URLを使用してPSPを要求するときに、ファイルが見つからないというエラーが表示される場合があります。その際は次のように対処します。

- Webゲートウェイの構成方法に合った、正確な仮想パスを要求しているかどうかを確認します。通常、パスにはホスト名が含まれます。また、オプションで、ポート番号、スキーマ名およびストアド・プロシージャの名前(.psp拡張子なし)が含まれます。

- ファイルをコンパイルするときに-replaceオプションを使用した場合、ストアド・プロシージャの古いバージョンは消去されます。そのため、コンパイルに失敗した場合は、エラーを修正しなければページは使用できません。スクリプトを別のスキーマでテストし、その後、本番スキーマにロードするという方法をとることもできます。

- ファイルを別のファイルからコピーした場合、ソース内のプロシージャ名ディレクティブを正しいファイル名と一致させるように変更してください。

- ファイルが見つからないというエラーが1つでも戻された場合、次回は最新バージョンのページを要求してください。ブラウザがエラー・ページをキャッシュする場合があります。ブラウザに再ロードされるページにキャッシュを強制的にバイパスさせる必要がある場合があります。

- PSPスクリプトが実行されると、結果はブラウザに戻されます。標準のデバッグ方法を使用して、出力のチェックおよび修正を行ってください。ここでは、適切な値がページに渡されるように、異なるHTMLフォーム、スクリプト、CGIプログラムの間でインタフェースを構成することが重要です。パラメータが一致しなければ、ページがエラーを戻す場合があります。
ガイドライン:

- ページに渡される内容を正確に判別するには、URLでパラメータを参照できるようにFORMタグの中でMETHOD=GETを使用します。

- ページを起動するフォームまたはCGIプログラムが適切なパラメータ数を渡すかどうかを確認します。また、フォームのNAME=属性で指定した名前が、PSPファイルのパラメータ名と一致していることも確認します。フォームに非表示の入力フィールドがある場合、あるいは「Submit」ボタンまたは「Reset」ボタンにNAME=属性が使用されている場合、PSPファイルは同等のパラメータを宣言する必要があります。

- パラメータが文字列から適切なPL/SQL型にキャストされることを確認します。たとえば、PSPファイルのパラメータがNUMBERで宣言されている場合、アルファベット文字を含めることはできません。

- ページへのハードコード・リンクを構成してパラメータを渡す場合は、特に、URLの問合せ文字列が、等号で区切られた名前/値ペアで構成されていることを確認します。

- 大きい文字列など、多数のパラメータ・データを渡す場合、METHOD=GETで渡すことができるボリュームを超えてしまう場合があります。その場合、PSPファイルを変更せずに、FORMタグの中でMETHOD=POSTに切り替えることができます。

- ソース・ファイルに構文エラーがある場合、loadpspコマンドは、行番号を正しくレポートしますが、実行中のエラーに対してレポートされた行番号は、ソースの変換バージョンを参照し、元のソースの行番号とは一致しません。予想したWebページではなくエラー・トレースが表示されるエラーが発生した場合は、例外ハンドラおよびデバッグ出力の表示によって、エラーの位置を特定する必要があります。

PL/SQL Server Pagesの商品化

PSPアプリケーションを商品化する前に、有用性やダウンロード速度などの問題も考慮する必要があります。

- すべてのイメージにHEIGHT=属性およびWIDTH=属性が指定されると、ブラウザがページを生成する速度が速くなります。また、写真のサイズを標準化したり、イメージの高さおよび幅をデータまたはURLとともにデータベースに格納しておくこともできます。

- 図形を表示しないビューア、またはテキストを音声で読み上げるブラウザを使用しているビューア用には、ALT=属性を使用して重要な図形の説明を含めます。これも、イメージとともにデータベースに格納しておきます。

- HTMLの表はデータ表示の方法として有効ですが、大きい表が原因でアプリケーションの速度が遅く感じることがあります。表全体がダウンロードされるまで、ビューアには空白のページが表示されます。HTML表のデータ量が大きければ、出力を複数の表に分割することを考慮してください。

- テキスト、フォントまたはバックグランドにそれぞれカラーを設定している場合、アプリケーションをブラウザのカラー設定の様々な組合せでテストします。

- ブラウザでフォアグラウンド・カラーのみをオーバーライドした場合、バックグラウンド・カラーのみをオーバーライドした場合、または両方をオーバーライドした場合に、それぞれどのような結果になるかをテストします。

- 1つのカラー(たとえば、フォアグラウンド・テキスト・カラー)を設定した場合に、白のバックグラウンドに白のテキストなど、読みにくい組合せを回避するために、すべてのカラーを<BODY>タグで設定してください。

- バックグランド・イメージを使用する場合、図形をロードしないビューアに対して適切なコントラストを設定できるように、同系色のバックグランド・カラーを指定します。

- 異なるカラーで表示する情報が重要な意味を持つ場合は、別の方法を使用することを検討します。たとえば、表内の特別な項目の横にアイコンを置いたりします。ユーザーによっては、ページをモノクロ画面で表示する場合や、様々なカラーを表示できないブラウザを使用している場合もあります。

- ユーザーに内容の情報を提供すると、ユーザーが迷わなくなります。ページに、わかりやすい<TITLE>タグを含めます。ユーザーが手順の途中にいる場合は、表示されているページがどの手順なのかを示します。手順を継続するか、前の手順に戻るか、または手順を完全に中止するかを示す論理点へのリンクを設定します。多くのページには、インクルード・ディレクティブを使用して埋め込んだ、標準のリンクが使用されています。

- ユーザーは、入力フィールドに不適切な値を入力してしまう場合があります。できるだけ、選択肢を示したSELECT構文のリストを使用します。フィールドに入力されたテキストは、SQLに渡す前に、すべて妥当性チェックを行う必要があります。妥当性は早い段階でチェックする方が効果的です。JavaScript関数は、不適切なデータを検出し、ユーザーが「Submit」ボタンを押してデータベースにコールする前に、ユーザーに対して修正を促します。

- ブラウザが、間違ったHTMLを表示する場合もあります。あるブラウザでは正常に表示されても、別のブラウザでは正常に表示されなかったり、まったく表示されない場合もあります。
ガイドライン:

- 引用符、タグのクローズおよび表に関するHTMLルールには注意してください。

- 単一のブラウザのみでサポートされているタグに依存することは、最小限にしてください。そのようなタグを使用することによって便利な場合もありますが、アプリケーションは他のブラウザでも使用可能である必要があります。

- 多くのWebサイトで、HTMLの妥当性および(場合によっては)有用性が無償でチェックできます。

11 連続問合せ通知(CQN)の使用

連続問合せ通知(CQN)を使用すると、問合せをオブジェクト変更通知用(デフォルト)または問合せ結果変更通知用としてアプリケーションからデータベースに登録できます。登録済の問合せで参照されるオブジェクトは、登録済オブジェクトです。

オブジェクト変更通知(OCN)に対する問合せが登録されると、その問合せで参照されるオブジェクトがトランザクションによって変更されてコミットされるたびに、問合せ結果が変更されたかどうかにかかわらず、データベースからアプリケーションに通知されます。

問合せ結果変更通知(QRCN)に対して問合せが登録されると、その問合せの結果がトランザクションによって変更されてコミットされるたびに、データベースからアプリケーションに通知されます。

CQN登録により、1つ以上の問合せのリストが通知タイプ(OCNまたはQRCN)および通知ハンドラに関連付けられます。CQN登録を作成するには、PL/SQLインタフェースまたはOracle Call Interface(OCI)を使用できます。PL/SQLインタフェースを使用する場合、通知ハンドラはサーバー側のPL/SQLストアド・プロシージャになり、OCIを使用する場合、通知ハンドラはクライアント側のCコールバック・プロシージャになります。

この章では、CQNの一般的な概念と、PL/SQL CQNインタフェースの使用方法について説明します。CQNにOCIを使用する方法の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

内容は次のとおりです。

- オブジェクト変更通知(OCN)

- 問合せ結果変更通知(QRCN)

- 通知を生成するイベント

- 通知内容

- CQNに適したアプリケーション

- CQN登録の作成

- CQN登録の問合せ

- 通知の解析

- 登録の削除

- CQNの構成: 使用例

注意:
OCNおよびQRCNという用語は、通知タイプと通知自体の両方を指します。アプリケーションによりOCNに対する問合せが登録されると、データベースからアプリケーションにOCNが送信され、アプリケーションによりQRCNに対する問合せが登録されると、データベースからアプリケーションにQRCNが送信されます。

オブジェクト変更通知(OCN)

アプリケーションでオブジェクト変更通知(OCN)に対する問合せが登録されると、その問合せに関連付けられているオブジェクトがトランザクションによって変更されてコミットされるたびに、問合せ結果が変更されたかどうかにかかわらず、データベースからアプリケーションにOCNが送信されます。

たとえば、アプリケーションで例11-1のOCNに対する問合せが登録され、EMPLOYEES表を変更するトランザクションがユーザーによってコミットされると、変更された行が問合せの条件句を満たしていない場合でも(DEPARTMENT_ID = 5の場合など)、データベースからアプリケーションにOCNが送信されます。

例11-1 変更通知として登録される問合せ

SELECT EMPLOYEE_ID, SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID = 10;

問合せ結果変更通知(QRCN)

注意:
QRCNを使用するには、データベースのCOMPATIBLE初期化パラメータが11.0.0以上であり、自動UNDO管理(AUM)が有効(デフォルト設定)である必要があります。
COMPATIBLE初期化パラメータの詳細は、『Oracle Database管理者ガイド』を参照してください。

AUMの詳細は、『Oracle Database管理者ガイド』を参照してください。

アプリケーションで問合せ結果変更通知(QRCN)に対する問合せが登録されると、その問合せの結果がトランザクションによって変更されてコミットされるたびに、データベースからアプリケーションにQRCNが送信されます。

たとえば、アプリケーションで例11-1のQRCNに対する問合せが登録されると、問合せ結果セットが変更された場合のみ、つまり、次のデータ操作言語(DML)文のいずれかがコミットされた場合にのみ、データベースからアプリケーションにQRCNが送信されます。

- 問合せの条件句(DEPARTMENT_ID = 10)を満たす行のINSERTまたはDELETE。

- 問合せの条件句(DEPARTMENT_ID = 10)を満たしている行のEMPLOYEE_IDまたはSALARY列へのUPDATE。

- 行の値が10から10以外の値に変更され、その行が結果セットから削除される原因となったDEPARTMENT_ID列へのUPDATE。

- 行の値が10以外の値から10に変更され、その行が結果セットに追加される原因となったDEPARTMENT_ID列へのUPDATE。

デフォルトの通知タイプはOCNです。QRCNの場合は、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_QUERYを指定します。

QRCNでは、保証モード(デフォルト)またはベストエフォート・モードを選択できます。

内容は次のとおりです。

- 保証モード

- ベストエフォート・モード

保証モード

保証モードでは、誤検出はありません。つまり、問合せ結果セットの変更が保証される場合にのみ、データベースからアプリケーションにQRCNが送信されます。

たとえば、アプリケーションで例11-1のQRCNに対する問合せが登録され、従業員201が部門10に所属しており、次の文が実行されるとします。

UPDATE EMPLOYEES
SET SALARY = SALARY + 10
WHERE EMPLOYEE_ID = 201;

UPDATE EMPLOYEES
SET SALARY = SALARY - 10
WHERE EMPLOYEE_ID = 201;

COMMIT;

このトランザクションの各UPDATE文によって問合せ結果セットは変更されますが、各文を合計すると問合せ結果セットへの影響はないため、このトランザクションに対してはデータベースからアプリケーションにQRCNは送信されません。

保証モードでは、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_BEST_EFFORTではなくQOS_QUERYを指定します。

問合せの中には、保証モードのQRCNに対して複雑すぎるものがあります。保証モードで登録可能な問合せの特性は、「保証モードでQRCNに対して登録可能な問合せ」を参照してください。

ベストエフォート・モード

保証モードでは複雑すぎる問合せの中には、ベストエフォート・モードでQRCNに対して登録できるものがあります。このモードでは、簡略バージョンの問合せがCQNによって作成および登録されます。

たとえば、例11-2の問合せは、集計関数SUMを含んでおり、保証モードのQRCNに対しては複雑すぎます。

例11-2 保証モードのQRCNに対して複雑すぎる問合せ

SELECT SUM(SALARY)
FROM EMPLOYEES
WHERE DEPARTMENT_ID = 20;

ベストエフォート・モードでは、例11-2の問合せの次のような簡略バージョンがCQNによって登録されます。

SELECT SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID = 20;

元の問合せの結果が変更されるたびに、その簡略バージョンの結果も変更されるため、簡略化が原因で通知が失われることはありません。ただし、簡略バージョンの結果は元の問合せの結果が変更されなくても変更される場合があるため、簡略化によって誤検出が発生することがあります。

ベストエフォート・モードでは、データベースは次の処理を行います。

- 通知関連の処理によるOLTPレスポンスのオーバーヘッドを次のように最小化します。

- 単一表問合せの場合、データベースでは、どの列が変更されたか、および変更された行によってどの条件句が満たされたかに基づいて、問合せ結果が変更されたかどうかを判断します。

- 複数表問合せ(結合)の場合、データベースでは、複数の表の間の主キー/外部キー制約関係を使用して、問合せ結果が変更されたかどうかを判断します。

- DML文によって問合せ結果セットが変更されるたびに、最初のDML文によって行われた変更が後続のDML文によって無効になった場合でも、アプリケーションにQRCNを送信します。

ベストエフォート・モードでのオーバーヘッドを最小化により、CQNで簡略化されない問合せに対しても、誤検出がまれに発生します。たとえば、例11-1の問合せと、「保証モード」のトランザクションを想定します。ベストエフォート・モードでは、CQNによって問合せは簡略化されませんが、トランザクションによって誤検出が発生します。

一部のタイプの問合せは非常に簡略化されているため、無効化がオブジェクト・レベルで発生します。つまり、該当の問合せで参照されるいずれかのオブジェクトが変更されるたびに発生します。このような問合せの例としては、サポートされていない列型を使用する問合せや、副問合せを含んでいる問合せがあります。この問題を解決するには、元の問合せを書き換えます。

たとえば、例11-3の問合せは、副問合せを含んでいるため、保証モードのQRCNに対しては複雑すぎます。

例11-3 簡略バージョンによってオブジェクトが無効になる問合せ

SELECT SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IN (
SELECT DEPARTMENT_ID
FROM DEPARTMENTS
WHERE LOCATION_ID = 1700
);

ベストエフォート・モードでは、例11-3の問合せがCQNによって次のように簡略化されます。

SELECT * FROM EMPLOYEES, DEPARTMENTS;

問合せの簡略化により、オブジェクトが無効になる場合があります。ただし、元の問合せを次のように書き換えると、その問合せを保証モードまたはベストエフォート・モードで登録できます。

SELECT SALARY
FROM EMPLOYEES, DEPARTMENTS
WHERE EMPLOYEES.DEPARTMENT_ID = DEPARTMENTS.DEPARTMENT_ID
AND DEPARTMENTS.LOCATION_ID = 1700;

ベストエフォート・モードでのみ登録可能な問合せについては、「ベストエフォート・モードでのみQRCNに対して登録可能な問合せ」で説明します。

デフォルトのQRCNモードは保証モードです。ベストエフォート・モードの場合は、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_BEST_EFFORTを指定します。

通知を生成するイベント

通知を生成するイベントは次のとおりです。

- DMLトランザクションのコミット

- DDL文のコミット

- 登録解除

- グローバル・イベント

DMLトランザクションのコミット

通知タイプがOCNの場合、1つ以上の登録済オブジェクトを変更するあらゆるDMLトランザクションで、コミット時に各オブジェクトに対して通知が1つ生成されます。

通知タイプがQRCNの場合、1つ以上の登録済問合せの結果を変更するあらゆるDMLトランザクションで、コミット時に通知が生成されます。この通知には、結果が変更された問合せのIDが含まれます。

どちらの通知タイプでも、通知には次の内容が含まれます。

- 変更された各表の名前

- 操作タイプ(INSERT、UPDATEまたはDELETE)

- 変更された各行のROWID(ROWIDオプションを使用して登録が作成され、変更された行の数があまり多くない場合)。詳細は、「ROWIDオプション」を参照。

DDL文のコミット

OCNとQRCNの両方について、次のデータ定義言語(DDL)文により、コミット時に通知が生成されます。

- ALTER TABLE

- TRUNCATE TABLE

- FLASHBACK TABLE

- DROP TABLE

注意:
通知タイプがOCNの場合、DROP TABLE文のコミットによってDROP NOTIFICATIONが生成されます。
削除された表に対する問合せのOCN登録は、その表(すでに存在しない表)から関連付けが解除されますが、登録自体は存続します。これらの登録のいずれかが削除された表以外のオブジェクトに関連付けられている場合、それらのオブジェクトに対する変更がコミットされると、通知は引き続き生成されます。削除された表にのみ関連付けられていた登録も存続し、その作成者は問合せ(およびその参照オブジェクト)をその登録に追加できます。

OCN登録は、問合せの登録時点におけるオブジェクトのバージョンと定義に基づきます。オブジェクトが削除されると、そのオブジェクトの登録の関連付けはオブジェクトから永続的に解除されます。オブジェクトが削除されたオブジェクトと同じ名前および同じスキーマで作成された場合、作成されたオブジェクトは削除されたオブジェクトに関連付けられていたOCN登録には関連付けられません。

通知タイプがQRCNの場合、次のようになります。

- 通知には次の内容が含まれます。

- 結果が変更された問合せのID

- 変更された表の名前

- DDL操作のタイプ

- 登録済問合せを無効にするDDL操作の中には、その問合せを登録解除する原因となるものもあります。
たとえば、次の問合せがQRCNに対して登録されるとします。

SELECT COL1 FROM TEST_TABLE
WHERE COL2 = 1;

TEST_TABLEのスキーマは次のとおりとします。

(COL1 NUMBER, COL2 NUMBER, COL3 NUMBER)

この場合、次のDDL文により、コミット時に問合せが無効になり、問合せが登録から削除されます。

ALTER TABLE DROP COLUMN COL2;

登録解除

OCNとQRCNの両方について、登録解除(データベースからの登録の削除)によって通知が生成されます。データベースで登録が削除される原因は次のとおりです。

- タイムアウト
問合せの登録時にTIMEOUTがゼロ以外の値で指定された場合、指定の時間間隔後にデータベースによって登録がパージされます。

問合せの登録時にQOS_DEREG_NFYが指定された場合、最初の通知の生成後にデータベースによって登録がパージされます。

- 権限の消失
登録済問合せに関連付けられているオブジェクトに対する権限が消失し、通知タイプがOCNの場合、データベースによって登録がパージされます。(通知タイプがQRCNの場合は、データベースによってその問合せは登録から削除されますが、登録はパージされません。)

問合せの登録に必要な権限は、「CQN登録を作成するための前提条件」を参照してください。

クライアント・アプリケーションによる明示的な登録解除の実行時には、通知は生成されません。

グローバル・イベント

グローバル・イベントEVENT_STARTUPおよびEVENT_SHUTDOWNにより、通知が生成されます。

Oracle RAC環境では、次のイベントによって通知が生成されます。

- EVENT_STARTUP(データベースの最初のインスタンスの起動時)

- EVENT_SHUTDOWN(データベースの最終インスタンスの停止時)

- EVENT_SHUTDOWN_ANY(データベースのいずれかのインスタンスの停止時)

前述のグローバル・イベントは、DBMS_CQ_NOTIFICATIONパッケージで定義されている定数です。

参照:
DBMS_CQ_NOTIFICATIONパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

通知内容

通知には、次の情報の一部またはすべてが含まれます。

- イベントのタイプ(次のいずれか)

- 起動

- オブジェクト変更

- 問合せ結果変更

- 登録解除

- 停止

- 影響を受けた登録の登録ID

- 変更されたオブジェクトの名前

- ROWIDオプションが指定されている場合の、変更された行のROWID

- 通知タイプがQRCNの場合の、結果が変更された問合せの問合せID

- 通知がDMLまたはDDL文の結果として生成された場合

- 変更された表の名前の配列

- 操作タイプ(INSERT、UPDATEなど)

通知には、変更されたデータ自体は含まれません。たとえば、5000から6000への月給の増額があっても、通知には示されません。変更されたオブジェクト、行または問合せ結果の最新の値を取得するには、アプリケーションからデータベースに問い合せる必要があります。

CQNに適したアプリケーション

CQNに適したアプリケーションは、データベースへのネットワーク・ラウンドトリップを回避するために、変更の頻度の低いオブジェクトに対する問合せの結果セットを中間層にキャッシュするアプリケーションです。これらのアプリケーションでは、CQNを使用して、キャッシュされる問合せを登録できます。このようなアプリケーションは、通知を受信すると、登録済問合せを再実行してキャッシュをリフレッシュできます。

このようなアプリケーションの例としては、Webフォーラムがあります。Webフォーラムのユーザーは、コンテンツがデータベースに挿入されても、挿入後すぐにそのコンテンツを参照する必要はないため、このアプリケーションでは情報を中間層にキャッシュし、キャッシュをいつリフレッシュするかをCQNで指示できます。

図11-1に、データがデータベースから提供され、中間にキャッシュされた後、インターネット経由でアクセスされる一般的な使用例を示します。

図11-1 中間層キャッシュ

中間層のアプリケーションは、キャッシュをデータベースと相対でできるかぎり最新の状態に保ちつつ、データベース・オブジェクトのキャッシュ・コピーに迅速にアクセスする必要があります。キャッシュ・データは、トランザクションでデータが変更されてコミットされると不要になるため、アプリケーションが不正な結果にアクセスする危険性があります。アプリケーションがCQNを使用している場合、データベースは、登録済オブジェクトに変更が発生した時点で変更内容の詳細を使用して通知を公開できます。この通知に応答して、アプリケーションではキャッシュ・データをバックエンド・データベースからフェッチしてリフレッシュできます。

図11-2に、中間層のWebクライアントが通知を受信して処理するプロセスを示します。

図11-2 連続問合せ通知(CQN)の基本プロセス

図11-2の各手順は次のとおりです(PL/SQLを使用して登録が作成され、アプリケーションによりHR.EMPLOYEESに対する問合せの結果セットがキャッシュされている場合)。

1. 開発者は、PL/SQLを使用して、問合せに対するCQN登録を作成します。このプロセスでは、通知を処理するストアドPL/SQLプロシージャを作成した後、PL/SQL CQNインタフェースを使用して問合せに対する登録を作成し、作成したPL/SQLプロシージャを通知ハンドラとして指定します。

2. データベースでは、データ辞書に登録情報が移入されます。

3. ユーザーがバックエンド・データベースのHR.EMPLOYEES表の行を更新し、その更新をコミットすると、問合せ結果が変更されます。これで、中間層でキャッシュされていたHR.EMPLOYEESのデータが無効になります。

4. データベースにより、内部キューに変更を説明するメッセージが追加されます。

5. データベースからJOBQバックグラウンド・プロセスに、通知メッセージが通知されます。

6. JOBQプロセスにより、クライアント・アプリケーションから指定されたストアド・プロシージャが実行されます。この例では、JOBQからサーバー側PL/SQLプロシージャにデータが渡されます。PL/SQL通知ハンドラの実装により、通知の処理方法が決まります。

7. 開発者は、サーバー側PL/SQLプロシージャ内に、登録済オブジェクトに対する変更を中間層のクライアント・アプリケーションに通知するための論理を実装できます。たとえば、HR.EMPLOYEES内で変更された行のROWIDをアプリケーションに通知します。

8. 中間層のクライアント・アプリケーションでは、バックエンド・データベースを問い合せて、変更があった行のデータを取得します。

9. クライアント・アプリケーションにより、キャッシュがこのデータで更新されます。

CQN登録の作成

CQN登録により、1つ以上の問合せのリストが通知タイプおよび通知ハンドラに関連付けられます。

通知タイプは、OCNまたはQRCNです。これらのタイプの詳細は、「オブジェクト変更通知(OCN)」および「問合せ結果変更通知(QRCN)」を参照してください。

CQN登録を作成するには、PL/SQLインタフェースまたはOCIを使用できます。PL/SQLインタフェースを使用する場合、通知ハンドラはサーバー側のPL/SQLストアド・プロシージャになり、OCIを使用する場合、通知ハンドラはクライアント側のCコールバック・プロシージャになります。(このトピックでは、PL/SQLインタフェースのみについて説明します。OCIの詳細は『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください)。

作成された登録は、データベースに格納されます。Oracle RAC環境では、この登録はすべてのデータベース・インタフェースから参照できます。いずれかのデータベース・インスタンスの問合せ結果がトランザクションによって変更されると、通知が生成されます。

デフォルトでは、登録は、それを作成したアプリケーションによって明示的に登録解除されるまで、または(権限の消失などが原因で)データベースによって暗黙的にパージされるまで存続します。

内容は次のとおりです。

- PL/SQL CQN登録インタフェース

- CQN登録オプション

- CQN登録を作成するための前提条件

- オブジェクト変更通知(OCN)に対して登録可能な問合せ

- 問合せ結果変更通知(QRCN)に対して登録可能な問合せ

- PL/SQLを介したCQNに対する問合せの登録

- CQN登録のベスト・プラクティス

- CQN登録のトラブルシューティング

PL/SQL CQN登録インタフェース

PL/SQL CQN登録インタフェースは、DBMS_CQ_NOTIFICATIONパッケージを使用して実装されます。登録ブロックを開くには、DBMS_CQ_NOTIFICATION.NEW_REG_STARTファンクションを使用します。通知タイプや通知ハンドラなどの登録詳細は、CQ_NOTIFICATION$_REG_INFOオブジェクトの一部として指定し、このオブジェクトは引数としてNEW_REG_STARTプロシージャに渡されます。登録ブロックがオープンの間に実行したすべての問合せは、CQNに登録されます。通知タイプとしてQRCNを指定すると、データベースによって各問合せに問合せIDが割り当てられます。この問合せIDは、DBMS_CQ_NOTIFICATION.CQ_NOTIFICATION_QUERYIDファンクションを使用して取得できます。登録ブロックをクローズするには、DBMS_CQ_NOTIFICATION.REG_ENDファンクションを使用します。

この手順の詳細は、「PL/SQLを介したCQNに対する問合せの登録」を参照してください。

参照:
DBMS_CQ_NOTIFICATIONパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

CQN登録オプション

CQN登録のデフォルトは、表11-1に示すオプションを使用して変更できます。

表11-1 連続問合せ通知登録オプション

オプション

説明

通知タイプ

QRCNを指定します(デフォルトはOCN)。

QRCNモード脚注1

ベストエフォート・モードを指定します(デフォルトは保証モード)。

ROWID

変更された各行のROWID疑似列の値を通知に含めます。

操作フィルタ脚注2

指定したフィルタ条件を操作タイプが満たした場合のみ、通知を公開します。

トランザクション・ラグ脚注2

非推奨。かわりに通知グループ化を使用してください。

通知グループ化

通知のグループ化方法を指定します。

信頼可能

通知を(デフォルトの共有メモリーではなく)永続データベース・キューに格納します。

通知時にパージ

最初の通知後に登録をパージします。

タイムアウト

指定の時間間隔後に登録をパージします。

脚注1 通知タイプがQRCNの場合にのみ適用されます。

脚注2 通知タイプがOCNの場合にのみ適用されます。

内容は次のとおりです。

- 「通知タイプ」オプション

- QRCNモード(QRCN通知タイプのみ)

- ROWIDオプション

- 操作フィルタ・オプション(OCN通知タイプのみ)

- トランザクション・ラグ・オプション(OCN通知タイプのみ)

- 通知グループ化オプション

- 信頼可能オプション

- 「通知時にパージ」および「タイムアウト」オプション

「通知タイプ」オプション

通知タイプは、OCN(「オブジェクト変更通知(OCN)」を参照)およびQRCN(「問合せ結果変更通知(QRCN)」を参照)です。

QRCNモード(QRCN通知タイプのみ)

QRCNモード・オプションは、通知タイプがQRCNの場合にのみ適用されます。通知タイプをQRCNに設定する手順は、「「通知タイプ」オプション」を参照してください。

QRCNモードには、保証モード(「保証モード」を参照)とベストエフォート・モード(「ベストエフォート・モード」を参照)があります。

デフォルトは保証モードです。ベストエフォート・モードの場合は、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_BEST_EFFORTを指定します。

ROWIDオプション

ROWIDオプションにより、変更された行それぞれのROWID疑似列の値(その行のrowid)が通知に含まれるようになります。変更された各行のROWIDオプションを通知に含めるには、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_ROWIDSを指定します。

注意:
ハイブリッド列圧縮(HCC)で圧縮された表の行を更新すると、行のROWIDが変更されます。特定のOracleストレージ・システムの機能であるHCCの詳細は、『Oracle Database概要』を参照してください。

アプリケーションでは、次の形式の問合せを実行すると、変更された行の内容を通知のROWID情報から取得できます。

SELECT * FROM table_name_from_notification
WHERE ROWID = rowid_from_notification;

ROWIDは、外部文字列形式で公開されます。通常のヒープ表では、ROWIDの長さは18バイトです。索引構成表(IOT)では、ROWIDの長さは主キーのサイズによって異なり、18バイトより長い場合があります。

ROWIDに十分なメモリーがサーバーにない場合、通知はFULL-TABLE-NOTIFICATIONにロールアップされることがあります(これは、通知記述子内の特殊フラグで示されます)。FULL-TABLE-NOTIFICATIONに対して考えられる原因は次のとおりです。

- ROWIDによって消費される共有メモリーの合計が動的共有プール・サイズの1%を超えています。

- 1回のトランザクションで1つの登録済オブジェクト内で変更された行が多すぎます(上限は約80行)。

- IOTについて変更された行の論理ROWIDの合計長が長すぎます(上限は約1800バイト)。

- 通知グループ化オプションNTFN_GROUPING_TYPEに値DBMS_CQ_NOTIFICATION.NTFN_GROUPING_TYPE_SUMMARYが指定されています(「通知グループ化オプション」を参照)。

FULL-TABLE-NOTIFICATIONにはROWIDは含まれないため、これを受信したアプリケーションでは表全体(つまり、すべての行)が変更された可能性があるとみなされます。

操作フィルタ・オプション(OCN通知タイプのみ)

操作フィルタ・オプションは、通知タイプがOCNの場合にのみ適用されます。

操作フィルタ・オプションを使用すると、通知を生成する操作のタイプを指定できます。

デフォルトは全操作です。一部の操作でのみ通知が生成されるように指定するには、CQ_NOTIFICATION$_REG_INFOオブジェクトのOPERATIONS_FILTER属性を使用します。OPERATIONS_FILTER属性では、操作のタイプを表す定数を使用してタイプを指定し、この定数は、DBMS_CQ_NOTIFICATIONパッケージで次のように定義されています。

操作

定数

INSERT

DBMS_CQ_NOTIFICATION.INSERTOP

UPDATE

DBMS_CQ_NOTIFICATION.UPDATEOP

DELETE

DBMS_CQ_NOTIFICATION.DELETEOP

ALTEROP

DBMS_CQ_NOTIFICATION.ALTEROP

DROPOP

DBMS_CQ_NOTIFICATION.DROPOP

UNKNOWNOP

DBMS_CQ_NOTIFICATION.UNKNOWNOP

すべて(デフォルト)

DBMS_CQ_NOTIFICATION.ALL_OPERATIONS

複数の操作を指定するには、ビット単位のORを使用します。次に例を示します。

DBMS_CQ_NOTIFICATION.INSERTOP + DBMS_CQ_NOTIFICATION.DELETEOP

QOS_QUERYは通知タイプとしてQRCNを指定するため、QOSFLAGS属性にQOS_QUERYも指定した場合はOPERATIONS_FILTERは無効です。

参照:
DBMS_CQ_NOTIFICATIONパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

トランザクション・ラグ・オプション(OCN通知タイプのみ)

トランザクション・ラグ・オプションは、通知タイプがOCNの場合にのみ適用されます。

注意:
このオプションは非推奨です。フロー制御の通知を実装するには、「通知グループ化オプション」を使用してください。

トランザクション・ラグ・オプションでは、クライアント・アプリケーションがデータベースから遅れることのできるトランザクション数を指定します。数が0の場合、登録済オブジェクトを変更するトランザクションごとに通知が送信されます。数が5の場合、登録済オブジェクトを変更するトランザクションのうち5番目ごとに通知が送信されます。データベースでは、クライアントで中間の変更が失われないように、中間の変更をオブジェクトの粒度で追跡して通知に含めます。

0より大きいトランザクション・ラグが役立つのは、アプリケーションでフロー制御の通知を実装している場合のみです。アプリケーションでは、通知がラグに達する程度に十分な頻度で生成されるようにし、無限に遅延されないようにしてください。

TRANSACTION_LAGを指定すると、QOS_ROWIDSも指定した場合でも、通知にROWIDは含まれません。

通知グループ化オプション

デフォルトでは、通知はその原因となるイベントの直後に生成されます。

通知グループ化オプションは、CQ_NOTIFICATION$_REG_INFOオブジェクトの属性であり、次の種類があります。

属性

説明

NTFN_GROUPING_CLASS

通知をグループ化するクラスを指定します。使用可能な値は、DBMS_CQ_NOTIFICATION.NTFN_GROUPING_CLASS_TIME(通知を時間でグループ化)と、デフォルトのゼロ(通知をその原因となるイベントの直後に生成)のみです。

NTFN_GROUPING_VALUE

グループを定義する時間間隔を秒単位で指定します。たとえば、この値が900の場合、同じ15分間隔内に生成された通知がグループ化されます。

NTFN_GROUPING_TYPE

次のいずれかのグループ化のタイプを指定します。

- DBMS_CQ_NOTIFICATION.NTFN_GROUPING_TYPE_SUMMARY: グループ内のすべての通知は、単一の通知に要約されます。
注意: ROWIDオプションを指定した場合でも、この単一の通知にはROWIDは含まれません。

- DBMS_CQ_NOTIFICATION.NTFN_GROUPING_TYPE_LAST: グループ内の最後の通知のみが公開され、それより前の通知は破棄されます。

NTFN_GROUPING_START_TIME

通知生成の開始時間を指定します。NULLが指定されると、システム生成の現在の時間がデフォルトになります。

NTFN_GROUPING_REPEAT_COUNT

通知を繰り返す回数を指定します。登録の存続中に通知を永続的に受信するには、DBMS_CQ_NOTIFICATION.NTFN_GROUPING_FOREVERに設定します。登録の存続中に最大でnの通知を受信するには、nに設定します。

注意:
タイムアウト、権限の消失およびグローバル・イベントによって生成された通知は、指定したグループ化間隔が終了する前に公開される場合があります。この場合、グループ化された保留中の通知が存在すると、間隔が終了する前にその通知も公開されます。

信頼可能オプション

デフォルトでは、CQN登録は共有メモリーに格納されます。これをかわりに永続データベース・キューに格納するには(つまり、信頼できる通知を生成するには)、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_RELIABLEを指定します。

信頼できる通知のメリットは、その生成後にデータベースで障害が発生しても、再起動後にその通知を配信できることです。Oracle RAC環境では、正常なデータベース・インスタンスがこの通知を配信できます。

信頼できる通知のデメリットは、デフォルトの通知よりもCPUおよびI/Oのコストが高いことです。

「通知時にパージ」および「タイムアウト」オプション

デフォルトでは、CQN登録は、それを作成したアプリケーションによって明示的に登録解除されるまで、または(権限の消失などが原因で)データベースによって暗黙的にパージされるまで存続します。

登録の最初の通知の生成後にその登録をパージするには、CQ_NOTIFICATION$_REG_INFOオブジェクトのQOSFLAGS属性にQOS_DEREG_NFYを指定します。

n秒後に登録をパージするには、CQ_NOTIFICATION$_REG_INFOオブジェクトのTIMEOUT属性にnを指定します。

「通知時にパージ」と「タイムアウト」の2つのオプションは、同時に使用できます。

CQN登録を作成するための前提条件

CQN登録を作成するための前提条件は次のとおりです。

- 次の権限が必要です。

- DBMS_CQ_NOTIFICATIONパッケージのEXECUTE権限(登録の作成にこのパッケージのサブプログラムを使用)

- CHANGE NOTIFICATIONシステム権限

- 登録するすべてのオブジェクトに対するSELECT権限

登録済の問合せに関連付けられているオブジェクトに対する権限を失うと、通知が生成されます(「登録解除」を参照)。

- SYS以外のユーザーとして接続する必要があります。

- コミットされていないトランザクションの途中でない必要があります。

- dml_locks init.oraパラメータの値がゼロ以外である必要があります(デフォルト値はゼロ以外です)。
(これは、通知を受信するための前提条件でもあります。)

注意:
QRCNを使用するには、データベースのCOMPATIBLE設定が11.0.0以上である必要があります。

オブジェクト変更通知(OCN)に対して登録可能な問合せ

ストアド・プロシージャやREFカーソルの一部として実行される問合せなど、ほとんどの問合せをOCNに対して登録できます。

OCNに対して登録不可能な問合せは次のとおりです。

- 固定表または固定ビューに対する問合せ

- ユーザー・ビューに対する問合せ

- データベース・リンク(dblink)を含む問合せ

- マテリアライズド・ビューでの問合せ

注意:
OCN登録ではシノニムを使用できますが、QRCN登録では使用できません。

問合せ結果変更通知(QRCN)に対して登録可能な問合せ

QRCNに対して保証モードで登録可能な問合せ、QRCNに対してベストエフォート・モードでのみ登録可能な問合せ、およびQRCNに対してどちらのモードでも登録不可能な問合せがあります。(モードの詳細は、「保証モード」および「ベストエフォート・モード」を参照してください。)

内容は次のとおりです。

- 保証モードでQRCNに対して登録可能な問合せ

- ベストエフォート・モードでのみQRCNに対して登録可能な問合せ

- どちらのモードでもQRCNに対して登録不可能な問合せ

保証モードでQRCNに対して登録可能な問合せ

問合せを保証モードでQRCNに対して登録するには、問合せを次のルールに準拠させる必要があります。

- 参照するすべての列がNUMBERまたはVARCHAR2データ型である必要があります。

- 列の式に含まれる算術演算子が次のバイナリ演算子に制限され、そのオペランドが数値データ型の列である必要があります。

- +(加算)

- -(減算、単項マイナスではない)

- *(乗算)

- /(除算)

- 条件句の比較演算子は次の演算子に制限されます。

- <(より小さい)

- <=(以下)

- =(等しい)

- >=(以上)

- >(より大きい)

- <>または!=(等しくない)

- IS NULL

- IS NOT NULL

- 条件句のBoolean演算子はAND、ORおよびNOTに制限されます。

- 問合せに集計関数(SUM、COUNT、AVERAGE、MIN、MAXなど)は含められません。
SQL集計関数のリストについては、『Oracle Database SQL言語リファレンス』を参照してください。

保証モードでは、単一表および一部の内部等価結合に対するほとんどの問合せが可能です(次の例を参照)。

SELECT SALARY FROM EMPLOYEES, DEPARTMENTS
WHERE EMPLOYEES.DEPARTMENT_ID = DEPARTMENTS.DEPARTMENT_ID
AND DEPARTMENTS.LOCATION_ID = 1700;

注意:

- 問合せオプティマイザで使用される実行計画により、問合せが保証モードでは矛盾する場合があります(OR拡張など)。問合せオプティマイザの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

- 保証モードで登録可能な問合せは、ベストエフォート・モードでも登録可能ですが、ベストエフォート・モードではCQNで簡略化されない問合せに対しても誤検出が発生する可能性があるため、結果は異なる場合があります。詳細は、「ベストエフォート・モード」を参照してください。

ベストエフォート・モードでのみQRCNに対して登録可能な問合せ

次のいずれかの条件を満たす問合せは、ベストエフォート・モードでのみQRCNに対して登録可能であり、その簡略バージョンでは通知がオブジェクトの粒度で生成されます。

- 暗号化が有効にされている列を参照する問合せ

- 同じ型の項目がSELECT構文のリストに11以上ある問合せ

- 次のいずれかを使用した式を含む問合せ

- 文字列関数(SUBSTR、LTRIM、RTRIMなど)

- 算術関数(TRUNC、ABS、SQRTなど)
SQL関数のリストについては、『Oracle Database SQL言語リファレンス』を参照してください。

- パターン一致条件LIKEおよびREGEXP_LIKE

- EXISTSまたはNOT EXISTS条件

- 別の表の列で定義されている条件句を使用した論理和を含む問合せ。次に例を示します。

SELECT EMPLOYEE_ID, DEPARTMENT_ID
FROM EMPLOYEES, DEPARTMENTS
WHERE EMPLOYEES.EMPLOYEE_ID = 10
OR DEPARTMENTS.DEPARTMENT_ID = 'IT';

- ユーザーROWIDアクセスを含む問合せ。次に例を示します。

SELECT DEPARTMENT_ID
FROM DEPARTMENTS
WHERE ROWID = 'AAANkdAABAAALinAAF';

- 内部結合以外の結合を含む問合せ

- 次のいずれかを使用した実行計画を含む問合せ

- ビットマップ結合索引、ドメイン索引またはファンクション索引

- UNION ALLまたはCONCATENATION
(問合せ自体の内部、または問合せオプティマイザで選択されたOR拡張実行計画の結果内で使用。)

- ORDER BYまたはGROUP BY
(問合せ自体の内部、または問合せオプティマイザで選択された実行計画内のORDER BYオプションを使用したSORT操作の結果内で使用。)

- オーバーフロー・セグメントがあり、パーティション化された索引構成表(IOT)

- クラスタ・オブジェクト

- パラレル実行

どちらのモードでもQRCNに対して登録不可能な問合せ

次のいずれかを参照する問合せは、保証モードとベストエフォート・モードのどちらでもQRCNに対して登録不可能です。

- ビュー

- 固定表、リモート表または仮想プライベート・データベース(VPD)ポリシーが有効化されている表

- DUAL(SELECT構文のリスト内)

- シノニム

- ユーザー定義のPL/SQLサブプログラムのコール

- 「保証モードでQRCNに対して登録可能な問合せ」にリストされていない演算子

- 集計関数COUNT
(他の集計関数は、ベストエフォート・モードでは登録可能ですが、保証モードでは登録不可能です。)

- アプリケーション・コンテキスト(次の例を参照)

SELECT SALARY FROM EMPLOYEES
WHERE USER = SYS_CONTEXT('USERENV', 'SESSION_USER');

- SYSDATE、SYSTIMESTAMPまたはCURRENT TIMESTAMP

また、マテリアライズド・ビューを使用して問合せオプティマイザがリライトした問合せはQRCNに対して登録できません。問合せオプティマイザの詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

PL/SQLを介したCQNに対する問合せの登録

PL/SQLを使用してCQN登録を作成する手順は、次のとおりです。

1. 通知ハンドラとして機能するストアドPL/SQLプロシージャを作成します。

2. 通知ハンドラの名前、通知タイプ、および登録のその他の属性を指定するCQ_NOTIFICATION$_REG_INFOオブジェクトを作成します。

3. クライアント・アプリケーションで、DBMS_CQ_NOTIFICATION.NEW_REG_STARTファンクションを使用して登録ブロックをオープンします。

4. 登録する問合せを実行します(DML操作またはDDL操作は実行しないでください)。

5. DBMS_CQ_NOTIFICATION.REG_ENDファンクションを使用して登録ブロックをクローズします。

内容は次のとおりです。

- PL/SQL通知ハンドラの作成

- CQ_NOTIFICATION$_REG_INFOオブジェクトの作成

- 通知内の各問合せの識別

- 既存の登録への問合せの追加

参照:
CQ_NOTIFICATION$_REG_INFOオブジェクトとファンクションNEW_REG_STARTおよびREG_ENDの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。それらすべてはDBMS_CQ_NOTIFICATIONパッケージで定義されています。

PL/SQL通知ハンドラの作成

通知ハンドラとして使用するPL/SQLストアド・プロシージャの作成時には、次のシグネチャを含める必要があります。

PROCEDURE schema_name.proc_name(ntfnds IN CQ_NOTIFICATION$_DESCRIPTOR)

このシグネチャで、schema_nameはデータベース・スキーマ名、proc_nameはストアド・プロシージャ名、ntfndsは通知記述子を示します。

通知記述子はCQ_NOTIFICATION$_DESCRIPTORオブジェクトであり、その属性によって変更の詳細(トランザクションID、変更のタイプ、影響を受けた問合せ、変更された表など)が記述されます。

通知記述子ntfndsはJOBQプロセスから通知ハンドラproc_nameに渡され、このハンドラがアプリケーション要件に従って通知を処理します。(これは図11-2の手順6に示します。)

注意:
通知ハンドラは、ジョブ・キュー・プロセス内で実行されます。JOB_QUEUE_PROCESSES初期化パラメータでは、ジョブの実行用に作成できるプロセスの最大数を指定します。PL/SQL通知を受信するには、JOB_QUEUE_PROCESSESをゼロ以外の値に設定する必要があります。

CQ_NOTIFICATION$_REG_INFOオブジェクトの作成

タイプCQ_NOTIFICATION$_REG_INFOのオブジェクトでは、登録済オブジェクトの変更時にデータベースで実行される通知ハンドラを指定します。SQL*Plusでは、次の文を実行してそのタイプ属性を表示できます。

DESC CQ_NOTIFICATION$_REG_INFO

表11-2に、SYS.CQ_NOTIFICATION$_REG_INFOの属性を示します。

表11-2 CQ_NOTIFICATION$_REG_INFOの属性

属性

説明

CALLBACK

通知の生成時に実行されるPL/SQLプロシージャ(通知ハンドラ)の名前を指定します。この名前は、hr.dcn_callbackのようにschema_name.procedure_name形式で指定する必要があります。

QOSFLAGS

1つ以上のサービスのクオリティ・フラグ(DBMS_CQ_NOTIFICATIONパッケージ内の定数)を指定します。この名前と説明は、表11-3を参照してください。

複数のサービスのクオリティ・フラグを指定するには、ビット単位のORを使用します。たとえば、DBMS_CQ_NOTIFICATION.QOS_RELIABLE + DBMS_CQ_NOTIFICATION.QOS_ROWIDSなどです。

TIMEOUT

登録のタイムアウト期間を指定します。0(ゼロ)以外の値に設定する場合は、データベースにより登録がパージされるまでの秒数を指定します。0またはNULLの場合、登録はクライアントにより明示的に解除されるまで存続します。

QOSFLAGS属性およびそのQOS_DEREG_NFYフラグと併用できます。

OPERATIONS_FILTER

OCN(「オブジェクト変更通知(OCN)」を参照)にのみ適用されます。QOS_FLAGS属性にQOS_QUERYフラグが指定されている場合は無効です。

SQL文の型に基づいてメッセージをフィルタリングします。DBMS_CQ_NOTIFICATIONパッケージ内の次の定数を指定できます。

- ALL_OPERATIONS。すべての変更時に通知します。

- INSERTOP。INSERT時に通知します。

- UPDATEOP。UPDATE時に通知します。

- DELETEOP。DELETE時に通知します。

- ALTEROP。ALTER TABLE操作時に通知します。

- DROPOP。DROP TABLE操作時に通知します。

- UNKNOWNOP。不明な操作時に通知します。

ビット単位のORを使用すると、操作の組合せを指定できます。たとえば、DBMS_CQ_NOTIFICATION.INSERTOP + DBMS_CQ_NOTIFICATION.DELETEOPなどです。

TRANSACTION_LAG

非推奨。フロー制御の通知を実装するには、NTFN_GROUPING_*属性を使用してください。

OCN(「オブジェクト変更通知(OCN)」を参照)にのみ適用されます。QOS_FLAGS属性にQOS_QUERYフラグが指定されている場合は無効です。

クライアントがデータベースから遅れることのできるトランザクション数またはデータベース変更数を指定します。0の場合、クライアントは無効化メッセージを生成直後に受信します。5の場合、登録済オブジェクトを変更するトランザクションのうち5番目ごとに通知が送信されます。データベースでは、中間の変更がオブジェクトの粒度で追跡され、変更が通知とともにバンドルされます。そのため、クライアントから中間の変更が失われることはありません。

トランザクションのコミット時にオブジェクトの変更通知をそれ以上の遅延なしで受信する必要のあるほとんどのアプリケーションでは、トランザクション・ラグ0(ゼロ)を選択するように期待されます。ゼロ以外のトランザクション・ラグが役立つのは、アプリケーションで通知に対するフロー制御を実装している場合のみです。ゼロ以外のトランザクション・ラグを使用する場合は、アプリケーションのワークロードのプロパティを、通知が妥当な頻度で生成されるように設定することをお薦めします。そうしないと、ラグに達するまで通知が無限に遅延する可能性があります。

TRANSACTION_LAGを指定すると、登録時にQOS_ROWIDSを指定した場合にも、通知メッセージにはROWIDレベルの粒度を使用できなくなります。

NTFN_GROUPING_CLASS

通知をグループ化するクラスを指定します。使用可能な値はDBMS_CQ_NOTIFICATION.NTFN_GROUPING_CLASS_TIME(通知を時間でグループ化)のみです。

NTFN_GROUPING_VALUE

グループを定義する時間間隔を秒単位で指定します。たとえば、この値が900の場合、同じ15分間隔内に生成された通知がグループ化されます。

NTFN_GROUPING_TYPE

次のいずれかのグループ化のタイプを指定します。

- DBMS_CQ_NOTIFICATION.NTFN_GROUPING_TYPE_SUMMARY: グループ内のすべての通知は、単一の通知に要約されます。

- DBMS_CQ_NOTIFICATION.NTFN_GROUPING_TYPE_LAST: グループ内の最後の通知のみが公開され、それより前の通知は破棄されます。

NTFN_GROUPING_START_TIME

通知生成の開始時間を指定します。NULLが指定されると、システム生成の現在の時間がデフォルトになります。

NTFN_GROUPING_REPEAT_COUNT

通知を繰り返す回数を指定します。登録の存続中に通知を永続的に受信するには、DBMS_CQ_NOTIFICATION.NTFN_GROUPING_FOREVERに設定します。登録の存続中に最大でnの通知を受信するには、nに設定します。

表11-3のサービスのクオリティ・フラグは、DBMS_CQ_NOTIFICATIONパッケージ内の定数です。このフラグは、CQ_NOTIFICATION$_REG_INFOのQOS_FLAGS属性を使用して指定できます(表11-2を参照)。

表11-3 サービスのクオリティ・フラグ

フラグ

説明

QOS_DEREG_NFY

最初の通知後に登録をパージします。

QOS_RELIABLE

通知を永続データベース・キューに格納します。

Oracle RAC環境では、データベース・インスタンスで障害が発生すると、正常なデータベース・インスタンスがキューにある通知メッセージを配信できます。

デフォルト: 通知はより効率のよい共有メモリーに格納されます。

QOS_ROWIDS

変更された各行のROWIDを通知に含めます。

QOS_QUERY

QRCNに対する問合せを登録します(「問合せ結果変更通知(QRCN)」を参照)。

QRCNに対する問合せを登録できない場合は、QOS_BEST_EFFORTも指定していないかぎり、登録時にエラーが生成されます。

デフォルト: OCNに対する問合せが登録されます(「オブジェクト変更通知(OCN)」を参照)。

QOS_BEST_EFFORT

QOS_QUERYと併用されます。問合せ結果変更の評価には複雑すぎる問合せの簡略バージョンを登録します。つまり、QRCNに対する問合せをベストエフォート・モードで登録します(「ベストエフォート・モード」を参照)。

どの問合せが簡略化されているかを確認するには、静的データ・ディクショナリ・ビューDBA_CQ_NOTIFICATION_QUERIESまたはUSER_CQ_NOTIFICATION_QUERIESを問い合せます。これらのビューでは、登録済の各問合せのQUERYIDとテキストが表示されます。

デフォルト: QRCNに対して問合せが保証モードで登録されます(「保証モード」を参照)。

登録済オブジェクトに変更があるたびに、プロシージャHR.dcn_callbackを起動する必要があるとします。例11-4では、HR.dcn_callbackが通知を受け取るように指定するCQ_NOTIFICATION$_REG_INFOオブジェクトを作成します。このオブジェクトを作成するには、DBMS_CQ_NOTIFICATIONパッケージに対するEXECUTE権限が必要です。

例11-4 CQ_NOTIFICATION$_REG_INFOオブジェクトの作成

DECLARE
v_cn_addr CQ_NOTIFICATION$_REG_INFO;

BEGIN
-- Create object:

v_cn_addr := CQ_NOTIFICATION$_REG_INFO (
'HR.dcn_callback',                 -- PL/SQL notification handler
DBMS_CQ_NOTIFICATION.QOS_QUERY     -- notification type QRCN
+ DBMS_CQ_NOTIFICATION.QOS_ROWIDS, -- include rowids of changed objects
0,                          -- registration persists until unregistered
0,                          -- notify on all operations
0                           -- notify immediately
);

-- Register queries: ...
END;
/

通知内の各問合せの識別

問合せの登録済リストに含まれる問合せにより、連続問合せ通知が生成される場合があります。特定の問合せによっていつ通知が生成されるかを確認するには、その問合せのSELECT構文のリストでDBMS_CQ_NOTIFICATION.CQ_NOTIFICATION_QUERYIDファンクションを使用します。次に例を示します。

SELECT EMPLOYEE_ID, SALARY, DBMS_CQ_NOTIFICATION.CQ_NOTIFICATION_QUERYID
FROM EMPLOYEES
WHERE DEPARTMENT_ID = 10;

結果:

EMPLOYEE_ID     SALARY CQ_NOTIFICATION_QUERYID
----------- ---------- -----------------------
200       2800                       0

1 row selected.

問合せによって通知が生成される場合、その通知には問合せIDが含まれます。

既存の登録への問合せの追加

問合せを既存の登録に追加する手順は、次のとおりです。

1. 既存の登録の登録IDを取得します。
これは、保存済の出力または*_CHANGE_NOTIFICATION_REGSの問合せから取得できます。

2. 登録IDをパラメータとして使用し、プロシージャDBMS_CQ_NOTIFICATION.ENABLE_REGをコールして既存の登録をオープンします。

3. 登録する問合せを実行します(DML操作またはDDL操作は実行しないでください)。

4. DBMS_CQ_NOTIFICATION.REG_ENDファンクションを使用して登録をクローズします。

例11-5では、登録IDが21の既存の登録に問合せを追加します。

例11-5 既存の登録への問合せの追加

DECLARE
v_cursor SYS_REFCURSOR;

BEGIN
-- Open existing registration
DBMS_CQ_NOTIFICATION.ENABLE_REG(21);
OPEN v_cursor FOR
-- Run query to be registered
SELECT DEPARTMENT_ID
FROM HR.DEPARTMENTS;  -- register this query
CLOSE v_cursor;
-- Close registration
DBMS_CQ_NOTIFICATION.REG_END;
END;
/

CQN登録のベスト・プラクティス

CQNに最適なパフォーマンスを得るには、次の登録ガイドラインに従ってください。

- 登録する問合せの数を少なくします。可能であれば、ほとんど変更されないオブジェクトを参照する問合せを登録します。
オブジェクトの揮発性が非常に高いと、多数の通知が送信されることになり、そのオーバーヘッドによってOLTPスループットが低下します。

- 同じ通知メッセージが複数の受信者宛に複製されないように、特定のオブジェクトについて重複登録の数を最小限に抑えます。

CQN登録のトラブルシューティング

登録を作成できない場合、または登録を作成しても予期した通知を受信していない場合は、次のような原因が考えられます。

- JOB_QUEUE_PROCESSESパラメータがゼロ以外の値に設定されていません。
このため、通知ハンドラを介してPL/SQL通知を受信できません。

- 登録の作成時にSYSユーザーとして接続しました。
CQN登録を作成するには、SYS以外のユーザーとして接続する必要があります。

- 登録済オブジェクトを変更した後で、そのトランザクションをコミットしていません。
通知は、トランザクションのコミット時にのみ生成されます。

- 登録がデータベースに正常に作成されていません。
確認するには、静的データ・ディクショナリ・ビュー*_CHANGE_NOTIFICATION_REGSを問い合せます。たとえば、次の文により、現行ユーザーに関するすべての登録と登録済オブジェクトが表示されます。

SELECT REGID, TABLE_NAME FROM USER_CHANGE_NOTIFICATION_REGS;

- 通知ハンドラの実行中に実行時エラーが発生しました。
その場合は、プロシージャの実行を試行したJOBQプロセスのトレース・ファイルに記録されます。通常、トレース・ファイルの名前は次の形式になります。

ORACLE_SID_jnumber_PID.trc

たとえば、ORACLE_SIDがdbs1で、JOBQプロセスのプロセスID(PID)が12483の場合、トレース・ファイルの名前は通常、dbs1_j000_12483.trcとなります。

通知ハンドラに'chnf_callback'、登録IDに100を指定して登録が作成されているとします。ここで、'chnf_callback'はデータベースに定義されていないとします。この場合、JOBQトレース・ファイルには次の書式のメッセージが含まれます。

****************************************************************************
Run-time error during execution of PL/SQL cbk chnf_callback for reg CHNF100.
Error in PLSQL notification of msgid:
Queue :
Consumer Name :
PLSQL function :chnf_callback
Exception Occured, Error msg:
ORA-00604: error occurred at recursive SQL level 2
ORA-06550: line 1, column 7:
PLS-00201: identifier 'CHNF_CALLBACK' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
****************************************************************************

通知ハンドラの実行中に実行時エラーが発生した場合は、実際に通知を受信していることを確認するために、簡略バージョンの通知ハンドラを作成してから、アプリケーション・ロジックを徐々に追加してください。

非常に単純な通知ハンドラの例は次のとおりです。

REM Create table in HR schema to hold count of notifications received.
CREATE TABLE nfcount(cnt NUMBER);
INSERT INTO nfcount (cnt) VALUES(0);
COMMIT;
CREATE OR REPLACE PROCEDURE chnf_callback
(ntfnds IN CQ_NOTIFICATION$_DESCRIPTOR)
IS
BEGIN
UPDATE nfcount SET cnt = cnt+1;
COMMIT;
END;
/

- トランザクションがコミットされてからエンド・ユーザーが通知を受信するまでに、タイム・ラグが発生しています。

CQN登録の問合せ

登録のQOSオプションなど、すべての登録に関するトップレベルの情報を確認するには、静的データ・ディクショナリ・ビュー*_CHANGE_NOTIFICATION_REGSを問い合せます。

たとえば、クライアントの登録IDと通知を受信するオブジェクトのリストを取得できます。HRの登録IDと表名を表示するには、次の問合せを使用します。

SELECT regid, table_name FROM USER_CHANGE_NOTIFICATION_REGS;

どの問合せがQRCNに対して登録されているかを確認するには、静的データ・ディクショナリ・ビューUSER_CQ_NOTIFICATION_QUERIESまたはDBA_CQ_NOTIFICATION_QUERIESを問い合せます。これらのビューには、問合せで使用されるバインド値に関する情報が含まれています。これらのビューでは、元の問合せのバインド値が、定数として問合せテキストに含まれます。問合せテキストは、登録済の元の問合せと同等ですが、同一ではない場合があります。

参照:
静的データ・ディクショナリ・ビューUSER_CHANGE_NOTIFICATION_REGSおよびDBA_CQ_NOTIFICATION_QUERIESの詳細は、『Oracle Databaseリファレンス』を参照してください。

通知の解析

トランザクションのコミット時に、データベースでは登録済オブジェクトがトランザクション中に変更されたかどうかが判別されます。変更されたと判別された場合、登録で指定されている通知ハンドラが実行されます。

内容は次のとおりです。

- CQ_NOTIFICATION$_DESCRIPTORオブジェクトの解析

- CQ_NOTIFICATION$_TABLEオブジェクトの解析

- CQ_NOTIFICATION$_QUERYオブジェクトの解析

- CQ_NOTIFICATION$_ROWオブジェクトの解析

CQ_NOTIFICATION$_DESCRIPTORオブジェクトの解析

CQN登録で通知が生成されると、CQ_NOTIFICATION$_DESCRIPTORオブジェクトがデータベースから通知ハンドラに渡されます。通知ハンドラでは、データベース変更の詳細をCQ_NOTIFICATION$_DESCRIPTORオブジェクトの属性から検出できます。

SQL*Plusでは、SYSとして接続し、次の文を実行するとこれらの属性を表示できます。

DESC CQ_NOTIFICATION$_DESCRIPTOR

表11-4に、CQ_NOTIFICATION$_DESCRIPTORの属性の要約を示します。

表11-4 CQ_NOTIFICATION$_DESCRIPTORの属性

属性

説明

REGISTRATION_ID

登録時に戻された登録ID。

TRANSACTION_ID

変更を行ったトランザクションのID。

DBNAME

通知が生成されたデータベースの名前。

EVENT_TYPE

通知をトリガーするデータベース・イベント。たとえば、属性には様々なデータベース・イベントに対応する次の定数を含めることができます。

- EVENT_NONE

- EVENT_STARTUP(インスタンスの起動)

- EVENT_SHUTDOWN(インスタンスの停止 - Oracle RACの場合は最後のインスタンスの停止)

- EVENT_SHUTDOWN_ANY(Oracle RACの場合は任意のインスタンスの停止)

- EVENT_DEREG(登録の削除)

- EVENT_OBJCHANGE(登録済の表に対する変更)

- EVENT_QUERYCHANGE(登録済の結果セットに対する変更)

NUMTABLES

変更された表の数。

TABLE_DESC_ARRAY

このフィールドは、OCN登録の場合にのみ存在します。QRCN登録の場合はNULLになります。

EVENT_TYPEがEVENT_OBJCHANGEの場合は、タイプCQ_NOTIFICATION$_TABLEの表変更記述子のVARRAYとなり、それぞれが変更された表に対応します。CQ_NOTIFICATION$_TABLEの属性は、表11-5を参照してください。

前述以外の場合はNULLになります。

QUERY_DESC_ARRAY

このフィールドは、QRCN登録の場合にのみ存在します。OCN登録の場合はNULLになります。

EVENT_TYPEがEVENT_QUERYCHANGEの場合は、タイプCQ_NOTIFICATION$_QUERYの結果セット変更記述子のVARRAYとなり、それぞれが変更された結果セットに対応します。CQ_NOTIFICATION$_QUERYの属性は、表11-6を参照してください。

前述以外の場合はNULLになります。

CQ_NOTIFICATION$_TABLEオブジェクトの解析

CQ_NOTIFICATION$_DESCRIPTORタイプには、タイプCQ_NOTIFICATION$_TABLEの表記述子のVARRAYを保持する属性TABLE_DESC_ARRAYが含まれています。

SQL*Plusでは、SYSとして接続し、次の文を実行するとこれらの属性を表示できます。

DESC CQ_NOTIFICATION$_TABLE

表11-5に、CQ_NOTIFICATION$_TABLEの属性の要約を示します。

表11-5 CQ_NOTIFICATION$_TABLEの属性

属性

指定 ...

OPFLAGS

変更があった表に対して実行された操作のタイプ。たとえば、属性には様々なデータベース操作に対応する次の定数を含めることができます。

- ALL_ROWSは、DELETE *のように表全体に変更があるか、行レベルの粒度の情報が要求されないか、通知に使用できず、受信者は表全体が変更されたとみなす必要があることを示します。

- UPDATEOPは更新を示します。

- DELETEOPは削除を示します。

- ALTEROPはALTER TABLEを示します。

- DROPOPはDROP TABLEを示します。

- UNKNOWNOPは不明な操作を示します。

TABLE_NAME

変更があった表の名前。

NUMROWS

変更があった行数。

ROW_DESC_ARRAY

タイプCQ_NOTIFICATION$_ROWの行記述子のVARRAY(表11-7を参照)。opflagsにALL_ROWSが設定されていた場合、ROW_DESC_ARRAYメンバーはNULLです。

CQ_NOTIFICATION$_QUERYオブジェクトの解析

CQ_NOTIFICATION$_DESCRIPTORタイプには、タイプCQ_NOTIFICATION$_QUERYの結果セット変更記述子のVARRAYを保持する属性QUERY_DESC_ARRAYが含まれています。

SQL*Plusでは、SYSとして接続し、次の文を実行するとこれらの属性を表示できます。

DESC CQ_NOTIFICATION$_QUERY

表11-6に、CQ_NOTIFICATION$_QUERYの属性の要約を示します。

表11-6 CQ_NOTIFICATION$_QUERYの属性

属性

指定 ...

QUERYID

変更された問合せのID。

QUERYOP

問合せを変更した操作(EVENT_QUERYCHANGEまたはEVENT_DEREG)。

TABLE_DESC_ARRAY

タイプCQ_NOTIFICATION$_TABLEの表変更記述子のVARRAY(それぞれが結果セットの変更の原因となった変更済の表に対応)。CQ_NOTIFICATION$_TABLEの属性は、表11-5を参照してください。

CQ_NOTIFICATION$_ROWオブジェクトの解析

登録中にROWIDオプションが指定されると、CQ_NOTIFICATION$_TABLEタイプにはROW_DESC_ARRAY属性、つまり、変更された行のROWIDを含むタイプCQ_NOTIFICATION$_ROWのVARRAYが設定されます。CQ_NOTIFICATION$_TABLEオブジェクトのOPFLAGSフィールドにALL_ROWSが設定されていた場合、ROWID情報は使用できません。

表11-7に、CQ_NOTIFICATION$_ROWの属性の要約を示します。

表11-7 CQ_NOTIFICATION$_ROWの属性

属性

指定 ...

OPFLAGS

変更があった表に対して実行された操作のタイプ。表11-5のOPFLAGSの説明を参照してください。

ROW_ID

変更された行のROWID。

登録の削除

登録を削除するには、登録IDをパラメータとして使用してプロシージャDBMS_CQ_NOTIFICATION.DEREGISTERをコールします。たとえば、次の文により、登録IDが21の登録が解除されます。

DBMS_CQ_NOTIFICATION.DEREGISTER(21);

登録を作成したユーザーまたはSYSユーザーのみが登録を解除できます。

CQNの構成: 使用例

この使用例では、開発者として従業員データ(名前、所在地、電話番号など)を提供するWebアプリケーションを管理しているとします。このアプリケーションはOracle Application Serverで実行され、使用量が多く、バックエンド・データベースにあるHR.EMPLOYEES表およびHR.DEPARTMENTS表の頻繁な問合せを処理します。この2つの表はあまり変更されないため、アプリケーションでは問合せ結果をキャッシュすることでパフォーマンスを改善できます。キャッシュにより、バックエンド・データベースへのラウンドトリップ、およびサーバー側での実行待機時間が回避されます。

DBMS_CQ_NOTIFICATIONパッケージを使用すると、HR.EMPLOYEES表およびHR.DEPARTMENTS表に基づく問合せを登録できます。CQNを構成する手順は、次のとおりです。

1. 「PL/SQL通知ハンドラの作成」の説明に従って、通知を処理するサーバー側PL/SQLストアド・プロシージャを作成します。

2. 「問合せの登録」の説明に従って、HR.EMPLOYEES表およびHR.DEPARTMENTS表へのQRCNに対する問合せを登録します。

これらの手順の完了後は、手順2で登録した問合せの結果に対する変更がコミットされると、手順1で作成した通知ハンドラによってWebアプリケーションに変更が通知され、この直後に、バックエンド・データベースの問合せによりWebアプリケーションでキャッシュがリフレッシュされます。

内容は次のとおりです。

- PL/SQL通知ハンドラの作成

- 問合せの登録

PL/SQL通知ハンドラの作成

次の説明に従って、通知を処理するサーバー側ストアドPL/SQLプロシージャを作成します。

1. AS SYSDBAでデータベースに接続します。

2. 必要な権限をHRに付与します。

GRANT EXECUTE ON DBMS_CQ_NOTIFICATION TO HR;
GRANT CHANGE NOTIFICATION TO HR;

3. 通知を受信するためにJOB_QUEUE_PROCESSESパラメータを有効化します。

ALTER SYSTEM SET "JOB_QUEUE_PROCESSES"=4;

4. SYS以外のユーザー(HRなど)としてデータベースに接続します。

5. 受信した通知イベントのレコードを保持するデータベース表を作成します。

-- Create table to record notification events.
DROP TABLE nfevents;
CREATE TABLE nfevents (
regid      NUMBER,
event_type NUMBER
);

-- Create table to record notification queries:
DROP TABLE nfqueries;
CREATE TABLE nfqueries (
qid NUMBER,
qop NUMBER
);

-- Create table to record changes to registered tables:
DROP TABLE nftablechanges;
CREATE TABLE nftablechanges (
qid             NUMBER,
table_name      VARCHAR2(100),
table_operation NUMBER
);

-- Create table to record ROWIDs of changed rows:
DROP TABLE nfrowchanges;
CREATE TABLE nfrowchanges (
qid        NUMBER,
table_name VARCHAR2(100),
row_id     VARCHAR2(2000)
);

6. 例11-6に示すように、プロシージャHR.chnf_callbackを作成します。

例11-6 サーバー側PL/SQL通知ハンドラの作成

CREATE OR REPLACE PROCEDURE chnf_callback (
ntfnds IN CQ_NOTIFICATION$_DESCRIPTOR
)
IS
regid           NUMBER;
tbname          VARCHAR2(60);
event_type      NUMBER;
numtables       NUMBER;
operation_type  NUMBER;
numrows         NUMBER;
row_id          VARCHAR2(2000);
numqueries      NUMBER;
qid             NUMBER;
qop             NUMBER;

BEGIN
regid := ntfnds.registration_id;
event_type := ntfnds.event_type;

INSERT INTO nfevents (regid, event_type)
VALUES (chnf_callback.regid, chnf_callback.event_type);

numqueries :=0;

IF (event_type = DBMS_CQ_NOTIFICATION.EVENT_QUERYCHANGE) THEN
numqueries := ntfnds.query_desc_array.count;

FOR i IN 1..numqueries LOOP  -- loop over queries
qid := ntfnds.query_desc_array(i).queryid;
qop := ntfnds.query_desc_array(i).queryop;

INSERT INTO nfqueries (qid, qop)
VALUES(chnf_callback.qid, chnf_callback.qop);

numtables := 0;
numtables := ntfnds.query_desc_array(i).table_desc_array.count;

FOR j IN 1..numtables LOOP  -- loop over tables
tbname :=
ntfnds.query_desc_array(i).table_desc_array(j).table_name;
operation_type :=
ntfnds.query_desc_array(i).table_desc_array(j).Opflags;

INSERT INTO nftablechanges (qid, table_name, table_operation)
VALUES (
chnf_callback.qid,
tbname,
operation_type
);

IF (bitand(operation_type, DBMS_CQ_NOTIFICATION.ALL_ROWS) = 0) THEN
numrows := ntfnds.query_desc_array(i).table_desc_array(j).numrows;
ELSE
numrows :=0;  -- ROWID info not available
END IF;

-- Body of loop does not run when numrows is zero.
FOR k IN 1..numrows LOOP  -- loop over rows
Row_id :=
ntfnds.query_desc_array(i).table_desc_array(j).row_desc_array(k).row_id;

INSERT INTO nfrowchanges (qid, table_name, row_id)
VALUES (chnf_callback.qid, tbname, chnf_callback.Row_id);

END LOOP;  -- loop over rows
END LOOP;  -- loop over tables
END LOOP;  -- loop over queries
END IF;
COMMIT;
END;
/

問合せの登録

通知ハンドラの作成後に、例11-7に示すように、HR.chnf_callbackを通知ハンドラとして指定して、通知を受信する対象となる問合せを登録します。

例11-7 問合せの登録

DECLARE
reginfo   CQ_NOTIFICATION$_REG_INFO;
mgr_id    NUMBER;
dept_id   NUMBER;
v_cursor  SYS_REFCURSOR;
regid     NUMBER;

BEGIN
/* Register two queries for QRNC: */
/* 1. Construct registration information.
chnf_callback is name of notification handler.
QOS_QUERY specifies result-set-change notifications. */

reginfo := cq_notification$_reg_info (
'chnf_callback',
DBMS_CQ_NOTIFICATION.QOS_QUERY,
0, 0, 0
);

/* 2. Create registration. */

regid := DBMS_CQ_NOTIFICATION.new_reg_start(reginfo);

OPEN v_cursor FOR
SELECT dbms_cq_notification.CQ_NOTIFICATION_QUERYID, manager_id
FROM HR.EMPLOYEES
WHERE employee_id = 7902;
CLOSE v_cursor;

OPEN v_cursor FOR
SELECT dbms_cq_notification.CQ_NOTIFICATION_QUERYID, department_id
FROM HR.departments
WHERE department_name = 'IT';
CLOSE v_cursor;

DBMS_CQ_NOTIFICATION.reg_end;
END;
/

新しく作成した登録を表示:

SELECT queryid, regid, TO_CHAR(querytext)
FROM user_cq_notification_queries;

次に類似した結果が得られます。

QUERYID REGID                               TO_CHAR(QUERYTEXT)
------- ----- ------------------------------------------------
22    41 SELECT HR.DEPARTMENTS.DEPARTMENT_ID
FROM HR.DEPARTMENTS
WHERE HR.DEPARTMENTS.DEPARTMENT_NAME  = 'IT'

21    41 SELECT HR.EMPLOYEES.MANAGER_ID
FROM HR.EMPLOYEES
WHERE HR.EMPLOYEES.EMPLOYEE_ID  = 7902

次のトランザクションを実行すると、QUERYIDが22の問合せの結果が変更されます。

UPDATE DEPARTMENTS
SET DEPARTMENT_NAME = 'FINANCE'
WHERE department_name = 'IT';

通知プロシージャchnf_callback(例11-6で作成したプロシージャ)が実行されます。

通知イベントが記録される表を問合せ:

SELECT * FROM nfevents;

次に類似した結果が得られます。

REGID EVENT_TYPE
----- ----------
61          7

EVENT_TYPE 7は、EVENT_QUERYCHANGE(問合せ結果変更)に対応します。

登録済の表への変更が記録される表を問い合せます。

SELECT * FROM nftablechanges;

次に類似した結果が得られます。

REGID     TABLE_NAME TABLE_OPERATION
----- -------------- ---------------
42 HR.DEPARTMENTS               4

TABLE_OPERATION 4は、UPDATEOP(更新操作)に対応します。

変更された行のROWIDが記録される表を問い合せます。

SELECT * FROM nfrowchanges;

次に類似した結果が得られます。

REGID     TABLE_NAME              ROWID
----- -------------- ------------------
61 HR.DEPARTMENTS AAANkdAABAAALinAAF

第III部

アプリケーション開発者向けの高度なトピック

ここでは、高度なテクノロジが必要なアプリケーションや、一部の開発者のみが使用するテクノロジに関するアプリケーション開発の情報について説明します。

章:

- 第12章「Oracle Flashback Technologyの使用」

- 第13章「プログラミング環境の選択」

- 第14章「複数のプログラミング言語を使用したアプリケーションの開発」

- 第15章「Oracle XAを使用したアプリケーションの開発」

- 第16章「パブリッシュ・サブスクライブ・モデルでのアプリケーションの開発」

- 第17章「識別コード・パッケージの使用」

- 第18章「スキーマ・オブジェクトの依存性」

- 第19章「エディションベースの再定義」

参照:
アプリケーション開発の際のパフォーマンス問題の詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

12 Oracle Flashback Technologyの使用

この章では、データベース・アプリケーションにおけるOracle Flashback Technologyの使用について説明します。

内容は次のとおりです。

- Oracle Flashback Technologyの概要

- Oracle Flashback Technologyに関するデータベースの構成

- Oracle Flashback Query(SELECT AS OF)の使用

- Oracle Flashback Version Queryの使用

- Oracle Flashback Transaction Queryの使用

- Oracle Flashback Transaction QueryとOracle Flashback Version Queryの併用

- DBMS_FLASHBACKパッケージの使用

- フラッシュバック・トランザクションの使用

- フラッシュバック・データ・アーカイブの使用(Oracle Total Recall)

- Oracle Flashback Technologyの一般ガイドライン

- Oracle Flashback Technologyのパフォーマンス・ガイドライン

Oracle Flashback Technologyの概要

Oracle Flashback TechnologyとはOracle Database機能のグループの1つであり、Point-in-Timeメディア・リカバリを使用しなくても、データベース・オブジェクトの過去の状態を表示したり、データベース・オブジェクトを前の状態に戻すことができます。

フラッシュバック機能を使用すると、次のことができます。

- 過去のデータを戻す問合せを実行します。

- データベースに対する変更の詳細履歴を示したメタデータを戻す問合せを実行します。

- 表または行を前の時点にリカバリします。

- トランザクション・データの変更を自動的に追跡およびアーカイブします。

- データベースがオンラインである間にトランザクションおよびその依存トランザクションをロールバックします。

Oracle Flashback機能では、自動UNDO管理(AUM)システムにより、トランザクションに関するメタデータおよび履歴データが取得されます。フラッシュバック機能はUNDOデータに依存します。UNDOデータは、個々のトランザクションの結果のレコードです。たとえば、ユーザーが給与を1000から1100に変更するUPDATE文を実行すると、Oracle DatabaseによってUNDOデータに値1000が格納されます。

UNDOデータは永続的であり、データベース停止時にも失われません。フラッシュバック機能を使用すると、UNDOデータを使用して過去のデータを問い合せたり、論理的な損害をリカバリしたりすることができます。UNDOデータは、フラッシュバック機能以外でも、Oracle Databaseによって次の処理に使用されます。

- アクティブなトランザクションのロールバック

- データベースまたはプロセス・リカバリを使用した終了済トランザクションのリカバリ

- SQL問合せに対する読取り一貫性の提供

内容は次のとおりです。

- アプリケーション開発機能

- データベース管理機能

フラッシュバック機能のその他の概要は、『Oracle Database概要』を参照してください。

アプリケーション開発機能

アプリケーション開発では、次のフラッシュバック機能を使用して、履歴データに関するレポートを作成したり、誤った変更を元に戻すことができます。(この機能は、データベース・ユーザーまたは管理者として対話形式でも使用できます。)

Oracle Flashback Query

この機能を使用して、SELECT文のAS OF句で指定した過去のある時点のデータを取得できます。詳細は、「Oracle Flashback Query(SELECT AS OF)の使用」を参照してください。

Oracle Flashback Version Query

この機能を使用して、特定の時間間隔内のメタデータおよび履歴データを取得します(たとえば、ある表の、特定の時間間隔内に存在していたすべての行を表示します)。各行バージョンに関するメタデータには、開始時間と終了時間、変更処理のタイプおよび行バージョンを作成したトランザクションの識別情報が含まれます。Oracle Flashback Version Queryを作成するには、SELECT文でVERSIONS BETWEEN句を使用します。詳細は、「Oracle Flashback Version Queryの使用」を参照してください。

Oracle Flashback Transaction Query

この機能を使用して、特定の時間間隔内における特定のトランザクションまたはすべてのトランザクションのメタデータおよび履歴データを取得できます。Oracle Flashback Transaction Queryを実行するには、静的データ・ディクショナリ・ビューFLASHBACK_TRANSACTION_QUERYから選択します。詳細は、「Oracle Flashback Transaction Queryの使用」を参照してください。

通常、Oracle Flashback Transaction Queryは、対象となる行のトランザクションIDを戻すOracle Flashback Version Queryと併用します(「Oracle Flashback Transaction QueryとOracle Flashback Version Queryの併用」を参照してください)。

DBMS_FLASHBACKパッケージ

この機能は、ある時点の最新データを検査できるよう、Oracle Database内部の時計を過去のある時点まで戻す場合、あるいはデータベースがオンラインである間にトランザクションおよびその依存トランザクションをロールバックする場合に使用できます(「フラッシュバック・トランザクション」を参照してください)。詳細は、「DBMS_FLASHBACKパッケージの使用」を参照してください。

フラッシュバック・トランザクション

フラッシュバック・トランザクションは、データベースがオンラインである間にトランザクションおよびその依存トランザクションをロールバックする場合に使用します。このリカバリ操作では、UNDOデータを使用して対応する補正トランザクションを作成および実行します。このトランザクションによって影響のあったデータが元の状態に戻ります(フラッシュバック・トランザクションは、DBMS_FLASHBACKパッケージの一部です)。詳細は、「DBMS_FLASHBACKパッケージの使用」を参照してください。

フラッシュバック・データ・アーカイブ(Oracle Total Recall)

フラッシュバック・データ・アーカイブを使用して、通常の問合せとOracle Flashback Queryを自動的に追跡およびアーカイブし、スナップショットが古すぎるというエラーが発生することなくデータベース・オブジェクトの各バージョンへのSQLレベルのアクセスを保証します。詳細は、「フラッシュバック・データ・アーカイブの使用(Oracle Total Recall)」を参照してください。

データベース管理機能

次のフラッシュバック機能は、主としてデータ・リカバリ用です。通常、この機能は、データベース管理者としてのみ使用します。

この章では、「アプリケーション開発機能」に重点を置いています。データベース管理機能の詳細は、『Oracle Database管理者ガイド』および『Oracle Databaseバックアップおよびリカバリ・ユーザーズ・ガイド』を参照してください。

Oracle Flashback Table

表の状態を以前の特定の時点までリカバリする場合に、この機能を使用します。データベースがオンラインの間は表のリストアが可能であり、指定した表に対する変更のみ元に戻すことができます。

Oracle Flashback Drop

削除された表をリカバリする場合に、この機能を使用します。この機能によって、DROP TABLE文の影響が無効になります。

Oracle Flashback Database

以前の特定の時点からのすべての変更を元に戻し、データベースをその時点まで迅速に戻す場合に、この機能を使用します。データベースのバックアップをリストアする必要がないため、処理が高速です。

Oracle Flashback Technologyに関するデータベースの構成

アプリケーションでフラッシュバック機能を使用するには、まず、ユーザーまたはデータベース管理者は次の各項で説明する構成タスクを実行する必要があります。

- 自動UNDO管理に関するデータベースの構成

- Oracle Flashback Transaction Queryに関するデータベースの構成

- フラッシュバック・トランザクションに関するデータベースの構成

- 特定のLOB列に対するOracle Flashback操作の有効化

- 必要な権限の付与

自動UNDO管理に関するデータベースの構成

自動UNDO管理(AUM)に関してデータベースを構成するには、ユーザーまたはデータベース管理者は次を実行する必要があります。

- フラッシュバック操作に必要なデータを保持するために十分な領域を持つUNDO表領域を作成します。
データの更新回数が増加するほど、より多くの領域が必要になります。データベース管理者は通常、必要な領域を計算します。

- 『Oracle Database管理者ガイド』の説明に従ってAUMを有効にします。次のデータベース初期化パラメータを設定します。

- UNDO_MANAGEMENT

- UNDO_TABLESPACE

- UNDO_RETENTION

固定サイズのUNDO表領域の場合、Oracle Databaseでは自動的にシステムを調整して、UNDO表領域に最適なUNDOを保持します。

自動的に拡張可能なUNDO領域の場合、Oracle Databaseでは、最長の問合せ期間よりも長いUNDOデータ、およびUNDO_RETENTIONパラメータで指定されたUNDO保持の低いしきい値が保持されます。

注意:
V$UNDOSTAT.TUNED_UNDORETENTIONを問い合せて、現在のUNDO表領域に対してUNDOが保持される期間を決定できます。V$UNDOSTATの詳細は、『Oracle Databaseリファレンス』を参照してください。

UNDO_RETENTIONの設定は、期限切れになっていないUNDOデータが廃棄されないことを保証するものではありません。システムの領域が不十分な場合、Oracle Databaseでは期限切れになっていないUNDOが新しく生成されたUNDOによって上書きされる場合があります。

- UNDO表領域に対しRETENTION GUARANTEE句を指定して、期限切れになっていないUNDOデータが廃棄されないようにします。

参照:
UNDO表領域の作成とAUMの有効化の詳細は、『Oracle Database管理者ガイド』を参照してください。

Oracle Flashback Transaction Queryに関するデータベースの構成

Oracle Flashback Transaction Query機能についてデータベースを構成するには、ユーザーまたはデータベース管理者は次を実行する必要があります。

- Oracle Databaseがバージョン10.0と互換性があることを確認します。

- サプリメンタル・ロギングを有効にします。

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

フラッシュバック・トランザクションに関するデータベースの構成

フラッシュバック・トランザクション機能についてデータベースを構成するには、ユーザーまたはデータベース管理者は次を実行する必要があります。

- データベースがマウントされているが、開かれていない状態で、ARCHIVELOGを有効にします。

ALTER DATABASE ARCHIVELOG;

- 1つ以上のアーカイブ・ログを開きます。

ALTER SYSTEM ARCHIVE LOG CURRENT;

- 必要最低限の主キーのサプリメンタル・ロギングが有効になっていない場合、これを有効にします。

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;

- 外部キーの依存性を追跡する場合は、外部キーのサプリメンタル・ロギングを有効にします。

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (FOREIGN KEY) COLUMNS;

注意:
外部キーの制約が非常に多い場合、外部キーのサプリメンタル・ロギングを有効にしても、パフォーマンス・ペナルティに見合う効果は得られない可能性があります。

特定のLOB列に対するOracle Flashback操作の有効化

表の特定のLOB列に対するフラッシュバック操作を可能にするには、ALTER TABLE文をRETENTIONオプションとともに使用します。

LOB列のUNDOデータは膨大になる場合があるため、フラッシュバック操作で使用するLOB列を定義する必要があります。

参照:
LOB記憶域およびRETENTIONパラメータの詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。

必要な権限の付与

ユーザーまたはデータベース管理者は、次のフラッシュバック機能を使用する必要があるユーザー、ロールまたはアプリケーションに対して権限を付与する必要があります。GRANT文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

Oracle Flashback QueryおよびOracle Flashback Version Query

問合せ中に特定のオブジェクトへのアクセスを許可するには、そのオブジェクトに関するFLASHBACKおよびSELECT権限を付与します。

すべての表に対する問合せを許可するには、FLASHBACK ANY TABLE権限を付与します。

Oracle Flashback Transaction Query

SELECT ANY TRANSACTION権限を付与します。

Oracle Flashback Transaction Queryによって取得したUNDO SQLコードの実行を許可するには、特定の表に対するSELECT、UPDATE、DELETEおよびINSERT権限を付与します。

DBMS_FLASHBACKパッケージ

DBMS_FLASHBACKパッケージの機能にアクセスできるようにするには、DBMS_FLASHBACKに対するEXECUTE権限を付与します。

フラッシュバック・データ・アーカイブ(Oracle Total Recall)

特定のユーザーが特定のフラッシュバック・データ・アーカイブを使用してデータ・アーカイブを表にフラッシュバックできるようにするには、フラッシュバック・データ・アーカイブに対するFLASHBACK ARCHIVEオブジェクト権限をそのユーザーに付与します。FLASHBACK ARCHIVEオブジェクト権限を付与するには、SYSDBAとしてログオンしているか、FLASHBACK ARCHIVE ADMINISTERシステム権限が必要です。

次の文の実行を許可するには、FLASHBACK ARCHIVE ADMINISTERシステム権限を付与します。

- CREATE FLASHBACK ARCHIVE

- ALTER FLASHBACK ARCHIVE

- DROP FLASHBACK ARCHIVE

FLASHBACK ARCHIVE ADMINISTERシステム権限を付与するには、SYSDBAとしてログオンしている必要があります。

CREATE FLASHBACK ARCHIVE文またはALTER FLASHBACK ARCHIVE文を使用して、デフォルトのフラッシュバック・データ・アーカイブを作成するには、SYSDBAとしてログオンしている必要があります。

フラッシュバック・データ・アーカイブで有効にされている表のフラッシュバック・データ・アーカイブを無効にするには、SYSDBAとしてログオンしているか、FLASHBACK ARCHIVE ADMINISTERシステム権限が必要です。

Oracle Flashback Query(SELECT AS OF)の使用

Oracle Flashback Queryを使用するには、SELECT文でAS OF句を使用します。Oracle Flashback Queryにより、過去のある時点で存在していたデータを取得できます。問合せでは、タイムスタンプまたはシステム変更番号(SCN)を使用することで、過去の時点が明示的に参照されます。その時点で最新であったコミット済データが戻されます。

Oracle Flashback Queryは、次のような場合に使用します。

- 失われたデータをリカバリしたり、コミット済の不適切な変更を取り消す場合。
たとえば、誤って行を削除または更新し、コミットしていても、すぐに誤りを元に戻すことができます。

- 現在のデータを過去の特定の時点の対応するデータと比較する場合。
たとえば、前日からのデータの変更を示す日報を作成できます。表データの個々の行の比較、または行セットの共通部分や結合の検索が可能です。

- 特定の時点でのトランザクション・データの状態を確認する場合。
たとえば、特定の日の預金残高を確認できます。

- アプリケーションの設計を簡略化する場合。一時データの類を格納する必要性をなくすことにより簡略化します。
Oracle Flashback Queryにより、データベースから直接過去のデータを取得できます。

- レポート生成ツールなどのパッケージ・アプリケーションを過去のデータに適用します。

- アプリケーションにセルフサービス・エラー修正を提供し、ユーザーが自分のエラーを元に戻して修正できるようにする場合。

内容は次のとおりです。

- 過去のデータの検査およびリストアの例

- Oracle Flashback Queryのガイドライン

SELECT AS OF文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

過去のデータの検査およびリストアの例

たとえば、午後12時30分に従業員Chungの行がemployee表から削除されていることに気付き、午前9時30分にはこのデータがデータベース内に正しく格納されていたことを知っているとします。この場合、Oracle Flashback Queryを使用して午前9時30分の表の内容を調べ、失われたデータを見つけることができます。必要に応じて失われたデータをリストアできます。

例12-1では、2004年4月4日午前9時30分におけるChungのレコードの状態が取得されます。

例12-1 Oracle Flashback Queryを使用した失われた行の取得

SELECT * FROM employees
AS OF TIMESTAMP
TO_TIMESTAMP('2004-04-04 09:30:00', 'YYYY-MM-DD HH:MI:SS')
WHERE last_name = 'Chung';

例12-2では、Chungの情報がemployees表にリストアされます。

例12-2 Oracle Flashback Query後の失われた行のリストア

INSERT INTO employees (
SELECT * FROM employees
AS OF TIMESTAMP
TO_TIMESTAMP('2004-04-04 09:30:00', 'YYYY-MM-DD HH:MI:SS')
WHERE last_name = 'Chung'
);

Oracle Flashback Queryのガイドライン

- 各表に対してAS OF句を指定または省略できます。また、異なる表に異なる時間を指定できます。

注意:
表がフラッシュバック・データ・アーカイブである場合、この表の作成日時よりも過去の日時を指定すると、問合せはこの表に対して、エラーではなく、0行を返します。(フラッシュバック・データ・アーカイブの詳細は、「フラッシュバック・データ・アーカイブの使用(Oracle Total Recall)」を参照してください。)

- 問合せでAS OF句を使用すると、Oracle Flashback Queryと同じセッションで表の作成、切捨てなどのデータ定義言語(DDL)操作、またはINSERT、DELETEなどのデータ操作言語(DML)操作を実行できます。

- Oracle Flashback Queryの結果を、データベースの現在の状態に影響するDDL文またはDML文内で使用するには、INSERT文またはCREATE TABLE AS SELECT文内でAS OF句を使用します。

- 3秒の違い(最大)がアプリケーションにおけるOracle Flashback Queryで重要となる場合、タイムスタンプではなくSCNを使用します。「Oracle Flashback Technologyの一般ガイドライン」を参照してください。

- ビューを定義するSELECT文のAS OF句を使用して、過去のデータを参照するビューを作成できます。
データベース・ホストの現在の時間から引いて相対時間を指定すると、過去の時間が各問合せで再計算されます。次に例を示します。

CREATE VIEW hour_ago AS
SELECT * FROM employees
AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '60' MINUTE);

SYSTIMESTAMPは、データベース・ホスト環境のタイムゾーンを参照します。

- 自己結合または集合演算(INTERSECT、MINUSなど)のAS OF句は、2つの異なる時間のデータを抽出または比較するために使用できます。
Oracle Flashback Queryの前にCREATE TABLE AS SELECT文またはINSERT INTO TABLE SELECT文を使用すると、結果を格納できます。たとえば、次の問合せでは、1時間前に存在していた行がemployees表に再挿入されます。

INSERT INTO employees
(SELECT * FROM employees
AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '60' MINUTE)
MINUS SELECT * FROM employees;

SYSTIMESTAMPは、データベース・ホスト環境のタイムゾーンを参照します。

Oracle Flashback Version Queryの使用

特定の時間間隔内に存在していた、特定の行の様々なバージョンを取得するには、Oracle Flashback Version Queryを使用します。COMMIT文が実行されると、そのたびに行バージョンが作成されます。

SELECT文でVERSIONS BETWEEN句を使用して、Oracle Flashback Version Queryを指定します。構文は次のとおりです。

VERSIONS {BETWEEN {SCN | TIMESTAMP} start AND end}

ここで、startおよびendはそれぞれ、問合せ対象の時間間隔の開始点と終了点を表す式です。時間間隔にはstartおよびendが含まれます。

Oracle Flashback Version Queryでは、特定の行について、指定した時間間隔内に存在していたすべてのバージョンの各1行を含む表が戻されます。表の各行には、行バージョンに関するメタデータの疑似列が含まれます。これについては表12-1で説明しています。この情報により、特定の変更(誤った変更など)がデータベースにいつ、どのように加えられたかがわかります。

表12-1 Oracle Flashback Version Queryにおける行データ疑似列

疑似列名

説明

VERSIONS_STARTSCN

VERSIONS_STARTTIME

行バージョンが作成されたときの開始システム変更番号(SCN)またはTIMESTAMP。この疑似列によって、データの値が最初に行バージョンに反映された時間が識別されます。この疑似列を使用して、Oracle Flashback TableまたはOracle Flashback Queryにおける過去のターゲット時間を指定できます。

この疑似列がNULLの場合、その行バージョンは、startより前に作成されています。

VERSIONS_ENDSCN

VERSIONS_ENDTIME

行バージョンが期限切れとなったときのSCNまたはTIMESTAMP。

この疑似列がNULLの場合、問合せの時点で行バージョンが最新であったか、またはその行がDELETE操作に対応しています。

VERSIONS_XID

その行バージョンが作成されたトランザクションの識別子。

VERSIONS_OPERATION

トランザクションにより実行された操作。Iは挿入、Dは削除、Uは更新を表します。バージョンは、挿入、削除または更新された行のバージョンです。つまり、INSERT操作後の行、DELETE操作前の行、またはUPDATE操作の影響を受ける行です。

ユーザーによる索引キーの更新の場合、Oracle Flashback Version Queryでは、UPDATE操作がDELETEおよびINSERTの2つの操作として処理される場合があり、Dの後にIのVERSIONS_OPERATIONが続く、2つのバージョンの行で表されます。

指定された行バージョンは、VERSIONS_START*の時間からVERSIONS_END*の時間(ただしこの時間は含まれない)まで有効です。つまり、VERSIONS_START* <= t < VERSIONS_END*である場合、時間tではいつでも有効です。たとえば、次の出力は、2002年9月9日(この日付を含む)から2003年11月25日(この日付は含まない)まで、給与が10243であったことを示します。

VERSIONS_START_TIME     VERSIONS_END_TIME     SALARY
-------------------     -----------------     ------
09-SEP-2003             25-NOV-2003           10243

次に、Oracle Flashback Version Queryの一般的な使用方法を示します。

SELECT versions_startscn, versions_starttime,
versions_endscn, versions_endtime,
versions_xid, versions_operation,
last_name, salary
FROM employees
VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2008-12-18 14:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2008-12-18 17:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE first_name = 'John';

Oracle Flashback Transaction QueryでVERSIONS_XIDを使用して、行の変更を元に戻すために必要なSQLおよびその変更の担当ユーザーなど、このトランザクションのメタデータを検索できます。「Oracle Flashback Transaction Queryの使用」を参照してください。

Flashback Version Queryでは、IOT(索引構成表)でのみ索引専用アクセスができますが、索引高速全スキャンはできません。

参照:
Oracle Flashback Version Queryの疑似列、およびVERSIONS句の構文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

Oracle Flashback Transaction Queryの使用

Oracle Flashback Transaction Queryを使用して、特定の時間間隔内における特定のトランザクションまたはすべてのトランザクションのメタデータおよび履歴データを取得できます。Oracle Flashback Transaction Queryは、静的データ・ディクショナリ・ビューFLASHBACK_TRANSACTION_QUERYの問合せを行います。この表の列の詳細は、『Oracle Databaseリファレンス』を参照してください。

列UNDO_SQLには、トランザクションで実行されたDML操作の論理的に逆の操作となるSQLコードがあります。通常、このコードを使用して、トランザクション中に実行された論理手順を元に戻すことができます。ただし、SQL_UNDOのコードが、元のトランザクションの厳密な逆操作ではない場合があります。たとえば、SQL_UNDO INSERT操作で表に行を戻す場合、その行が削除された行と同じROWIDではないことがあります。

次の文では、トランザクションID、操作、操作の開始SCNおよび終了SCN、操作の担当ユーザー、および操作の論理的な逆操作を示すSQLコードなどのトランザクション情報について、FLASHBACK_TRANSACTION_QUERYビューを問い合せています。

SELECT xid, operation, start_scn, commit_scn, logon_user, undo_sql
FROM flashback_transaction_query
WHERE xid = HEXTORAW('000200030000002D');

次の文では、Oracle Flashback Version Queryを副問合せとして使用し、各行バージョンを、行データの変更を担当するLOGON_USERに関連付けています。

SELECT xid, logon_user
FROM flashback_transaction_query
WHERE xid IN (
SELECT versions_xid FROM employees VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2003-07-18 14:00:00', 'YYYY-MM-DD HH24:MI:SS') AND
TO_TIMESTAMP('2003-07-18 17:00:00', 'YYYY-MM-DD HH24:MI:SS')
);

注意:
XIDをWHERE句に指定せずにFLASHBACK_TRANSACTION_QUERYを問い合せると、問合せによって多数の無関係の行がスキャンされるため、パフォーマンスが低下します。

参照:

- データベース管理者がフラッシュバック表を使用して、個々の行ではなく表全体をリストアする方法の詳細は、『Oracle Databaseバックアップおよびリカバリ・ユーザーズ・ガイド』を参照してください。

- データベース管理者がフラッシュバック表を使用して、個々の行ではなく表全体をリストアする方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

Oracle Flashback Transaction QueryとOracle Flashback Version Queryの併用

この例では、データベース管理者は次のコマンドを実行します。

DROP TABLE emp;
CREATE TABLE emp (
empno   NUMBER PRIMARY KEY,
empname VARCHAR2(16),
salary  NUMBER
);
INSERT INTO emp (empno, empname, salary) VALUES (111, 'Mike', 555);
COMMIT;

DROP TABLE dept;
CREATE TABLE dept (
deptno   NUMBER,
deptname VARCHAR2(32)
);
INSERT INTO dept (deptno, deptname) VALUES (10, 'Accounting');
COMMIT;

この時点で、empおよびdeptにはそれぞれ1行があります。行バージョンに関しては、各表に1つのバージョンを示す1行が含まれます。誤ったトランザクションにより、empno 111が表empから削除されたとします。

UPDATE emp SET salary = salary + 100 WHERE empno = 111;
INSERT INTO dept (deptno, deptname) VALUES (20, 'Finance');
DELETE FROM emp WHERE empno = 111;
COMMIT;

次に、トランザクションにより、新規従業員名とともにempno 111が表empに再挿入されます。

INSERT INTO emp (empno, empname, salary) VALUES (111, 'Tom', 777);
UPDATE emp SET salary = salary + 100 WHERE empno = 111;
UPDATE emp SET salary = salary + 50 WHERE empno = 111;
COMMIT;

データベース管理者はアプリケーション・エラーを検出したため、問題を診断する必要があります。データベース管理者は次の問合せを発行し、empno 111に対応するemp表の行のバージョンを取得します。この問合せでは、Oracle Flashback Version Queryの疑似列が使用されます。

SELECT versions_xid XID, versions_startscn START_SCN,
versions_endscn END_SCN, versions_operation OPERATION,
empname, salary
FROM emp
VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
WHERE empno = 111;

次に類似した結果が得られます。

XID               START_SCN    END_SCN O EMPNAME              SALARY
---------------- ---------- ---------- - ---------------- ----------
09001100B2200000   10093466            I Tom                     927
030002002B210000   10093459            D Mike                    555
0800120096200000   10093375   10093459 I Mike                    555

3 rows selected.

結果表の行は降順の時系列で示しています。3行目は、表が作成されたときに表に挿入された、表empの行のバージョンに対応しています。2行目は、誤ったトランザクションにより削除されたempの行に対応します。1行目は、新規従業員名とともに再挿入されたempの行のバージョンに対応します。

データベース管理者は、トランザクション030002002B210000を誤ったトランザクションとして識別し、Oracle Flashback Transaction Queryを使用して、このトランザクションによるすべての変更を監査します。

SELECT  xid, start_scn, commit_scn, operation, logon_user, undo_sql
FROM flashback_transaction_query
WHERE xid = HEXTORAW('000200030000002D');

次に類似した結果が得られます。

XID               START_SCN COMMIT_SCN OPERATION LOGON_USER
---------------- ---------- ---------- --------- ------------------------------
UNDO_SQL
--------------------------------------------------------------------------------

030002002B210000   10093452   10093459 DELETE    HR
insert into "HR"."EMP"("EMPNO","EMPNAME","SALARY") values ('111','Mike','655');

030002002B210000   10093452   10093459 INSERT    HR
delete from "HR"."DEPT" where ROWID = 'AAATjuAAEAAAAJrAAB';

030002002B210000   10093452   10093459 UPDATE    HR
update "HR"."EMP" set "SALARY" = '555' where ROWID = 'AAATjsAAEAAAAJ7AAA';

030002002B210000   10093452   10093459 BEGIN     HR

4 rows selected.

次に行われる問合せの結果を読みやすくするために、データベース管理者は次のSQL*Plusコマンドを使用します。

COLUMN operation FORMAT A9
COLUMN table_name FORMAT A10
COLUMN table_owner FORMAT A11

誤ったトランザクションおよびそれ以降のすべてのトランザクションを確認するには、データベース管理者は次の問合せを実行します。

SELECT xid, start_scn, commit_scn, operation, table_name, table_owner
FROM flashback_transaction_query
WHERE table_owner = 'HR'
AND start_timestamp >=
TO_TIMESTAMP ('2002-04-16 11:00:00','YYYY-MM-DD HH:MI:SS');

次に類似した結果が得られます。

XID               START_SCN COMMIT_SCN OPERATION TABLE_NAME TABLE_OWNER
---------------- ---------- ---------- --------- ---------- -----------
02000E0074200000   10093435   10093446 INSERT    DEPT       HR
030002002B210000   10093452   10093459 DELETE    EMP        HR
030002002B210000   10093452   10093459 INSERT    DEPT       HR
030002002B210000   10093452   10093459 UPDATE    EMP        HR
0800120096200000   10093374   10093375 INSERT    EMP        HR
09001100B2200000   10093462   10093466 UPDATE    EMP        HR
09001100B2200000   10093462   10093466 UPDATE    EMP        HR
09001100B2200000   10093462   10093466 INSERT    EMP        HR

8 rows selected.

注意:
この問合せではXIDがWHERE句に指定されていないため、多数の無関係の行をスキャンし、パフォーマンスが低下します。

DBMS_FLASHBACKパッケージの使用

DBMS_FLASHBACKパッケージでもOracle Flashback Queryと同じ機能が提供されますが、Oracle Flashback Queryのほうが便利な場合があります。

DBMS_FLASHBACKパッケージはタイムマシンのように機能します。つまり、時計を特定の時点に戻して、過去のその時点にいるかのように通常の問合せを実行し、その後現在に戻ることができます。DBMS_FLASHBACKパッケージを使用して、AS OFやVERSIONS BETWEENなどの特別な句を使用せずに過去のデータに問合せを実行できるため、既存のPL/SQLコードを再使用して、過去の時点のデータベースを問い合せることができます。

DBMS_FLASHBACKパッケージのEXECUTE権限が必要です。

PL/SQLコードでDBMS_FLASHBACKパッケージを使用する手順は、次のとおりです。

1. DBMS_FLASHBACK.ENABLE_AT_TIMEまたはDBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBERを起動して、過去の時間を指定します。

2. 通常の問合せ(AS OFなど、特別なフラッシュバック機能の構文を使用しない)を実行します。DDL操作やDML操作は実行しません。
指定された過去の時間におけるデータベースに対し、問合せが行われます。

3. DBMS_FLASHBACK.DISABLEを起動して現在に戻ります。
再度DBMS_FLASHBACK.ENABLE_AT_TIMEまたはDBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBERを起動する前に、DBMS_FLASHBACK.DISABLEを起動する必要があります。ENABLE/DISABLEのペアはネストできません。

カーソルを使用して問合せの結果を格納するには、カーソルをオープンしてからDBMS_FLASHBACK.DISABLEを起動します。結果を格納し、DBMS_FLASHBACK.DISABLEを起動した後、次のことができます。

- INSERTまたはUPDATE操作を実行し、過去のデータベースの格納結果を使用して現在のデータベースの状態を変更します。

- 現在のデータを過去のデータと比較します。DBMS_FLASHBACK.DISABLEを起動した後、2番目のカーソルをオープンします。過去のデータを取得するには最初のカーソルからフェッチし、現在のデータを取得するには2番目のカーソルからフェッチします。過去のデータを一時表に格納し、その後MINUSやUNIONなどの集合演算子を使用して、過去のデータと現在のデータを比較または結合できます。

DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBERを起動して、いつでも現在のシステム変更番号(SCN)を取得できます。事前のDBMS_FLASHBACK.ENABLEの起動とは関係なく、DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBERでは、必ず現在のSCNが戻されます。

参照:

- DBMS_FLASHBACKパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

フラッシュバック・トランザクションの使用

DBMS_FLASHBACK.TRANSACTION_BACKOUTプロシージャでは、データベースがオンラインである間にトランザクションおよびその依存トランザクションをロールバックします。このリカバリ操作では、UNDOデータを使用して対応する補正トランザクションを作成および実行します。このトランザクションによって影響のあったデータが元の状態に戻ります。

ロールバック中のトランザクションは、次の制約を受けます。

- トランザクションは、データベース表の論理構造を変更するDDL操作を実行できません。

- 次のラージ・オブジェクト(LOB)データ型を使用できません。

- BFILE

- BLOB

- CLOB

- NCLOB

- LogMinerがサポートしていない機能を使用できません。
LogMinerがサポートする機能は、トランザクションをロールバックしているデータベースのCOMPATIBLE初期化パラメータの値によって異なります。デフォルト値は、最新メジャー・リリースのリリース番号です。

トランザクションのフラッシュバックは、LogMinerからSQLデータ型サポートを継承します。したがって、トランザクションにサポートされていないSQLデータ型が含まれていたことが原因でLogMinerで障害が発生した場合、トランザクションのフラッシュバックでも障害が発生します。

一部のデータ型は、LogMinerではサポートされていますが、このような型の列を修正する操作の一端として、Undo情報を生成しません。したがって、トランザクションのフラッシュバックは、このようなデータ型を含む表をサポートしません。これには、BLOB型、CLOB型、およびXML型を含む表が該当します。

参照:

- ロジカル・スタンバイ・データベースでのデータ型およびDDLサポートに関する詳細は、『Oracle Data Guard概要および管理』を参照してください。

- LOBデータ型の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- LogMinerの詳細は、『Oracle Databaseユーティリティ』を参照してください。

- COMPATIBLE初期化パラメータの詳細は、『Oracle Database管理者ガイド』を参照してください。

内容は次のとおりです。

- 依存トランザクション

- TRANSACTION_BACKOUTパラメータ

- TRANSACTION_BACKOUTレポート

依存トランザクション

トランザクションのフラッシュバックのコンテキストでは、トランザクション2は、次のいずれかの方法で、トランザクション1に依存します。

- Write-after-Write依存性
トランザクション1は表の行を変更し、後からトランザクション2が同じ行を変更します。

- 主キーの依存性
ある表の列cには主キー制約が含まれます。この表のある行の列cには値vが入っています。トランザクション1はこの行を削除し、その後、トランザクション2は同じ表に行を1つ挿入し、値vを列cに割り当てます。

- 外部キーの依存性
表bの列b1には、表aの列a1にある外部キー制約が含まれます。トランザクション1はa1の値を変更し、後に、トランザクション2がb1の値を変更します。

TRANSACTION_BACKOUTパラメータ

TRANSACTION_BACKOUTプロシージャのパラメータは次のとおりです。

- バックアウトするトランザクションの数

- 名前またはXIDで識別されたバックアウトするトランザクションのリスト

- 時間ヒント(名前でトランザクションを識別する場合)
任意のトランザクションの開始時間より早い時間を指定します。

- 表12-2のバックアウト・オプション

TRANSACTION_BACKOUTプロシージャの構文およびパラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

表12-2 フラッシュバックTRANSACTION_BACKOUTオプション

オプション

説明

CASCADE

後行順で指定トランザクションおよびすべての依存トランザクションをバックアウトします(つまり、親がバックアウトされる前に子がバックアウトされます)。

CASCADEがない場合、依存トランザクションが指定されていないとエラーが発生します。

NOCASCADE

デフォルト。依存トランザクションを持たないと予想される指定トランザクションをバックアウトします。最初の依存トランザクションによってエラーが発生し、*_FLASHBACK_TXN_REPORTに表示されます。

NOCASCADE_FORCE

依存トランザクションを無視して、指定トランザクションをバックアウトします。サーバーでは、コミット時間とは逆の順序で指定トランザクションのUNDO SQL文を実行します。

制約に違反せず、その結果に満足している場合は、変更をコミットできます。それ以外の場合は、ロールバックできます。

NONCONFLICT_ONLY

指定トランザクションの競合しない行に変更をバックアウトします。データベースの一貫性は保たれますが、トランザクションは完全に失われます。

TRANSACTION_BACKOUTではトランザクションの依存性を分析してDML操作を実行し、レポートを生成します。TRANSACTION_BACKOUTではトランザクション・バックアウトの一環として実行されるDML操作はコミットしませんが、正しい形式で行および表に対する必要なロックを保持し、他の依存関係がシステムに介入しないようにします。トランザクション・バックアウトを永続的なものにするには、明示的にトランザクションをコミットする必要があります。

TRANSACTION_BACKOUTレポート

TRANSACTION_BACKOUTによって生成されたレポートを参照するには、静的データ・ディクショナリ・ビュー*_FLASHBACK_TXN_STATEおよび*_FLASHBACK_TXN_REPORTを問い合せます。

*_FLASHBACK_TXN_STATE

静的データ・ディクショナリ・ビュー*_FLASHBACK_TXN_STATEでは、トランザクションがアクティブであるか、またはバックアウトされているかが示されます。このビューにトランザクションが表示される場合は、バックアウトされています。

*_FLASHBACK_TXN_STATEは、補正トランザクションに対してアトミックにメンテナンスされます。補正トランザクションがバックアウトされている場合、加えられたすべての変更もバックアウトされ、*_FLASHBACK_TXN_STATEにこれが反映されます。たとえば、補正トランザクションctがトランザクションt1およびt2をバックアウトする場合、t1およびt2は*_FLASHBACK_TXN_STATEに表示されます。ct自身が後でバックアウトされる場合、t1およびt2による影響は元に戻され、t1およびt2は*_FLASHBACK_TXN_STATEに表示されなくなります。

参照:
*_FLASHBACK_TXN_STATEの詳細は、『Oracle Databaseリファレンス』を参照してください。

*_FLASHBACK_TXN_REPORT

静的データ・ディクショナリ・ビュー*_FLASHBACK_TXN_REPORTでは、各バックアウト・トランザクションの詳細レポートを生成します。

参照:
*_FLASHBACK_TXN_REPORTの詳細は、『Oracle Databaseリファレンス』を参照してください。

フラッシュバック・データ・アーカイブの使用(Oracle Total Recall)

フラッシュバック・データ・アーカイブにより、その存続期間中、表に対するすべてのトランザクションによる変更を追跡および格納できます。フラッシュバック・データ・アーカイブは、レコード・ステージ・ポリシーと監査レポートのコンプライアンスに役立ちます。

フラッシュバック・データ・アーカイブは、1つ以上の表領域またはその部品で構成されます。フラッシュバック・データ・アーカイブは複数所有できます。SYSDBAとしてログオンしている場合は、システムに対してデフォルトのフラッシュバック・データ・アーカイブを指定できます。フラッシュバック・データ・アーカイブは、保有時間を使用して構成されます。フラッシュバック・データ・アーカイブにアーカイブされたデータは、保有時間中は保持されます。

デフォルトでは、表に対してフラッシュバック・アーカイブは無効になっています。次のすべてに該当する場合は表のフラッシュバック・アーカイブを有効にすることができます。

- 表に対して使用するフラッシュ・データ・アーカイブに対するFLASHBACK ARCHIVEオブジェクト権限がある。

- 表が、ネスト表、クラスタ表、一時表、リモート表または外部表でない。

- 表にLONG列またはネストされた列が含まれない。

- 表に、フラッシュバック・データ・アーカイブによって予約されている次のいずれかの語が列名として使用されていない。

- STARTSCN

- ENDSCN

- RID

- XID

- OP

- OPERATION

表に対してフラッシュバック・アーカイブを有効にした後は、FLASHBACK ARCHIVE ADMINISTERシステム権限がある場合、またはSYSDBAとしてログオンしている場合のみ、これを無効にできます。

特定の表に対してフラッシュバック・データ・アーカイブを選択する場合は、その表のデータ保有要件およびFLASHBACK ARCHIVEオブジェクト権限のあるフラッシュバック・データ・アーカイブの保有時間を考慮してください。

内容は次のとおりです。

- フラッシュバック・データ・アーカイブの作成

- フラッシュバック・データ・アーカイブの変更

- フラッシュバック・データ・アーカイブの削除

- デフォルト・フラッシュバック・データ・アーカイブの指定

- フラッシュバック・データ・アーカイブの有効化および無効化

- フラッシュバック・データ・アーカイブが有効な表のDDL文

- フラッシュバック・データ・アーカイブ・データの表示

- フラッシュバック・データ・アーカイブの使用例

参照:
Oracle Total Recallの詳細は、http://www.oracle.com/database/total-recall.htmlを参照してください。

フラッシュバック・データ・アーカイブの作成

次を指定し、CREATE FLASHBACK ARCHIVE文を使用してフラッシュバック・データ・アーカイブを作成します。

- フラッシュバック・データ・アーカイブの名前

- フラッシュバック・データ・アーカイブの最初の表領域の名前

- (オプション)フラッシュバック・データ・アーカイブが最初の表領域で使用できる最大領域量
デフォルトは無制限です。最初の表領域の領域割当て制限も無制限でないかぎりは、この値を指定する必要があります。指定しない場合、ORA-55621のエラーが発生します。

- 保有時間(表のフラッシュバック・データ・アーカイブのデータの格納が保証されている日数)

- Oracle Database 11gリリース2 (11.2.0.4)において: (オプション)[NO] OPTIMIZE DATAを使用して、フラッシュバック・データ・アーカイブでメンテナンスされる履歴表のデータの記憶域を最適化するかどうか。
デフォルトはNO OPTIMIZE DATAです。

SYSDBAとしてログオンしている場合は、システムに対してこれをデフォルトのフラッシュバック・データ・アーカイブとして指定できます。このオプションを省略しても、後でこのフラッシュバック・データ・アーカイブをデフォルトにできます(「デフォルト・フラッシュバック・データ・アーカイブの指定」を参照)。

例

- デフォルトのフラッシュバック・データ・アーカイブfla1を作成します。これは最大10GBの表領域tbs1を使用し、そのデータは1年間保持されます。

CREATE FLASHBACK ARCHIVE DEFAULT fla1 TABLESPACE tbs1
QUOTA 10G RETENTION 1 YEAR;

- フラッシュバック・データ・アーカイブfla2を作成します。これは表領域tbs2を使用し、そのデータは2年間保持されます。

CREATE FLASHBACK ARCHIVE fla2 TABLESPACE tbs2 RETENTION 2 YEAR;

CREATE FLASHBACK ARCHIVE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

フラッシュバック・データ・アーカイブの変更

ALTER FLASHBACK ARCHIVE文を使用して、次を実行できます。

- フラッシュバック・データ・アーカイブの保有時間を変更します。

- データの一部またはすべてをパージします。

- 表領域を追加、変更、削除します。

注意:
フラッシュバック・データ・アーカイブのすべての表領域を削除すると、エラーが発生します。

SYSDBAとしてログオンしている場合は、ALTER FLASHBACK ARCHIVE文を使用して、特定のファイルをシステムに対するデフォルトのフラッシュバック・データ・アーカイブにすることもできます。

例

- フラッシュバック・データ・アーカイブfla1を、デフォルトのフラッシュバック・データ・アーカイブにします。

ALTER FLASHBACK ARCHIVE fla1 SET DEFAULT;

- フラッシュバック・データ・アーカイブfla1に対して、最大5GBの表領域tbs3を追加します。

ALTER FLASHBACK ARCHIVE fla1 ADD TABLESPACE tbs3 QUOTA 5G;

- フラッシュバック・データ・アーカイブfla1に対して、必要に応じてtbs4と同じサイズの表領域を追加します。

ALTER FLASHBACK ARCHIVE fla1 ADD TABLESPACE tbs4;

- フラッシュバック・データ・アーカイブfla1が表領域tbs3で使用できる最大領域を20GBに変更します。

ALTER FLASHBACK ARCHIVE fla1 MODIFY TABLESPACE tbs3 QUOTA 20G;

- フラッシュバック・データ・アーカイブfla1に対して、必要に応じてtbs1と同じサイズの表領域を使用できるようにします。

ALTER FLASHBACK ARCHIVE fla1 MODIFY TABLESPACE tbs1;

- フラッシュバック・データ・アーカイブfla1の保有時間を2年に変更します。

ALTER FLASHBACK ARCHIVE fla1 MODIFY RETENTION 2 YEAR;

- フラッシュバック・データ・アーカイブfla1から表領域tbs2を削除します。

ALTER FLASHBACK ARCHIVE fla1 REMOVE TABLESPACE tbs2;

(表領域tbs2は削除されません。)

- フラッシュバック・データ・アーカイブfla1からすべての履歴データをパージします。

ALTER FLASHBACK ARCHIVE fla1 PURGE ALL;

- フラッシュバック・データ・アーカイブfla1から1日以上経過したすべての履歴データをパージします。

ALTER FLASHBACK ARCHIVE fla1
PURGE BEFORE TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' DAY);

- フラッシュバック・データ・アーカイブfla1からSCN 728969より古いすべての履歴データをパージします。

ALTER FLASHBACK ARCHIVE fla1 PURGE BEFORE SCN 728969;

ALTER FLASHBACK ARCHIVE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

フラッシュバック・データ・アーカイブの削除

DROP FLASHBACK ARCHIVE文を使用してフラッシュバック・データ・アーカイブを削除します。フラッシュバック・データ・アーカイブを削除するとその履歴データは削除されますが、その表領域は削除されません。

例

表領域を削除せず、フラッシュバック・データ・アーカイブfla1およびその履歴データを削除します。

DROP FLASHBACK ARCHIVE fla1;

DROP FLASHBACK ARCHIVE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

デフォルト・フラッシュバック・データ・アーカイブの指定

デフォルトでは、システムにはデフォルト・フラッシュバック・データ・アーカイブがありません。SYSDBAとしてログオンしている場合は、次のいずれかの方法でデフォルト・フラッシュバック・データ・アーカイブを指定できます。

- ALTER FLASHBACK ARCHIVE文のSET DEFAULT句を使用して、既存のフラッシュバック・データ・アーカイブの名前を指定します。次に例を示します。

ALTER FLASHBACK ARCHIVE fla1 SET DEFAULT;

fla1がない場合は、エラーが発生します。

- フラッシュバック・データ・アーカイブを作成する際、CREATE FLASHBACK ARCHIVE文にDEFAULTを含めます。次に例を示します。

CREATE FLASHBACK ARCHIVE DEFAULT fla2 TABLESPACE tbs1
QUOTA 10G RETENTION 1 YEAR;

システムのデフォルト・フラッシュバック・データ・アーカイブは、自分自身のデフォルト・フラッシュバック・データ・アーカイブを持たないすべてのユーザーに対するデフォルト・フラッシュバック・データ・アーカイブです。

参照:

- CREATE FLASHBACK ARCHIVE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- ALTER DATABASE文の詳細は、Oracle Database SQL言語リファレンスを参照

フラッシュバック・データ・アーカイブの有効化および無効化

デフォルトでは、表に対してフラッシュバック・アーカイブは無効になっています。その表に対して使用するフラッシュバック・データ・アーカイブのFLASHBACK ARCHIVEオブジェクト権限がある場合は、表のフラッシュバック・アーカイブを有効にできます。

表に対してフラッシュバック・アーカイブを有効にするには、CREATE TABLE文またはALTER TABLE文にFLASHBACK ARCHIVE句を含めます。FLASHBACK ARCHIVE句には、その表の履歴データを格納するフラッシュバック・データ・アーカイブを指定できます。デフォルトは、システムに対してデフォルトのフラッシュバック・データ・アーカイブです。存在しないフラッシュバック・データ・アーカイブを指定すると、エラーが発生します。

表に対してフラッシュバック・アーカイブを有効にしても、AUMが無効な場合は、表を変更しようとするとエラーORA-55614が発生します。

表でフラッシュバック・アーカイブが有効になっている場合は、別のフラッシュバック・データ・アーカイブを再度有効にしようとするとエラーが発生します。

表に対してフラッシュバック・アーカイブを有効にした後は、FLASHBACK ARCHIVE ADMINISTERシステム権限がある場合、またはSYSDBAとしてログオンしている場合のみ、これを無効にできます。表に対してフラッシュバック・アーカイブを無効にするには、ALTER TABLE文にNO FLASHBACK ARCHIVEを指定します。(CREATE TABLE文にNO FLASHBACK ARCHIVEを指定する必要はありません。これはデフォルトです。)

参照:
CREATE TABLE文のFLASHBACK ARCHIVE句の詳細(使用制限も含む)は、『Oracle Database SQL言語リファレンス』を参照してください。

例

- 表employeeを作成してデフォルトのフラッシュバック・データ・アーカイブに履歴データを格納します。

CREATE TABLE employee (EMPNO NUMBER(4) NOT NULL, ENAME VARCHAR2(10),
JOB VARCHAR2(9), MGR NUMBER(4)) FLASHBACK ARCHIVE;

- 表employeeを作成してフラッシュバック・データ・アーカイブfla1に履歴データを格納します。

CREATE TABLE employee (EMPNO NUMBER(4) NOT NULL, ENAME VARCHAR2(10),
JOB VARCHAR2(9), MGR NUMBER(4)) FLASHBACK ARCHIVE fla1;

- 表employeeのフラッシュバック・アーカイブを有効にして、デフォルトのフラッシュバック・データ・アーカイブに履歴データを格納します。

ALTER TABLE employee FLASHBACK ARCHIVE;

- 表employeeのフラッシュバック・アーカイブを有効にして、フラッシュバック・データ・アーカイブfla1に履歴データを格納します。

ALTER TABLE employee FLASHBACK ARCHIVE fla1;

- 表employeeのフラッシュバック・アーカイブを無効にします。

ALTER TABLE employee NO FLASHBACK ARCHIVE;

フラッシュバック・データ・アーカイブが有効な表のDDL文

フラッシュバック・データ・アーカイブは次のDDL文のみをサポートします。

- ALTER TABLE文では、次のいずれかが実行されます。

- 列の追加、削除、名前変更、または修正

- 制約の追加、削除、または名前変更

- パーティション、またはサブパーティション操作の削除、または切捨て

- TRUNCATE TABLE文

- 表の名前を変更するRENAME文

フラッシュバック・データ・アーカイブは、パーティションまたはサブパーティションの移動、分割、マージ、結合、表の移動、LONG列のLOB列への変換を実行するDDL文をサポートしません。

たとえば、フラッシュバック・データ・アーカイブを有効にした表に対して次のDDL文を使用すると、エラーORA-55610が発生します。

- UPGRADE TABLE句を含むALTER TABLE文。INCLUDING DATA句を持つことも持たないこともあります。

- パーティション、またはサブパーティション操作を移動、または交換するALTER TABLE文。

- DROP TABLE文

フラッシュバック・データ・アーカイブ対応の表でサポートされていないDDL文を使用する必要がある場合は、DBMS_FLASHBACK_ARCHIVE.DISASSOCIATE_FBAプロシージャを使用して、そのフラッシュバック・データ・アーカイブから実表の関連付けを解除します。その後、フラッシュバック・データ・アーカイブと実表を再度関連付けするには、DBMS_FLASHBACK_ARCHIVE.REASSOCIATE_FBAプロシージャを使用します。

参照:

- ALTER TABLE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- TRUNCATE TABLE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- RENAME文の詳細は、Oracle Database SQLリファレンスを参照

- DROP TABLE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- DBMS_FLASHBACK_ARCHIVEパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

フラッシュバック・データ・アーカイブ・データの表示

表12-3に静的データ・ディクショナリ・ビューを示し、簡潔に説明します。このビューに対して、フラッシュバック・データ・アーカイブ・ファイルに関する情報の問合せを実行できます。

表12-3 フラッシュバック・データ・アーカイブ・ファイルの静的データ・ディクショナリ・ビュー

ビュー

説明

*_FLASHBACK_ARCHIVE

フラッシュバック・データ・アーカイブ・ファイルに関する情報を表示します。

*_FLASHBACK_ARCHIVE_TS

フラッシュバック・データ・アーカイブ・ファイルの表領域を表示します。

*_FLASHBACK_ARCHIVE_TABLES

データ・フラッシュバック・アーカイブ・ファイルが有効になっている表に関する情報を表示します。

参照:

- *_FLASHBACK_ARCHIVEの詳細は、『Oracle Databaseリファレンス』を参照してください。

- *_FLASHBACK_ARCHIVE_TSの詳細は、『Oracle Databaseリファレンス』を参照してください。

- *_FLASHBACK_ARCHIVE_TABLESの詳細は、『Oracle Databaseリファレンス』を参照してください。

フラッシュバック・データ・アーカイブの使用例

- 使用例: フラッシュバック・データ・アーカイブを使用したデジタル・シュレッディングの実行

- 使用例: フラッシュバック・データ・アーカイブを使用した履歴データへのアクセス

- 使用例: フラッシュバック・データ・アーカイブを使用したレポートの生成

- 使用例: フラッシュバック・データ・アーカイブの監査への使用

- 使用例: フラッシュバック・データ・アーカイブを使用したデータのリカバリ

使用例: フラッシュバック・データ・アーカイブを使用したデジタル・シュレッディングの実行

企業でTaxes表に対する履歴データの変更内容を10年後に「シュレッド」(削除)するとします。Taxesのフラッシュバック・データ・アーカイブを作成する際、10年の保有時間を指定します。

CREATE FLASHBACK ARCHIVE taxes_archive TABLESPACE tbs1 RETENTION 10 YEAR;

Taxesのトランザクションからの履歴データは、10年を超えるとパージされます。(Taxesの表自体、および10年未満のトランザクションからの履歴データはパージされません。)

使用例: フラッシュバック・データ・アーカイブを使用した履歴データへのアクセス

表inventoryから年初にすべての品目の在庫を取得できるように、また、表stock_dataからその年の任意の日付の業務終了時点での自社の有価証券における、各シンボルの株価を取得できるようにするとします。

デフォルトのフラッシュバック・データ・アーカイブfla1を作成します。これは最大10GBの表領域tbs1を使用し、そのデータは5年間保持されます(SYSDBAとしてログオンしている必要があります)。

CREATE FLASHBACK ARCHIVE DEFAULT fla1 TABLESPACE tbs1
QUOTA 10G RETENTION 5 YEAR;

表inventoryおよびstock_dataのフラッシュバック・データ・アーカイブを有効にして、デフォルトのフラッシュバック・データ・アーカイブに履歴データを格納します。

ALTER TABLE inventory FLASHBACK ARCHIVE;
ALTER TABLE stock_data FLASHBACK ARCHIVE;

2007年の年初にすべての品目の在庫を取得するには、次の問合せを使用します。

SELECT product_number, product_name, count FROM inventory AS OF
TIMESTAMP TO_TIMESTAMP ('2007-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS');

2007年7月23日の業務の終了時に有価証券の各シンボルの株価を取得するには、次の問合せを使用します。

SELECT symbol, stock_price FROM stock_data AS OF
TIMESTAMP TO_TIMESTAMP ('2007-07-23 16:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE symbol IN my_portfolio;

使用例: フラッシュバック・データ・アーカイブを使用したレポートの生成

ユーザーが、過去5年間格納されているデータについて、表investmentsからレポートを生成できるようにするとします。

デフォルトのフラッシュバック・データ・アーカイブfla2を作成します。これは最大20GBの表領域tbs1を使用し、そのデータは5年間保持されます(SYSDBAとしてログオンしている必要があります)。

CREATE FLASHBACK ARCHIVE DEFAULT fla2 TABLESPACE tbs1
QUOTA 20G RETENTION 5 YEAR;

表investmentsのフラッシュバック・アーカイブを有効にして、デフォルトのフラッシュバック・データ・アーカイブに履歴データを格納します。

ALTER TABLE investments FLASHBACK ARCHIVE;

Lisaは、2006年12月31日の業務終了時点での投資の運用成績に関するレポートを必要としています。次の問合せを使用します。

SELECT * FROM investments AS OF
TIMESTAMP TO_TIMESTAMP ('2006-12-31 16:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE name = 'LISA';

使用例: フラッシュバック・データ・アーカイブの監査への使用

医療保険会社では、診療所を監査する必要があります。医療保険会社は表Billingsにその債権があり、デフォルトのフラッシュバック・データ・アーカイブfla4を作成します。これは最大100GBの表領域tbs1を使用し、そのデータは10年間保持されます。

CREATE FLASHBACK ARCHIVE DEFAULT fla4 TABLESPACE tbs1
QUOTA 100G RETENTION 10 YEAR;

この会社では表Billingsのフラッシュバック・アーカイブを有効にして、デフォルトのフラッシュバック・データ・アーカイブに履歴データを格納します。

ALTER TABLE Billings FLASHBACK ARCHIVE;

2007年5月1日に、クライアントは診断と検査について誤った金額を請求されました。2007年5月1日現在の記録を確認するには、会社は次の問合せを使用します。

SELECT date_billed, amount_billed, patient_name, claim_Id,
test_costs, diagnosis FROM Billings AS OF TIMESTAMP
TO_TIMESTAMP('2007-05-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS');

使用例: フラッシュバック・データ・アーカイブを使用したデータのリカバリ

エンド・ユーザーが、データベースですでにコミット済の誤ったトランザクションからリカバリします。誤ったトランザクションのUNDOデータは今後利用できなくなりますが、必要な履歴情報がフラッシュバック・データ・アーカイブにあるため、フラッシュバック問合せはシームレスに機能します。

Lisaはソフトウェア開発グループを管理しており、そのグループの製品販売が好調です。このため、2007年11月3日に、2年を超える経験を有するレベル3の全従業員に10%の昇給とレベル4への昇進を与えることを決定します。Lisaはこの変更を人事部(HR)代表のBobに依頼します。

BobはHRのWebアプリケーションを使用して、employee表を更新し、Lisaのレベル3の部下に10%の昇給とレベル4への昇進を与えます。次に、Bobは当日の自分の業務を終了して退社しますが、トランザクション中に2年の経験という要件を省略したことに気づいていません。数日後、Bobが更新を完了したかどうかをLisaが確認した際、昇給がグループの全員に与えられたことが判明します。LisaはただちにBobに電話し、誤りを修正するよう要求します。

Bobは最初は、バックアップにアクセスしなければ従業員表を以前の状態に戻せないと考えます。次に、employee表ではフラッシュバック・データ・アーカイブが有効になっていることを思い出します。

Bobは最初に、彼の変更後にemployee表を変更した他のトランザクションがないことを検証します。トランザクション問合せからのコミット・タイムスタンプは、2日前のBobのトランザクションと一致します。

次に、Bobは次の文を使用してemployee表を誤った変更以前の状態に戻します。

DELETE EMPLOYEE WHERE MANAGER = 'LISA JOHNSON';
INSERT INTO EMPLOYEE
SELECT * FROM EMPLOYEE
AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '2' DAY)
WHERE MANAGER = 'LISA JOHNSON';

それからBobはLisaに要求された更新を再度実行します。

Oracle Flashback Technologyの一般ガイドライン

- DBMS_FLASHBACK.ENABLEおよびDBMS_FLASHBACK.DISABLEプロシージャを、制御しないSQLコード、または複数の連続した問合せに対して過去の同じ時刻を使用する場合のSQLコードの周辺で使用します。

- 記述するSQLコードで、簡便性のためにOracle Flashback Query、Oracle Flashback Version QueryまたはOracle Flashback Transaction Queryを使用します。たとえば、Oracle Flashback Queryは柔軟性が高く、単一の問合せで比較と結果の格納を行うことができます。

- 後でフラッシュバック機能で使用するためのSCNを取得するには、DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBERを使用します。

- 問合せで使用する過去の時間を計算または取得するには、タイムスタンプまたはSCN引数としてファンクション戻り値を使用します。たとえば、INTERVAL値をSYSTIMESTAMP関数の値に加算または減算します。

- Oracle Flashback Query、Oracle Flashback Version QueryおよびOracle Flashback Transaction Queryをローカルまたはリモートで使用します。リモートのOracle Flashback Queryの例は次のとおりです。

SELECT * FROM employees@some_remote_host AS OF
TIMESTAMP (SYSTIMESTAMP - INTERVAL '60' MINUTE);

- データベースの整合性を保証するには、過去のデータを問い合せる前に、必ずCOMMITまたはROLLBACK操作を実行します。

- すべてのフラッシュバック処理は、問合せ対象の時点に有効であった設定ではなく、各国語およびキャラクタ・セットなどの現在のセッション設定を使用することに注意してください。

- 表の構造を変更するいくつかのDDL(列の削除/変更、表の移動、パーティションの削除、表/パーティションの切捨て、制約の追加など)では、表に対する既存のUNDOデータは無効になります。DDL実行以前の時間のデータを取得しようとすると、ORA-01466のエラーが発生します。表の記憶域属性(PCTFREE、INITRANS、MAXTRANSなど)を変更するDDL操作では、UNDOデータは無効にされません。

- 正確な時間の過去のデータを問い合せるには、SCNを使用します。タイムスタンプを使用した場合、問合せの実際の時間は、指定した時間よりも最大3秒早くなる場合があります。内部的には、Oracle DatabaseではSCNが使用され、このSCNは、3秒の間隔でタイムスタンプにマップされます。
たとえば、SCN値1000および1005が、タイムスタンプ午前8時41分および8時46分にそれぞれマップされているとします。午前8時41分から8時45分59秒の間に行われた問合せはSCN 1000にマップされます。午前8時46分に行われたOracle Flashback QueryはSCN 1005にマップされます。したがって、表の作成などのDDL操作の直後の時点を指定した場合、Oracle DatabaseではDDL操作の直前のSCNが使用されることがあり、エラーORA-01466が発生します。

- 動的パフォーマンス(V$)ビューから過去のデータは取得できません。このようなビューに問合せを実行すると、常に現在のデータが戻されます。

- 静的データ・ディクショナリ・ビュー(*_TABLESなど)では、過去のデータに問合せを実行できます。

- Oracle Database 11gリリース2 (11.2.0.4)では、フラッシュバック・データ・アーカイブを作成または変更する際、OPTIMIZE DATAを指定して、フラッシュバック・データ・アーカイブでメンテナンスされる履歴表のデータ記憶域の最適化を有効化できます。
OPTIMIZE DATAは、次の機能のいずれかを使用して履歴表のデータの記憶域を最適化します。

- 高度な行圧縮

- 高度なLOB圧縮

- 高度なLOB重複除外

- セグメント・レベルの圧縮層

- 行レベルの圧縮層

デフォルトでは、履歴表のデータ記憶域を最適化しません。

Oracle Flashback Technologyのパフォーマンス・ガイドライン

- Oracle Flashback Queryに関連するすべての表の統計情報を生成するには、DBMS_STATSパッケージを使用します。統計情報を最新の状態に維持します。Oracle Flashback Queryは、これらの統計情報に依存するコストベース・オプティマイザを使用します。

- アクセスする必要のあるUNDOデータの量を最小限にします。問合せを使用する際に、表全体をスキャンするのでなく、索引を使用して少量の過去データを選択します。全表をスキャンする必要がある場合は、問合せにパラレル・ヒントを追加します。
I/Oのパフォーマンス・コストは、バッファ・キャッシュに存在していないデータおよびUNDOブロックにおけるページングのコストです。CPUの使用におけるパフォーマンス・コストは、影響を受けるデータ・ブロックにUNDO情報を適用する際のコストです。最近の過去における変更を操作する場合、フラッシュバック操作にはCPUの限界があります。

アーカイバのバージョン問合せがバッファ・キャッシュでUNDOデータを見つけられるように、十分なバッファ・キャッシュを設定することをお薦めします。バッファ・キャッシュのアクセスは、ディスク・アクセスよりも大幅に高速です。

- Oracle Flashback Version Queryの場合は、索引構造を使用します。Oracle Databaseでは、データの変更および索引変更に関するUNDOデータが保持されます。索引参照ベースのOracle Flashback Version Queryのパフォーマンスは、全表スキャン(索引を使用しない場合は必要)よりも桁違いに高速です。

- Oracle Flashback Transaction Queryでは、xid列の型がRAW(8)です。xid列に対して作成された索引を利用するには、HEXTORAW変換ファンクションHEXTORAW(xid)を使用します。

- マテリアライズド・ビューに対するOracle Flashback Queryには、クエリー・リライト最適化の効果はありません。

13 プログラミング環境の選択

開発プロジェクト用のプログラミング環境を選択するときは、次のドキュメントを読むことをお薦めします。

- この章の各項、およびそれらの項で参照しているドキュメント。

- プラットフォームでサポートされるコンパイラや開発ツールを示すプラットフォーム固有のドキュメント。

次のようにプログラミング環境の選択が明白な場合もあります。

- Pro*COBOLでは、ADTやコレクション型がサポートされませんが、Pro*C/C++ではサポートされています。

- SQLJが動的SQLをサポートする方法は、JDBCとは異なります。

必要な機能をすべて備えたプログラミング言語がない場合は、次の理由により、複数のプログラミング言語を使用することができます。

- この章のすべてのプログラミング言語は、PL/SQLおよびJavaのストアド・サブプログラムを起動できます。(ストアド・サブプログラムには、トリガーおよびADTメソッドが含まれます。)

- PL/SQL、Java、SQLおよびOracle Call Interface(OCI)は、外部のCサブプログラムを起動できます。

- 外部Cサブプログラムは、SQL、OCIまたはPro*C(C++ではなく)を使用してOracle Databaseにアクセスできます。

複数言語プログラミングの詳細は、第14章「複数のプログラミング言語を使用したアプリケーションの開発」を参照してください。

内容は次のとおりです。

- アプリケーション・アーキテクチャの概要

- プログラム・インタフェースの概要

- PL/SQLの概要

- Oracle Database Javaサポートの概要

- PL/SQLまたはJavaの選択

- プリコンパイラの概要

- OCIおよびOCCIの概要

- プリコンパイラまたはOCIの選択

- Oracle Data Provider for .NET(ODP.NET)の概要

- OraOLEDBの概要

- Oracle Objects for OLE(OO4O)の概要

アプリケーション・アーキテクチャの概要

ここで、アプリケーション・アーキテクチャは、データベース・アプリケーションがOracle Databaseに接続するコンピューティング環境を意味します。

内容は次のとおりです。

- クライアント/サーバー・アーキテクチャ

- サーバー側のプログラミング

- 2層アーキテクチャと3層アーキテクチャ

参照:
アプリケーション・アーキテクチャの詳細は、『Oracle Database概要』を参照してください。

クライアント/サーバー・アーキテクチャ

従来のクライアント/サーバー・プログラムでは、アプリケーションのコードはデータベース・サーバー以外のシステムである、クライアント・システム上で実行されます。データベース・コールは、クライアント・システムからデータベース・サーバーに送信されます。挿入および更新操作時には、データがクライアントからサーバーに送信され、問合せ操作時には、データがサーバーからクライアントに戻されます。データは、クライアント・システム上で処理されます。クライアント/サーバー・プログラムは、通常、プリコンパイラを使用して作成されますが、SQL文はC、C++、COBOLなどの別の言語のコードに埋め込まれています。

参照:
クライアント/サーバー・アーキテクチャの詳細は、『Oracle Database概要』を参照してください。

サーバー側のプログラミング

データベースで変更が発生した場合に自動的に実行されるトリガー、または明示的に起動されるストアド・サブプログラムを使用して、完全にデータベース内に常駐するアプリケーション・ロジックを開発できます。アプリケーションから作業をオフロードすると、検証およびクリーン・アップの実行に使用されるコードを再利用できたり、様々なクライアントからのデータベース処理を制御できます。たとえば、Webサーバーを介したストアド・サブプログラムの起動を可能にすることで、クライアント/サーバー・アプリケーションと同じ機能を実行するWebベースのユーザー・インタフェースを構成できます。

参照:
サーバー側のプログラミングの詳細は、『Oracle Database概要』を参照してください。

2層アーキテクチャと3層アーキテクチャ

クライアント/サーバー・コンピューティングは、2層モデルと呼ばれることがあります。このモデルでは、アプリケーションはデータベース・サーバーと直接通信します。3層モデルでは、別個のアプリケーション・サーバーが要求を処理します。アプリケーション・サーバーには、基本的なWebサーバーや、キャッシュやロード・バランスなどの拡張機能を実行するサーバーがあります。この中間層の処理能力を向上させると、クライアント・システムに必要なリソースを少なくできるため、Thinクライアント構成になり、この構成では、クライアント・システムが必要とするのはWebブラウザか、またはTCP/IPやHTTPプロトコルを介して要求を送信する他の手段のみです。

参照:
複数層アーキテクチャの詳細は、『Oracle Database概要』を参照してください。

プログラム・インタフェースの概要

プログラム・インタフェースは、データベース・アプリケーションとOracle Databaseの間のソフトウェア・レイヤーです。プログラム・インタフェースの機能は次のとおりです。

- クライアント・ユーザー・プロセスによるSGAへの破壊的アクセスを防ぐ、セキュリティのための障壁になります。

- 通信メカニズムとして働きます。つまり、情報リクエストの形式を設定し、データを渡し、エラーをトラップして返します。

- 特に、異機種コンピュータ間で、または外部ユーザー・プログラムのデータ型に対して、データを変換します。

Oracleコードはサーバーとして働き、アプリケーション(クライアント)のために、データ・ブロックからの行のフェッチなどデータベース・タスクを実行します。プログラム・インタフェースは、Oracle Databaseソフトウェアおよびオペレーティング・システム固有のソフトウェアの両方によって提供される複数の部分で構成されます。

参照:
プログラム・インタフェースの詳細は、『Oracle Database概要』を参照してください。

内容は次のとおりです。

- ユーザー・インタフェース

- ステートフル・ユーザー・インタフェースとステートレス・ユーザー・インタフェース

ユーザー・インタフェース

ユーザー・インタフェースとは、アプリケーションがエンド・ユーザーに対して表示するものです。これはそのアプリケーションの背後にあるテクノロジおよびユーザー自身のニーズによって異なります。経験豊富なユーザーの場合は、データベースに渡すSQL文を入力できます。初心者ユーザーの場合は、クライアント・システム(Windows、X-Windowなど)のグラフィック・ライブラリを使用したGraphical User Interface(GUI)を表示できます。また、これらの従来のユーザー・インタフェースは、HTMLおよびJavaを使用してWebブラウザで提供することもできます。

ステートフル・ユーザー・インタフェースとステートレス・ユーザー・インタフェース

従来のクライアント/サーバー・アプリケーションでは、アプリケーションはユーザーのアクションを記録し、この情報を1つ以上のセッションで使用できます。たとえば、前に選択した項目を再入力する必要がないように、その項目をメニュー内に表示できます。アプリケーションがこの方法で情報を保存できる場合、そのアプリケーションはステートフルであるといいます。

WebアプリケーションまたはThinクライアント・アプリケーションは、ステートレスであると開発が容易です。ステートレス・アプリケーションは、必要なすべての情報を収集し、データベースを使用してその情報を処理し、ユーザーが変わるとそれらの操作を再実行します。これは、顧客登録などの単一画面要求を処理する一般的な方法です。

デフォルトでステートレスであるWebアプリケーションにステートフルのアクションを追加する方法は、数多くあります。たとえば、Webページ上のエントリ・フォームから次のWebページに情報が渡されるように、複数の異なる手順を通してユーザーの選択内容を記憶するウィザードのようなインタフェースを構成できます。Cookieを使用してクライアント・システムに関する少量の情報項目を格納でき、ユーザーがWebサイトに再度アクセスしたときはそれらの項目を取得できます。また、サーブレットを使用して、データベース・セッションを開いたままにし、同じクライアントからの要求間で、変数の格納もできます。

PL/SQLの概要

SQLの手続き型拡張言語であるOracleのPL/SQLは、完全な移植性を備えた高パフォーマンスのトランザクション処理言語です。PL/SQLでは、SQL文によるデータ操作、条件選択やループによるプログラム・フローの制御、定数や変数の宣言、サブプログラムの定義、型、サブタイプ、およびADTの定義とこれらの型を持つ変数の宣言、ランタイム・エラーのトラップが可能です。

Oracle Databaseのプログラム・インタフェースのいずれかを使用して作成したアプリケーションであれば、PL/SQLストアド・サブプログラムを起動したり、PL/SQLコードのブロックをOracle Databaseに送信して実行できます。第三世代言語(3GL)のアプリケーションでは、ホスト変数および暗黙的データ型変換を使用して、PL/SQLのスカラー・データ型およびコンポジット・データ型にアクセスできます。3GL言語は、アセンブラ言語に比べて理解しやすく、名前付き変数などの機能が含まれています。第四世代言語(4GL)とは異なり、アプリケーション・ドメイン固有ではありません。

PL/SQLを使用すると、Webクライアントで起動できるストアド・プロシージャを開発することができます。

参照:

- PL/SQLの利点、主要な機能およびアーキテクチャの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- Web開発にPL/SQLを使用する方法の詳細は、第9章「PL/SQL Webアプリケーションの開発」を参照してください。

Oracle Database Javaサポートの概要

この項では、JavaアプリケーションをサポートするOracle Databaseの機能の概要を説明します。データベースには、java.lang、java.ioなどのコアJDKライブラリが含まれています。データベースでは、JDBCおよびSQLJなどのクライアント側Java標準がサポートされています。また、データベース内でデータ処理集中型のJavaコードを実行可能な、サーバー側のJDBCおよびSQLJドライバが提供されています。

内容は次のとおりです。

- Oracle JVMの概要

- Oracle JDBCの概要

- Oracle SQLJの概要

- Oracle JDBCとOracle SQLJの比較

- Oracle JPublisherの概要

- Javaストアド・サブプログラムの概要

- Oracle Database Webサービスの概要

参照:

- 『Oracle Database Java開発者ガイド』

- 『Oracle Database JDBC開発者ガイド』

- 『Oracle Database JPublisherユーザーズ・ガイド』

Oracle JVMの概要

Oracle Databaseとともに提供されるOracle JVM(Java仮想マシン)はJ2SEバージョン1.5.x仕様に準拠しており、データベース・セッション・アーキテクチャをサポートしています。

任意のデータベース・セッションにより、専用JVMをアクティブにできます。すべてのセッションで同じJVMコードおよびJVM静的値を共有しますが、個々のセッション領域では、指定したセッションのプライベート状態が保持され、ガベージが収集されます。

この設計のメリットは次のとおりです。

- JavaアプリケーションにSQL操作と同じセッションの分離性およびデータの整合性が備わります。

- データの整合性を保つために別のプロセスでJavaを実行する必要がありません。

- Oracle JVMはメモリー・フットプリントが小さい堅牢なJVMです。

- Oracle JVMにはデータベースと同じ線形対称マルチプロセッシング(SMP)スケーラビリティがあるため、何千もの同時Javaセッションをサポートできます。

Oracle JVMは、Oracle Databaseがサポートする全プラットフォームで一貫して動作します。Oracle JVMを使用して開発したJavaアプリケーションは、サポートされるどのプラットフォームにも簡単に移植できます。

Oracle JVMには、デプロイ時のネイティブ・コンパイラが含まれています。このコンパイラでは、Javaコードは1回のコンパイルで実行可能形式で格納され、複数のユーザーがこれを共有できるため、より早く効率的な起動が可能になります。

Oracle JVMでは、データベースのセキュリティ機能も使用できます。Javaクラスをコール可能にする前に、(Oracle JDeveloper、サード・パーティIDE、SQL*Plusまたはloadjavaユーティリティを使用して)データベース・スキーマにロードする必要があります。Javaクラスのコールは、データベース認証とデータベース認可、Java 2セキュリティ、および実行者権限(IR)や定義者権限(DR)を介して、保護および制御されます。

参照:
Oracle JVMのその他の概要は、『Oracle Database概要』を参照してください。

Oracle JDBCの概要

Java Database Connectivity(JDBC)は、Oracle Databaseなどのオブジェクト・リレーショナル・データベースに対してJavaからSQL文を送信するApplication Program Interface(API)です。

Oracle Databaseには、JDBC 1.22標準に対する次の拡張機能が含まれます。

- Oracleデータ型のサポート

- 行のプリフェッチによるパフォーマンス強化

- バッチ処理の実行によるパフォーマンス強化

- ラウンドトリップを削減する問合せ列型の指定

- DatabaseMetaDataコールの制御

Oracle Databaseは、JDBC 2.0標準のすべてのAPI(コアAPI、オプションのパッケージおよび多数の拡張機能を含む)をサポートしています。その拡張機能のいくつかには、データソース、JTAおよび分散トランザクションが含まれます。

Oracle Databaseは、JDBC 3.0標準の次の機能をサポートしています。

- JDK 1.5のサポート。

- ローカル・トランザクションとグローバル・トランザクション間の切替え。

- トランザクションのセーブポイント。

- 接続プールによってプリコンパイルされたSQL文の再利用。

注意:
JDBCコードとSQLJコードは相互運用が可能です。詳細は、「Oracle JDBCとOracle SQLJの比較」を参照してください。

内容は次のとおりです。

- Oracle JDBCドライバ

- JDBC 2.0のサンプル・プログラム

- JDBC 2.0より前のサンプル・プログラム

参照:
Oracle DatabaseでのJavaサポートのその他の概要は、『Oracle Database概要』を参照してください。

Oracle JDBCドライバ

JDBC標準では、次の4種類のJDBCドライバが定義されています。

型

説明

1

JDBC-ODBCブリッジ。ソフトウェアはクライアント・システム上にインストールする必要があります。

2

ネイティブ・メソッド(CまたはC++をコール)およびJavaメソッド。ソフトウェアはクライアント上にインストールする必要があります。

3

Pure Java。クライアントはソケットを使用してサーバー上のミドルウェアをコールします。

4

最もPure Javaの度合の高いソリューション。Javaソケットを使用してデータベースと直接対話します。

JDBCはSQL規格のPart 3「Call-Level Interface」に基づいています。

動的SQLを実行するにはJDBCを使用します。動的SQLでは、実行される埋込みSQL文が何であるかはアプリケーションが実行されるまでわからず、SQL文の作成に入力を必要とします。

Oracleによって実装されたドライバには、Sun Microsystemsが定義したJDBC標準機能に対する拡張が含まれています。

内容は次のとおりです。

- JDBC Thinドライバ

- JDBC OCIドライバ

- サーバー側JDBC内部ドライバ

参照:

- JDBCドライバのその他の概要は、『Oracle Database概要』を参照してください。

- JDBCの詳細は、『Oracle Database JDBC開発者ガイドおよびリファレンス』を参照してください。

JDBC Thinドライバ

JDBC Thinドライバはタイプ4(100% Pure Java)のドライバで、Javaソケットを使用してデータベース・サーバーに直接接続します。このドライバには、独自のTwo-Task Common(TTC)実装(Oracle NetのTCP/IPを軽量小型用に実装したもの)が含まれています。このドライバは、完全にJavaで作成されているため、プラットフォームには依存しません。

Thinドライバでは、クライアント側にOracleソフトウェアは必要ありません。サーバー側にはTCP/IPリスナーが必要です。このドライバは、WebブラウザをダウンロードするJavaアプレット内、またはOracleクライアント・ソフトウェアをインストールしないアプリケーション内で使用します。Thinドライバは自己完結型ですが、Javaソケットをオープンするため、ソケットをサポートするブラウザでのみ実行できます。

JDBC OCIドライバ

JDBC OCIドライバはタイプ2のJDBCドライバです。Cで作成されているOCIをコールして、Oracle Databaseと対話します。したがって、ネイティブ・メソッドおよびJavaメソッドの両方を使用します。

OCIドライバを使用すると、Thinドライバより多くの機能(透過的アプリケーション・フェイルオーバー、高度なセキュリティ、高度なLOB操作など)にアクセスできます。

OCIドライバは、異なるOracle Databaseバージョン間の互換性を提供します。また、OCIドライバは、IPC、Named Pipes、TCP/IPおよびIPX/SPXを含むすべてのインストール済Oracle Netアダプタもサポートします。

OCIドライバは、ネイティブ・メソッド(JavaとCの組合せ)を使用するため、プラットフォーム固有のドライバです。Oracle Net、OCIライブラリ、COREライブラリなどのすべての依存ファイルとともに、Oracle8i以降のバージョンをクライアントにインストールする必要があります。OCIドライバは、通常、Thinドライバより実行速度が速くなります。

OCIドライバは、プラットフォーム固有のCライブラリを使用しており、Webブラウザにはダウンロードできないため、Javaアプレット用には適していません。Oracle Application Serverなどの中間層アプリケーション・サーバー内で実行中のJ2EEコンポーネントでは、OCIドライバを使用できます。Oracle Application Serverは、アプリケーションおよびブラウザ間のアクセスをサポートするミドルウェア・サービスおよびツール製品を提供します。

サーバー側JDBC内部ドライバ

サーバー側JDBC内部ドライバは、タイプ2のドライバで、データベース・サーバー内で実行されます。このため、大量データへのアクセスに必要なラウンドトリップの数が削減されます。このドライバと、JavaサーバーVM、データベース、実行速度を最大で10倍に上げるJavaネイティブ・コンパイラ、およびSQLエンジンは、すべて同じアドレス空間内で実行されます。

このドライバは、データベースで使用されるすべてのJavaプログラムのサーバー側サポートを提供します。PL/SQLストアド・サブプログラムおよびトリガーをコールすることもできます。

サーバー側JDBCドライバは、クライアント側ドライバと同じ機能および拡張機能を完全にサポートします。

JDBC 2.0のサンプル・プログラム

次の例では、JDBC 2.0のJNDIを使用してデータソースを検索する場合の推奨される方法を示します。

// import the JDBC packages
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.pool.*;
...
InitialContext ictx = new InitialContext();
DataSource ds = (DataSource)ictx.lookup("jdbc/OracleDS");
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT last_name FROM employees");
while ( rs.next() ) {
out.println( rs.getString("ename") + "<br>");
}
conn.close();

JDBC 2.0より前のサンプル・プログラム

次のソース・コードは、Oracle JDBC Thinドライバの登録、データベースヘの接続、Statementオブジェクトの作成、問合せの実行および結果セットの処理を行います。

SELECT文は、hr.employees表のlast_name列を取得してその内容をリストします。

import java.sql.*
import java.math.*
import java.io.*
import java.awt.*

class JdbcTest {
public static void main (String args []) throws SQLException {
// Load Oracle driver
DriverManager.registerDriver (new oracle.jdbc.OracleDriver());

// Connect to the local database
Connection conn =
DriverManager.getConnection ("jdbc:oracle:thin:@myhost:1521:orcl",
"hr", "password");

// Query the employee names
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery ("SELECT last_name FROM employees");

// Print the name out
while (rset.next ())
System.out.println (rset.getString (1));
// Close the result set, statement, and the connection
rset.close();
stmt.close();
conn.close();
}
}

Propertiesオブジェクトを使用するgetConnection()メソッドによって、JDBCドライバに対するOracle Databaseの拡張を実行します。Propertiesオブジェクトを使用すると、ユーザー、パスワードおよびデータベース情報の他に、行プリフェッチおよびバッチ実行を指定できます。

このコード内でOCIドライバを使用するには、Connection文を次のコードで置換します。MyHostStringは、tnsnames.oraファイル内のエントリです。

Connection conn = DriverManager.getConnection ("jdbc:oracle:oci8:@MyHostString",
"hr", "password");

アプレットを作成する場合のgetConnection()およびregisterDriver()の文字列の指定は異なります。

Oracle SQLJの概要

注意:
このドキュメントでは、SQLJはOracle SQLJおよびその拡張機能を意味します。

SQLJは、Javaソース・コード内にSQL文を埋め込むためのANSI SQL-1999標準です。SQLJは、JDBCにかわり、Javaからのクライアント側およびサーバー側SQLデータ・アクセスを、より簡単なものにします。

SQLJのソース・ファイルには、SQL文が埋め込まれたJavaソースが含まれています。Oracle SQLJは、動的SQLおよび静的SQLをサポートします。動的SQLのサポートは、SQLJ標準に対するOracleの拡張機能です。

Oracle Databaseでは、SQLJをサポートするトランスレータおよびランタイム・ドライバを提供します。SQLJトランスレータは100% Pure Javaで、JDKバージョン1.1以上であれば、どのJVMにでも移植できます。

Oracle SQLJトランスレータは、次の作業を行います。

- SQLJソースを、SQLJランタイム・ドライバへのコールを持つJavaコードに変換します。SQLJトランスレータは、ソース・コードをPure Javaのソース・コードに変換し、データベース・スキーマに対して静的SQL文の構文およびセマンティクスを確認し、ホスト変数とSQLとで型に互換性があるかどうかを検証します。

- Javaコンパイラを使用して生成済Javaコードをコンパイルします。

- ターゲット・データベース用にプロファイルを作成します(オプション)。SQLJで、Oracle Database固有にカスタマイズされたプロファイル・ファイルが生成されます。

Oracle Databaseは、Oracle JVMで実行されるSQLJのストアド・サブプログラムおよびトリガーをサポートします。SQLJは、JDeveloperと統合されています。SQLJに対するソース・レベルのデバッグ・サポートはJDeveloperで使用できます。

次に、単純で実行可能なSQLJ文の例を示します。employee表ではemployee_idが一意であるため、この文は値を1つ戻します。

String name;
#sql  { SELECT first_name INTO :name FROM employees WHERE employee_id=112 };
System.out.println("Name is " + name + ", employee number = " + employee_id);

SQL式に含まれる各ホスト変数(または、修飾名か複雑なJavaホスト式)の前にはコロン(:)が付きます。その他のSQLJ文はJavaの型を宣言します。たとえば、多数の値を取得する問合せのイテレータ(データベース・カーソルに関連する構造体)を宣言できます。

#sql iterator EmpIter (String EmpNam, int EmpNumb);

参照:
Oracle SQLJ構文の例および詳細は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。

内容は次のとおりです。

- SQLJのメリット

- サーバー内のSQLJストアド・サブプログラム

参照:
SQLJのその他の概要は、『Oracle Database概要』を参照してください。

SQLJのメリット

Javaに対するOracle SQLJ拡張機能を使用すると、埋込みSQLを介してデータベース操作を実行するアプリケーションを迅速に開発したり、簡単にメンテナンスできます。

特に、Oracle SQLJには次の特長があります。

- 静的SQLからデータベースにアクセスする簡潔でわかりやすいメカニズムを提供します。アプリケーション内のSQLは、ほとんどの場合静的です。SQLJは、JDBCよりさらに簡潔で、エラーが発生しにくい静的SQL構文を提供します。

- 変換時に構文およびセマンティクスの検証を行うSQLチェッカー・モジュールを提供します。

- 柔軟なデプロイメント構成を提供します。これにより、クライアント側、サーバー側または中間層でSQLJを実装できるようになります。

- ソフトウェア標準をサポートします。SQLJはベンダー・グループの努力の集積であり、携わったすべてのベンダーは、今後、SQLJをサポートしていきます。アプリケーションで複数ベンダーのデータベースにアクセスできます。

- ソース・コード・レベルの移植性を提供します。各ベンダーのDBMSコードがベンダー固有の機能に依存していない場合は、実行可能ファイルをすべてのベンダーのDBMSで使用できます。

- クライアントおよびサーバーで統一されたプログラミング・スタイルを施行します。

- SQLJトランスレータと、グラフィカルなIDEであるOracle JDeveloperを統合します。この開発環境では、SQLJ変換、Javaコンパイル、プロファイルのカスタマイズ、ソース・コード・レベルのデバッグがすべて1つの手順で提供されます。

- Oracle Databaseデータ型の拡張機能が含まれています。

サーバー内のSQLJストアド・サブプログラム

SQLJアプリケーションは、次の方法でサーバーに格納して実行できます。

- SQLJソース・コードをクライアント上で変換、コンパイルおよびカスタマイズ後に、loadjavaユーティリティを使用して、生成済のクラスおよびリソースをサーバーにロードします。通常、クラスはJavaアーカイブ(.jar)ファイルに格納されます。

- または、loadjavaを使用してSQLJソース・コードをサーバーにロードし、サーバーの埋込みトランスレータを使用してこのコードを変換およびコンパイルします。

Oracle JDBCとOracle SQLJの比較

JDBCコードおよびSQLJコードは相互運用が可能なため、JDBCの動的SQL文をSQLJの静的および動的SQL文とともに使用できます。SQLJのイテレータ・クラスが、JDBCの結果セットに対応します。

JDBCとSQLJには、次のような相違点があります。

- JDBCは、Javaからデータベースに対する完全な動的SQLインタフェースを提供します。これにより、開発者はデータベースの操作を完全に制御できるようになります。SQLJを使用すると、Javaデータベース・プログラミングを簡略化して、開発の生産性を向上できます。

- JDBCは、Javaからの動的SQL実行を詳細に制御します。SQLJは、特定のデータベース・スキーマ内でのSQL操作に対して、高レベルの静的バインディングを提供します。

- SQLJのソース・コードは同等のJDBCソース・コードより簡潔です。

- SQLJでは、データベース接続を使用して静的SQLコードの型チェックを行います。JDBCは完全に動的なAPIであるため、型チェックを行いません。

- SQLJでは、問合せ出力および戻りパラメータに強い型指定を行えるため、コール時に型チェックを実行できます。JDBCは、SQLとの間でやりとりされる値についてコンパイル時の型チェックを行いません。

- SQLJプログラムでは、SQL文の中にJavaバインド式を直接埋め込むことができます。JDBCでは、各バインド変数ごとに取得するか、設定用の文が個別に必要になるため、バインドは位置番号によって指定されます。

- SQLJは、SQLストアド・サブプログラムのコールに関して簡潔な規則を提供します。
たとえば、次の連続する4つの例は、JDBCエスケープ構文、またはOracle JDBC構文を使用したストアド・プロシージャまたはストアド・ファンクションをコールする方法を示しています。

prepStmt.prepareCall("{call fun(?,?)}");       //stored proc. JDBC esc.
prepStmt.prepareCall("{? = call fun(?,?)}");   //stored func. JDBC esc.
prepStmt.prepareCall("begin fun(:1,:2);end;"); //stored proc. Oracle
prepStmt.prepareCall("begin :1 := fun(:2,:3);end;"); //stored func. Oracle

SQLJでは、次のコードに相当します。

#sql {call fun(param_list) };  //Stored procedure
// Declare x
...
#sql x = {VALUES(fun(param_list)) };  // Stored function
// where VALUES is the SQL construct

次に、SQLJおよびJDBCに共通するメリットを示します。

- SQLJソース・ファイルにはJDBCコールを含めることができます。SQLJおよびJDBCは相互運用が可能です。

- Oracle JPublisherはカスタムJavaクラスを生成します。このクラスは、SQLJまたはJDBCのアプリケーションでOracle Database ADTおよびコレクション型にマップできます。

- PL/SQLとJavaのストアド・サブプログラムは完全に互換性があります。

Oracle JPublisherの概要

Oracle JPublisherは、データベース中心のJavaクラスを手動で作成するプロセスを自動化するコード・ジェネレータです。Oracle JPublisherはクライアント側ユーティリティであり、データベース・システムに組み込まれています。Oracle JPublisherはコマンドラインから実行できます。また、Oracle JDeveloper IDEからは直接実行できます。

Oracle JPublisherでは、PL/SQLパッケージ、およびADT、VARRAY型やネストした表の型などのデータベース・オブジェクト型の検査後、対応するフィールドおよびメソッドを持つPL/SQLパッケージのラッパーであるJavaクラスを生成します。

生成されたJavaクラスをJavaクライアントまたはJ2EEコンポーネントに組み込んで使用し、データベース・オブジェクト型インスタンスとデータベース間で透過的に交換および転送できます。

参照:

- Oracle JPublisherのその他の概要は、『Oracle Database概要』を参照してください。

- Oracle JPublisherの詳細は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。

Javaストアド・サブプログラムの概要

Javaストアド・サブプログラムを使用すると、中間層で実行するプログラムから独立した、データベース・サーバーで実行するプログラムを実装できます。この方法でアプリケーションを構造化すると複雑にならず、再利用率、セキュリティ、パフォーマンスおよびスケーラビリティが向上します。

たとえば、永続性のあるデータが必要な操作を実行するJavaストアド・サブプログラム、およびプレゼンテーションやビジネス・ロジック操作を実行する別のプログラムを作成できます。

Javaストアド・サブプログラムのSQLに対するインタフェースは、PL/SQLの実行モデルと類似した実行モデルを使用します。

参照:

- Javaストアド・サブプログラムのその他の概要は、『Oracle Database概要』を参照してください。

- Javaストアド・サブプログラムの詳細は、『Oracle Database Java開発者ガイド』を参照してください。

Oracle Database Webサービスの概要

Webサービスは、Javaアプリケーション開発用の分散コンピューティング・パラダイムを提供し、JDBCなどの初期のJavaプロトコルのかわりとなり、アプリケーションがXMLおよびWebプロトコルを介して相互作用できるようにします。たとえば、電子部品のベンダーは、在庫管理のためにWebベースのプログラム・インタフェースを仕入先に提供できます。ベンダーは、プログラムの一部としてWebサービスを起動し、戻されたデータに基づいて在庫を自動的に発注できます。

Webサービスで使用される主要なテクノロジは次のとおりです。

- Webサービス記述言語(WSDL): XML文書作成のための標準書式。WSDLでは、Webサービスで実行できる操作、Webサービスの位置および起動方法が記述されます。特に、Webサービスが提供する操作およびパラメータ(パラメータ型を含む)が記述されます。また、WSDL文書には、Webサービスの位置、転送プロトコルおよび起動スタイルも記述されます。

- Simple Object Access Protocol(SOAP)メッセージ: Webサービスで使用するXMLベースのメッセージ・プロトコル。SOAPでは、HTTP、FTP、SMTPまたはJMSなどの特定の転送メカニズムは指定しませんが、ほとんどのWebサービスはHTTPまたはHTTPSを使用するメッセージを受信します。

- Universal Description, Discovery, and Integration(UDDI)ビジネス・レジストリ: Webサービスをインターネット上でリスト表示するディレクトリ。UDDIレジストリはよく電話帳と比較されます。たとえば、一意の識別子のリスト表示(ホワイト・ページ)、ビジネス・カテゴリのリスト表示(イエロー・ページ)およびサービス・プロトコルへのバインド指示(グリーン・ページ)という具合です。

Webサービスでは、様々な方法およびプロトコルを使用できます。次に例を示します。

- 同期ディスパッチ(通常)または非同期ディスパッチが可能です。

- Webサービスは、引数が送信されて応答が戻されるRPCスタイルの操作、または一方向のSOAP文書交換などのメッセージ・スタイルで起動できます。

- 様々なエンコーディング・ルール(リテラルまたはエンコード)を使用できます。

Webサービスは、必要な情報が事前にすべてわかっている場合は静的に起動でき、操作およびトランスポート・エンドポイントをその場で検出できる場合は動的に起動できます。

Oracle Databaseは、Webサービス・プロバイダまたはWebサービス・コンシューマのいずれかとして機能できます。プロバイダとしてデータベースを使用すると、ストアド・サブプログラム、データ、メタデータ、およびキューイング・システムやメッセージング・システムなどのデータベース・リソースに対するアクセスを共有および切断できます。

Webサービス・プロバイダとしてOracle Databaseを使用すると、次のような非接続環境および異機種間環境が提供されます。

- 作成に使用された言語に依存しないストアド・サブプログラムの公開

- SQL問合せおよびXQueryの公開

参照:
Webサービス・プロバイダとしてのOracle Databaseのその他の概要は、『Oracle Database概要』を参照してください。

PL/SQLまたはJavaの選択

PL/SQLおよびJavaは、サーバー内で相互運用します。JavaからPL/SQLパッケージを実行するか、またはJavaラッパーでPL/SQLクラスをラップして、分散CORBAおよびEnterprise JavaBeansクライアントから起動できるようにできます。

表13-1に、PL/SQLパッケージ、およびそれぞれの相当するJavaでの操作を示します。

表13-1 PL/SQLパッケージおよび相当するJavaでの操作

PL/SQLパッケージ

相当するJavaでの操作

DBMS_ALERT

SQLJまたはJDBCでパッケージをコールします。

DBMS_DDL

JDBCを使用します。

DBMS_JOB

Javaストアド・サブプログラムを持つジョブをスケジューリングします。

DBMS_LOCK

SQLJまたはJDBCでコールします。

DBMS_MAIL

JavaMailを使用します。

DBMS_OUTPUT

サブクラスoracle.aurora.rdbms.OracleDBMSOutputStreamまたはJavaストアド・サブプログラムDBMS_JAVA.SET_STREAMSを使用します。

DBMS_PIPE

SQLJまたはJDBCでコールします。

DBMS_SESSION

JDBCを使用して、ALTER SESSION文を実行します。

DBMS_SNAPSHOT

SQLJまたはJDBCでコールします。

DBMS_SQL

JDBCを使用します。

DBMS_TRANSACTION

JDBCを使用して、ALTER SESSION文を実行します。

DBMS_UTILITY

SQLJまたはJDBCでコールします。

UTL_FILE

JAVAUSERPRIV権限を付与してJava I/Oエントリ・ポイントを使用します。

内容は次のとおりです。

- PL/SQLとJavaの類似性

- Javaに対するPL/SQLの利点

- PL/SQLに対するJavaの利点

PL/SQLとJavaの類似性

PL/SQLおよびJavaにはどちらもパッケージおよびライブラリがあります。

PL/SQLおよびJavaにはどちらも次のオブジェクト指向機能があります。

- どちらにも継承があります。

- PL/SQLには、型進化(型のメソッドおよび属性を、その型を使用するサブタイプおよび表データを保持しながら変更する機能)があります。

- Javaには、分散システムを開発するためのポリモフィズムおよびコンポーネント・モデルがあります。

Javaに対するPL/SQLの利点

SQLの拡張機能であるPL/SQLでは、すべてのSQLデータ型、データ・カプセル化、情報隠蔽、オーバーロードおよび例外処理がサポートされます。このため次の利点があります。

- SQLデータ型は、JavaよりもPL/SQLで簡単に使用できます。

- SQL操作はJavaよりもPL/SQLで速く処理されます(特に大量のデータが扱われる場合、多くのデータベース・アクセスが行われる場合、またはバルク操作が使用される場合)。
Oracle9iでは、一部の高度なPL/SQL機能がJavaで使用できない場合があります(たとえば、自律型トランザクションやリモート・データベース用のdblink機能などです)。

PL/SQLでのコード開発は、通常、Javaを使用した場合より速く行うことができます。

PL/SQLに対するJavaの利点

Javaはオープン分散アプリケーション用に使用され、多くのJavaベース開発ツールが存在しています。JavaにはPL/SQLよりも豊富な型体系があります。JavaはCORBA(クライアントに様々なコンピュータ言語を持つことができます)およびEnterprise JavaBeansを使用できます。PL/SQLパッケージはCORBAまたはEnterprise JavaBeansクライアントから起動できます。Javaによって、XMLツール、Internet File SystemまたはJavaMailを実行できます。

プリコンパイラの概要

クライアント/サーバー・プログラムは、通常、プリコンパイラを使用して作成されます。プリコンパイラは、C、C++、COBOLなどの言語で作成された高レベル・プログラムにSQL文を埋め込むためのプログラミング・ツールです。クライアント・アプリケーションは、SQL文をホストするためホスト・プログラムと呼ばれ、その作成に使用される言語はホスト言語と呼ばれます。

プリコンパイラはホスト・プログラムを入力として受け取り、埋込みSQL文を標準データベース・ランタイム・ライブラリ・コールに変換し、ソース・プログラムを生成します。ユーザーは、通常の方法でソース・プログラムをコンパイルおよびリンクして、実行できます。

内容は次のとおりです。

- Pro*C/C++プリコンパイラの概要

- Pro*COBOLプリコンパイラの概要

参照:
Oracleプリコンパイラのその他の概要は、『Oracle Database概要』を参照してください。

Pro*C/C++プリコンパイラの概要

Pro*C/C++プリコンパイラの場合、ホスト言語はCまたはC++です。Pro*C/C++プリコンパイラの機能の一部は次のとおりです。

- スレッド・パッケージをサポートしているプラットフォームの場合は、マルチスレッド・プログラムを作成できます。同時接続は、シングル・スレッド・アプリケーションでもマルチスレッド・アプリケーションでもサポートされます。

- PL/SQLブロックを埋め込むことによって、パフォーマンスを向上できます。PL/SQLブロックは、ユーザーが独自に作成したか、またはOracle Databaseパッケージで提供されている、JavaやPL/SQLのサブプログラムを起動できます。

- プリコンパイラ・オプションを使用すると、プリコンパイル時のみでなく、実行時にもSQL文またはPL/SQL文の構文およびセマンティクスを確認できます。

- PL/SQLおよびJavaのストアド・サブプログラムを起動できます。COBOLまたはCで作成したモジュールは、Pro*C/C++から起動できます。共有ライブラリ内の外部Cサブプログラムは、プログラムから起動できます。

- 様々な環境で実行できるように、条件付きでコード・セクションをプリコンパイルできます。

- パフォーマンスを向上させるには、コード内で配列、構造体または構造体配列をホスト変数およびインジケータ変数として使用します。

- エラーおよび警告を処理してデータの整合性を保証することができます。エラーをどのように処理するかは、プログラマが制御します。

- プログラムで内部データ型からC言語データ型(またはその逆)に変換できます。

- 低レベルのCインタフェースおよびC++インタフェースであるOracle Call Interface(OCI)およびOracle C++ Call Interface(OCCI)は、プリコンパイラ・ソース内で使用できます。

- Pro*C/C++は、動的SQL(変数の値および文の構文をユーザーが入力できる手法)をサポートします。

- Pro*C/C++で、特殊なSQL文を使用してユーザー定義のオブジェクト型を含む表を操作できます。Object Type Translator(OTT)で、データベース内のADTおよび名前付きコレクション型を、ソースに含める構造体およびヘッダーにマップします。

- ネストした表およびVARRAYという2種類のコレクション型が一連のSQL文でサポートされています。これによって、データを高度に制御できます。

- ラージ・オブジェクトは、別の一連のSQL文によってアクセスされます。

- 動的SQLのための新しいANSI SQL規格が新しいアプリケーション用にサポートされ、様々なホスト変数を使用してSQL文を実行できます。動的SQLのための従来の手法も、既存のアプリケーションで使用できます。

- グローバリゼーション・サポートによって、マルチバイト・キャラクタおよびUCS2 Unicodeデータを使用できます。

- スクロール可能カーソルを使用して、結果セット内を移動できます。たとえば、結果セットの最終行のフェッチ、または結果セット内の絶対位置または相対位置へのジャンプが可能です。

- 接続プールは、いくつかの名前付き接続で共有されているデータベースへの物理接続のグループです。接続プールのオプションを有効化すると、Pro*C/C++アプリケーションのパフォーマンスを最適化できます。接続プールのオプションは、デフォルトでは無効になっています。

参照:
Pro*C/C++プリコンパイラの詳細は、Pro*C/C++プリコンパイラのプログラマーズ・ガイドを参照してください。

例13-1に、スキーマhr内のemployees表を問い合せるCソース・プログラムのコードの一部を示します。

例13-1 Pro*C/C++アプリケーション

...
#define  UNAME_LEN   10
...
int   emp_number;
/* Define a host structure for the output values of a SELECT statement. */
/* No declare section needed if precompiler option MODE=ORACLE          */
struct {
VARCHAR  last_name[UNAME_LEN];
float    salary;
float    commission_pct;
} emprec;
/* Define an indicator structure to correspond to the host output structure. */
struct {
short emp_name_ind;
short sal_ind;
short comm_ind;
} emprec_ind;
...
/* Select columns last_name, salary, and commission_pct given the user's input
/* for employee_id. */
EXEC SQL SELECT last_name, salary, commission_pct
INTO :emprec INDICATOR :emprec_ind
FROM employees
WHERE employee_id = :emp_number;
...

埋込みSELECT文と対話型(SQL*Plus)のSELECT文との違いはごくわずかです。すべての埋込みSQL文はEXEC SQLで始まります。コロン(:)がすべてのホスト(C)変数の前に付きます。データおよび(データ値がNULLの場合または文字列が切り捨てられたときに設定される)インジケータの戻り値は、(前述のコード部分にあるような)構造体、配列または構造体配列の中に格納できます。結果セットの値が複数の場合でも、前述の例(社員番号が一意のため結果が1つのみ)と同様の方法で簡単に処理されます。埋込みSQLでは、列および表の実際の名前を使用します。

プリコンパイラ・オプションのデフォルト値を使用することも、リソースの使用方法、エラーの通知方法、出力形式およびカーソル(特定の接続またはSQL文に対応するカーソル)の管理方法を制御するための値を入力することもできます。カーソルは、結果セットの値が複数の場合に使用します。

オプションは、構成ファイル内に入力するか、コマンドラインに入力するか、またはEXEC ORACLEで始まる特殊な文でソース・コード内に直接入力します。エラーが見つからなかった場合は、次に、Cプログラムの場合と同じように出力ソース・ファイルをコンパイルおよびリンクして実行します。

クライアントからのサーバー・データベース・アクセスを様々なプラットフォーム上に配置できるように作成するには、プリコンパイラを使用します。Pro*C/C++を使用すると、独自のユーザー・インタフェースを自由に設計し、既存のアプリケーションに自由にデータベース・アクセスを追加できます。

埋込みSQL文を作成する前に、SQL*Plusで対話型SQLをテストし、その後、少し変更を加えることで、埋込みSQLアプリケーションのテストを開始できます。

Pro*COBOLプリコンパイラの概要

Pro*COBOLプリコンパイラの場合、ホスト言語はCOBOLです。Pro*COBOLプリコンパイラの機能の一部は次のとおりです。

- PL/SQLまたはJavaのストアド・サブプログラムを起動できます。PL/SQLブロックを埋め込むことによって、パフォーマンスを向上できます。PL/SQLブロックでは、独自に作成したか、またはOracle Databaseパッケージで提供されているサブプログラムを起動できます。

- プリコンパイラ・オプションを使用すると、カーソル、エラー、構文検査、ファイル形式などの処理方法を定義できます。

- プリコンパイラ・オプションを使用すると、プリコンパイル時のみでなく、実行時にもSQL文またはPL/SQL文の構文およびセマンティクスを確認できます。

- 様々な環境で実行できるように、条件付きでコード・セクションをプリコンパイルできます。

- パフォーマンスを向上させるには、コード内で表、グループ項目またはグループ項目の表をホスト変数またはインジケータ変数として使用します。

- エラーおよび警告の処理方法をプログラミングし、データの整合性を保証できます。

- Pro*COBOLは、動的SQL(変数の値および文の構文をユーザーが入力できる手法)をサポートします。

参照:
Pro*COBOLプリコンパイラの詳細は、『Pro*COBOLプログラマーズ・ガイド』を参照してください。

例13-2に、スキーマhr内のemployees表を問い合せるCOBOLソース・プログラムのコードの一部を示します。

例13-2 Pro*COBOLアプリケーション

...
WORKING-STORAGE SECTION.
*
* DEFINE HOST INPUT AND OUTPUT HOST AND INDICATOR VARIABLES.
* NO DECLARE SECTION NEEDED IF MODE=ORACLE.
*
01  EMP-REC-VARS.
05  EMP-NAME    PIC X(10) VARYING.
05  EMP-NUMBER  PIC S9(4) COMP VALUE ZERO.
05  SALARY      PIC S9(5)V99 COMP-3 VALUE ZERO.
05  COMMISSION  PIC S9(5)V99 COMP-3 VALUE ZERO.
05  COMM-IND    PIC S9(4) COMP VALUE ZERO.
...
PROCEDURE DIVISION.
...
EXEC SQL
SELECT last_name, salary, commission_pct
INTO :EMP-NAME, :SALARY, :COMMISSION:COMM-IND
FROM employees
WHERE employee_id = :EMP-NUMBER
END-EXEC.
...

埋込みSELECT文と対話型(SQL*Plus)のSELECT文との違いはごくわずかです。すべての埋込みSQL文はEXEC SQLで始まります。コロン(:)がすべてのホスト(COBOL)変数の前に付きます。SQL文はEND-EXECによって終了します。データおよび(データ値がNULLの場合または文字列が切り捨てられたときに設定される)インジケータの戻り値は、(前述のコード部分にあるような)グループ項目、表、またはグループ項目の表に格納できます。結果セットの値が複数の場合でも、前述の例(社員番号が一意のため結果が1つのみ)と同様の方法で簡単に処理されます。埋込みSQLでは、列および表の実際の名前を使用します。

プリコンパイラ・オプションのデフォルト値を使用することも、リソースの使用方法、エラーの通知方法、出力形式およびカーソル(特定の接続またはSQL文に対応するカーソル)の管理方法を制御するための値を入力することもできます。

オプションは、構成ファイル内に入力するか、コマンドラインに入力するか、またはEXEC ORACLEで始まる特殊な文でソース・コード内に直接入力します。エラーが見つからなかった場合は、COBOLプログラムの場合と同じように出力ソース・ファイルをコンパイルおよびリンクして実行できます。

クライアントからのサーバー・データベース・アクセスを様々なプラットフォーム上に配置できるように作成するには、プリコンパイラを使用します。Pro*COBOLを使用すると、独自のユーザー・インタフェースを自由に設計し、既存のCOBOLアプリケーションに自由にデータベース・アクセスを追加できます。

使用できる埋込みSQL文はANSI規格に準拠しているため、Oracle Net経由で多数のデータベースのデータにアクセスできます。

埋込みSQL文を作成する前に、SQL*Plusで対話型SQLをテストし、その後、少し変更を加えることで、埋込みSQLアプリケーションのテストを開始できます。

OCIおよびOCCIの概要

Oracle Call Interface(OCI)およびOracle C++ Call Interface(OCCI)は、APIです。これらによって、3GL固有のサブプログラム起動を使用して、Oracle Databaseにアクセスしたり、SQL文実行のすべての過程を制御するアプリケーションを作成できます。これらのAPIは次のものを提供します。

- システム・メモリーおよびネットワーク接続の効率的な使用による、パフォーマンスおよびスケーラビリティの向上

- 2層クライアント/サーバー環境または複数層環境における、動的なセッションおよびトランザクション管理のための一貫したインタフェース

- N層認証

- Oracle Databaseオブジェクトを使用したアプリケーション開発の包括的サポート

- 外部データベースへのアクセス

- 増加するユーザー数および要求数に対応したサービスを、ハードウェアを追加しなくても提供できるアプリケーション開発

OCIを使用すると、データベース内のデータおよびスキーマをC言語のようなホスト・プログラミング言語を使用して操作できます。OCCIは、C++言語との使用に適したオブジェクト指向インタフェースです。これらのAPIは、標準的なデータベース・アクセス関数および検索関数のライブラリを、実行時にアプリケーション内にリンクされる動的ランタイム・ライブラリ(OCILIB)の形式で提供します。SQLまたはPL/SQLを3GLプログラムに埋め込む必要はありません。

参照:
OCIおよびOCCIコールの詳細は、次を参照してください。

- 『Oracle Call Interfaceプログラマーズ・ガイド』

- 『Oracle C++ Call Interfaceプログラマーズ・ガイド』

- 『Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド』

- 『Oracle Databaseグローバリゼーション・サポート・ガイド』

- 『Oracle Databaseデータ・カートリッジ開発者ガイド』

内容は次のとおりです。

- OCIおよびOCCIのメリット

- OCIおよびOCCI関数

- OCIおよびOCCIアプリケーションの手続き型要素および非手続き型要素

- OCIアプリケーションまたはOCCIアプリケーションの作成

OCIおよびOCCIのメリット

OCIおよびOCCIは、Oracle Databaseに対する他のアクセス方法に比べて、次のような優れたメリットがあります。

- アプリケーション設計のすべての面に対する細かな制御。

- プログラムに対する高度な実行制御。

- 使い慣れた3GLプログラム手法およびアプリケーション開発ツール(ブラウザやデバッガなど)の使用。

- 動的SQL、メソッド4のサポート。

- 様々なプラットフォームにおいて、すべてのOracle Databaseのプログラム・インタフェースが使用可能。

- コールバックを使用した動的バインドおよび定義。

- サーバー・メタデータ層を表す記述機能。

- 登録されたクライアント・アプリケーションに対する非同期のイベント通知。

- 配列のデータ操作言語(DML)の機能拡張。

- コミット要求を実行に対応付けてラウンドトリップを減らす機能

- 透過的プリフェッチ・バッファを使用して問合せを最適化し、ラウンドトリップを減らす機能。

- OCIおよびOCCIハンドルに対する相互排他(mutex)ロックの実装が不要になるスレッド・セーフティ。

- 非ブロック化モードでのサーバー接続コールが実行中か、または完了できない場合、制御がOCIコードまたはOCCIコードに戻る機能。

OCIおよびOCCI関数

OCIとOCCIの両方とも、次の種類の関数があります。

関数の種類

目的

リレーショナル

データベース・アクセスを管理し、SQL文を処理します。

ナビゲーション

データベースから取得したオブジェクトを操作します。

データベースのマッピングおよび操作

Oracle Databaseデータ型のデータ属性を操作します。

外部サブプログラム

PL/SQLからCコールバックを作成します。

OCIおよびOCCIアプリケーションの手続き型要素および非手続き型要素

OCIおよびOCCIを使用すると、SQLが提供する強力な非手続き型データ・アクセス機能と、CやC++など数多くのプログラミング言語で提供される手続き型機能を組み合せたアプリケーションを開発できます。手続き型言語および非手続き型言語には次のような特性があります。

- 非手続き型言語プログラムでは、操作対象のデータ群は指定されますが、実行される操作およびその操作の実行方法は指定されません。SQLは非手続き型であるため、データベース・トランザクションの実行用として簡単に覚えやすく使用しやすい言語です。また、SQLは、最新のリレーショナル・データベース・システムおよびオブジェクト・リレーショナル・データベース・システムにおけるデータのアクセスおよび操作に使用される標準言語でもあります。

- 手続き型言語プログラムでは、文の実行の多くが、その前後の文や、ループまたは条件ブランチなどの制御構造に依存します。これらはSQLでは使用できません。このような言語は、手続き型であるためにSQLより複雑になりますが、非常に柔軟で強力でもあります。

OCIプログラムまたはOCCIプログラムで非手続き型言語の要素と手続き型言語の要素を組み合せることができるため、構造化プログラミング環境の中でOracle Databaseに簡単にアクセスできます。

OCIおよびOCCIでは、Oracle Databaseで使用可能なSQLのデータ定義、データ操作、問合せおよびトランザクション制御のすべての機能をサポートします。たとえば、OCIプログラムまたはOCCIプログラムはOracle Databaseに対する問合せを実行できます。この問合せで、次のように、入力(バインド)変数を使用してデータベースにデータを提供するようにプログラムに要求できます。

SELECT name FROM employees WHERE empno = :empnumber

このSQL文では、:empnumberがアプリケーションによって提供される値のプレースホルダです。

また、SQLの手続き型拡張言語である、OracleのPL/SQLを使用することもできます。PL/SQLで開発するアプリケーションは、SQLのみで作成したアプリケーションより強力で柔軟です。OCIおよびOCCIは、Oracle Databaseにあるオブジェクトにアクセスし、操作する機能も提供しています。

OCIアプリケーションまたはOCCIアプリケーションの作成

図13-1に示すとおり、OCIまたはOCCIプログラムは非データベース・アプリケーションと同じ方法でコンパイルおよびリンクします。特別な事前処理またはプリコンパイルは必要ありません。

図13-1 OCIまたはOCCIの開発過程

注意:
OCIプログラムおよびOCCIプログラムを正しくリンクするには、プラットフォームによってはOCIライブラリおよびOCCIライブラリ以外のライブラリを含める必要があります。必要な追加ライブラリの詳細は、プラットフォーム固有のOracleマニュアルを参照してください。

プリコンパイラまたはOCIの選択

通常、プリコンパイラ・アプリケーションには同等のOCIアプリケーションより少ないコードが含まれているため、生産性が向上します。

データベースを詳細に制御する必要がある場合は、OCIアプリケーション(純OCIアプリケーションまたはOCIコールが埋め込まれたプリコンパイラ・アプリケーション)の方が適しています。

- OCIでは、セッションの多重化および移行をより詳細に制御できます。

- OCIでは、リストを含む任意の構造体に使用できるコールバックを使用して、動的バインドおよび定義が提供されます。

- OCIにはメタデータを扱う多くのコールがあります。

- OCIでは、クライアント・アプリケーションに対して非同期のイベントを通知できます。クライアントに対し、他のクライアントに伝播するための通知を生成する手段が提供されます。

- OCIでは、任意のエラー・メッセージを戻す前に、DML文は配列を使用してできるだけ多くの反復を完了します。

- 特殊な目的のためのOCIコールには、アドバンスト・キューイング、グローバリゼーション・サポート、データ・カートリッジおよび日時データ型のサポートが含まれます。

- OCIコールは、Pro*C/C++アプリケーションに埋め込むことができます。

Oracle Data Provider for .NET(ODP.NET)の概要

Oracle Data Provider for .NET(ODP.NET)は、Oracle Databaseのデータ・プロバイダの実装です。

ODP.NETはOracle Database固有のAPIを使用して、.NETアプリケーションからデータベース機能およびデータへの高速かつ高信頼アクセスを提供します。また、ODP.NETは、Microsoft .NET Framework Class Libraryで入手可能なクラスおよびインタフェースを使用し、継承します。

Oracle Provider for OLE DBを使用するプログラマに対して、ADO(ActiveX Data Objects)では簡単なプログラミング・モデルを表すオートメーション・レイヤーを提供します。ADO.NETからも類似したプログラミング・モデルがパフォーマンスの向上のために提供されますが、オートメーション・レイヤーはありません。さらに重要な点として、ADO.NETモデルを使用することで、ODP.NETなどのネイティブ・プロバイダはOracle Database固有の特定の機能およびデータ型を公開できるようになります。

参照:
Oracle Data Provider for .NET開発者ガイド

次に、Oracle Databaseに接続し、接続を切断する前にバージョン番号を表示する単純なC#アプリケーションを示します。

using System;
using Oracle.DataAccess.Client;

class Example
{
OracleConnection con;

void Connect()
{
con = new OracleConnection();
con.ConnectionString = "User Id=hr;Password=password;Data Source=oracle";
con.Open();
Console.WriteLine("Connected to Oracle" + con.ServerVersion);
}

void Close()
{
con.Close();
con.Dispose();
}

static void Main()
{
Example example = new Example();
example.Connect();
example.Close();
}
}

注意:
その他のサンプルは、ディレクトリORACLE_BASE\ORACLE_HOME\ODP.NET\Samplesで提供されます。

OraOLEDBの概要

Oracle Provider for OLE DB(OraOLEDB)は、高いパフォーマンスを提供し、OLE DBコンシューマがOracleデータへ効率的にアクセスできるようにするOLE DBデータ・プロバイダです。通常、この開発者ガイドでは、OLE DBまたはADOを介してOraOLEDBを使用していることを想定しています。

参照:
『Microsoft Windows用Oracle Provider for OLE DB開発者ガイド for Microsoft Windows』

Oracle Objects for OLE(OO4O)の概要

Oracle Objects for OLE(OO4O)は、Microsoft COM AutomationおよびActiveXテクノロジをサポートするプログラミング言語またはスクリプト言語であれば、どの言語からでもOracle Database内に格納されているデータに簡単にアクセスできるように設計された製品です。このような言語には、Visual Basic、Visual C++、Visual Basic For Applications(VBA)、IIS Active Server Pages(VBScriptおよびJavaScript)などがあります。

OO4Oの使用方法の詳細は、OO4Oのオンライン・ヘルプを参照してください。

Oracle Objects for OLEは、次のソフトウェア・レイヤーで構成されています。

- OO4Oインプロセス・オートメーション・サーバー

- Oracle Data Control

- Oracle Objects for OLE C++クラス・ライブラリ

図13-2に、OO4Oのソフトウェア・コンポーネントを示します。

図13-2 ソフトウェア・レイヤー

内容は次のとおりです。

- OO4Oオートメーション・サーバー

- OO4Oオブジェクト・モデル

- Oracle LOBおよびオブジェクト・データ型のサポート

- Oracle Data Control

- Oracle Objects for OLE C++クラス・ライブラリ

OO4Oオートメーション・サーバー

OO4Oオートメーション・サーバーは、Oracle Databaseに接続し、SQL文およびPL/SQLブロックを実行してその結果にアクセスする一連のCOMオートメーション・オブジェクトです。

Microsoft ADOなどのCOMベースのデータベース接続APIとは異なり、OO4Oオートメーション・サーバーは、特にOracle Databaseを対象に開発されたものです。

これは、Oracle Database固有の機能にアクセスするために最適化されたAPIを提供します。このAPIを使用せずにODBCまたはOLEデータベース固有のコンポーネントからアクセスすると、煩雑で非効率です。

OO4Oは、Visual BasicまたはExcelなどで開発される典型的な2層クライアント/サーバー・アプリケーションから、Microsoft Internet Information Server(IIS)のWebサーバー・アプリケーションやMicrosoft Transaction Server(MTS)などの複数層アプリケーション・サーバー環境にデプロイされるアプリケーション・サーバーまで、広範囲な環境にわたり、Oracle Databaseに効率的かつ簡単にアクセスするための重要な機能を提供します。

次のような機能があります。

- PL/SQLおよびJavaのストアド・サブプログラム、および無名PL/SQLブロックの実行サポート。これには、PL/SQLカーソルなど、ストアド・サブプログラムのパラメータとして使用されるOracle Databaseデータ型のサポートが含まれます。「Oracle LOBおよびオブジェクト・データ型のサポート」を参照してください。

- 問合せの結果セットに簡単かつ効率的にアクセスし、スクロール可能で更新可能なカーソルのサポート。

- 効率的なWebサーバー・アプリケーション開発のための、スレッド・セーフなオブジェクトおよび接続プール管理機能。

- Oracle Databaseオブジェクト・リレーショナル・データ型およびLOBデータ型の完全サポート。

- AQの完全サポート。

- 配列の挿入および更新のサポート。

- Microsoft Transaction Server(MTS)のサポート。

OO4Oオブジェクト・モデル

図13-3に、Oracle Objects for OLEオブジェクト・モデルを示します。

図13-3 オブジェクトおよびそのリレーション

内容は次のとおりです。

- OraSession

- OraServer

- OraDatabase

- OraDynaset

- OraField

- OraMetaDataおよびOraMDAttribute

- OraParameterおよびOraParameters

- OraParamArray

- OraSQLStmt

- OraAQ

- OraAQMsg

- OraAQAgent

OraSession

OraSessionオブジェクトは、アプリケーション内で使用されるOraDatabase、OraConnectionおよびOraDynasetオブジェクトのコレクションを管理します。

通常は、1つのアプリケーションに対してOraSessionオブジェクトが1つ作成されますが、アプリケーション内とアプリケーション間で共有する名前付きOraSessionオブジェクトを作成できます。

OraSessionオブジェクトは、アプリケーションの最上位オブジェクトです。これは、Oracle Objects for OLEメソッドではなく、CreateObject VB/VBA APIによって作成される唯一のオブジェクトです。次に、OraSessionオブジェクトの作成方法を示すコード・フラグメントを示します。

Dim OraSession as Object
Set OraSession = CreateObject("OracleInProcServer.XOraSession")

OraServer

OraServerは、Oracle Databaseへの物理的なネットワーク接続を表します。

OraServerインタフェースは、Oracle Call Interfaceで提供される接続多重化機能を公開して使用可能にするために導入されています。OraServerオブジェクトの作成後、OpenDatabaseメソッドをコールすることでこのオブジェクトに複数のユーザー・セッション(OraDatabase)を連結できます。この機能は、IISなどのように、N層分散環境でOracle Objects for OLEを使用するアプリケーション・コンポーネント用として特に便利です。

多数のアクティブ・ユーザー・セッションを持ったOracle Databaseにアクセスする際に接続多重化機能を使用することによって、サーバーの処理要件およびリソース要件が削減され、サーバーのスケーラビリティも向上します。

OraServerを使用すると、複数のOraDatabaseオブジェクト(多重化)間で単一接続を共有できる一方で、OraSessionから取得された各OraDatabaseには独自の物理接続を持つことができます。

OraDatabase

OraDatabaseインタフェースは、トランザクション制御用メソッド、およびOracle Databaseオブジェクト型を表すインタフェース作成用のメソッドを追加します。スキーマ・オブジェクトの属性は、OraDatabaseインタフェースのDescribeメソッドを使用して取得できます。

Oracle Database 8gリリース1より前のリリースでは、OraSessionインタフェースのOpenDatabaseメソッドをコールしてOraDatabaseオブジェクトを作成していました。Oracle Netの別名、ユーザー名およびパスワードが、引数としてこのメソッドに渡されます。Oracle Database 8gリリース1では、このメソッドをコールするとOraServerオブジェクトが暗黙的に作成されます。

OraDatabaseオブジェクトはOraServerインタフェースのOpenDatabaseメソッドを使用して作成できます。

トランザクション制御メソッドは、OraDatabase(ユーザー・セッション)レベルで使用できます。トランザクションは、Read-Write(デフォルト)、Serializable、またはRead-onlyとして開始できます。トランザクション制御メソッドには、次が含まれます。

- BeginTrans

- CommitTrans

- RollbackTrans

次に例を示します。

UserSession.BeginTrans(OO4O_TXN_READ_WRITE)
UserSession.ExecuteSQL("delete emp where empno = 1234")
UserSession.CommitTrans

OraDynaset

OraDynasetオブジェクトによって、SQLのSELECT文で作成されたデータを参照および更新できます。

OraDynasetオブジェクトは1つのカーソルと考えることができますが、実際にOraDynasetのセマンティクスを実装するには実カーソルをいくつか使用する場合があります。OraDynasetオブジェクトは、サーバーからフェッチされたデータのローカル・キャッシュを自動的に保持し、ブラウズ・データ内のスクロール可能カーソルを透過的に実装します。大規模な問合せの場合は、かなりのローカル・ディスク領域が必要になる場合があります。アプリケーションを開発する場合は、ディスクの使用が少なくなるように、問合せをさらに微調整することをお薦めします。

OraField

OraFieldオブジェクトは、ダイナセットの行内の単一の列またはデータ項目を表します。

現在行が更新中の場合は、OraFieldオブジェクトは現在更新中の値を表します。ただし、この値はまだデータベースにコミットされていない可能性があります。

フィールドのValueプロパティへの割当ては、(Editを使用して)レコードを編集中の場合、または(AddNewを使用して)レコードを追加中の場合のみ許可されます。他の方法でフィールドのValueプロパティにデータを割り当てると、エラーが発生します。

OraMetaDataおよびOraMDAttribute

OraMetaDataオブジェクトは、データベース内の特定のスキーマ・オブジェクトに関する記述情報を表すOraMDAttributeオブジェクトのコレクションです。

OraMetaDataオブジェクトは、次の3つの列を持つ表として表すことができます。

- メタデータの属性名

- メタデータの属性値

- Valueが別のOraMetaDataオブジェクトかどうかを示すFlag

OraMetaDataオブジェクトに含まれているOraMDAttributeオブジェクトは、序数を使用した添字またはプロパティの名前を使用してアクセスできます。コレクションにない索引を参照すると、NULLのOraMDAttributeオブジェクトが戻されます。

OraParameterおよびOraParameters

OraParameterオブジェクトは、SQL文またはPL/SQLブロック内のバインド変数を表します。

OraParameterオブジェクトは、OraDatabaseオブジェクトのOraParametersコレクションを介して間接的に作成、アクセスおよび削除されます。各パラメータには、それぞれ識別名および関連値があります。SQL文またはPL/SQL文の中でパラメータ名をプレースホルダとして使用すると、(オブジェクトの記述に示されているとおり)他のオブジェクトのSQL文およびPL/SQL文にパラメータを自動的にバインドできます。このようにパラメータを使用することで、動的な問合せを容易にし、プログラムのパフォーマンスを向上させます。

OraParamArray

OraParamArrayオブジェクトは、OraParameterオブジェクトによって表されるスカラー型バインド変数に対して、SQL文またはPL/SQLブロック内の配列型バインド変数を表します。

OraParamArrayオブジェクトは、OraDatabaseオブジェクトのOraParametersコレクションを介して間接的に作成、アクセスおよび削除されます。各OraParamArrayオブジェクトには、それぞれ識別名および関連値があります。

OraSQLStmt

OraSQLStmtオブジェクトは、単一のSQL文を表します。OraDatabaseオブジェクトからOraSQLStmtオブジェクトを作成するには、CreateSQLメソッドを使用します。

OraSQLStmtオブジェクトは、作成中およびリフレッシュ中に、パラメータ名をSQL文でプレースホルダとして使用して、使用可能なすべての関連入力パラメータを指定されたSQL文に自動的にバインドします。これによって、SQL文の再解析をしなくてもSQL文の実行パフォーマンスが向上します。

SALARYプレースホルダに別の値を使用して、後で同一の問合せを実行するために、OraSQLStmtオブジェクトを使用できます。次に例を示します(updateStmtは、ここではOraSQLStmtオブジェクトのことです)。

OraDatabase.Parameters("SALARY").value = 200000
updateStmt.Parameters("ENAME").value = "KING"
updateStmt.Refresh

OraAQ

OraAQオブジェクトは、OraDatabaseインタフェースのCreateAQメソッドを起動してインスタンス化します。このオブジェクトは、データベース内にあるキューを表します。

Oracle Objects for OLEは、Oracle Advanced Queuing(AQ)機能にアクセスするインタフェースを提供します。これによって、Visual Basicなどの一般的なCOMベースの開発環境からAQ機能にアクセスできます。Oracle Advanced Queuingの詳細は、『Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド』を参照してください。

OraAQMsg

OraAQMsgオブジェクトは、キューまたはデキューされるメッセージをカプセル化します。メッセージは、ユーザー定義型またはRAW型です。

Oracle Advanced Queuingの詳細は、『Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド』を参照してください。

OraAQAgent

OraAQAgentオブジェクトはメッセージの受信者を表し、複数コンシューマに対応したキューに対してのみ有効です。これは、OraAQMsgの子です。

OraAQAgentオブジェクトは、AQAgentメソッドをコールしてインスタンス化することもできます。次に例を示します。

Set agent = qMsg.AQAgent(name)

OraAQAgentオブジェクトは、AddRecipientメソッドをコールしてインスタンス化することもできます。次に例を示します。

Set agent = qMsg.AddRecipient(name, address, protocol).

Oracle LOBおよびオブジェクト・データ型のサポート

Oracle Objects for OLE(OO4O)は、Oracle Databaseでのオブジェクト・データ型およびLOBのインスタンスの、アクセスおよび操作を完全にサポートします。図13-4に、OO4Oがサポートするデータ型を示します。

このようなデータ型のインスタンスは、データベースからフェッチするか、あるいは入力変数または出力変数として、ストアド・サブプログラムを含むSQL文およびPL/SQLブロックに渡すことができます。すべてのインスタンスは、属性の動的アクセスおよび操作用のメソッドを提供するCOMオートメーション・インタフェースにマップされます。

図13-4 サポートされているOracle Databaseデータ型

内容は次のとおりです。

- OraBLOBおよびOraCLOB

- OraBFILE

OraBLOBおよびOraCLOB

Oracle Objects for OLEのOraBlobインタフェースおよびOraClobインタフェースは、データ型BLOB、CLOB、およびNCLOBのラージ・データベース・オブジェクトに対して操作を実行するメソッドを提供します。ここでは、BLOB、CLOBおよびNCLOBデータ型をLOBデータ型といいます。

LOBデータは、ReadメソッドおよびCopyToFileメソッドを使用してアクセスします。

LOBデータは、Write、Append、Erase、Trim、Copy、CopyFromFileおよびCopyFromBfileメソッドを使用して変更します。行の中のLOB列の内容を変更する前に、行のロックを取得する必要があります。LOB列がOraDynasetオブジェクトのフィールドの場合は、ロックはEditメソッドをコールして取得します。

OraBFILE

Oracle Objects for OLEのOraBFileインタフェースは、データ型BFILEのラージ・データベース・オブジェクトに対して操作を実行するメソッドを提供します。

BFILEは、データベース表領域外のオペレーティング・システム・ファイル内に格納される大規模なバイナリ・データ・オブジェクトです。

Oracle Data Control

Oracle Data Control(ODC)は、Visual Basicおよびカスタム・コントロールをサポートするその他の開発ツールにおける、ビジュアル・コントロール(編集、テキスト、リストおよびグリッド)とOracle Databaseとの間のデータ交換を簡素化するために設計されたActiveXコントロールです。

ODCは、Oracle Databaseと、それにバインドされたグリッド・コントロールなどのビジュアルなデータ認識コントロールからの情報の流れを処理するエージェントとして機能します。ODCは、データの表示および編集などの様々なユーザー・インタフェース(UI)・タスクを管理します。また、データベースに対する問合せの実行および結果の管理も行います。

Oracle Data Controlは、Visual Basicに含まれているMicrosoftデータ・コントロールに相当します。Visual Basicのデータ・コントロールを使い慣れている場合は、Oracle Data Controlの使用方法をすぐに理解できます。データ認識コントロールとODCとの間の通信は、Microsoftの指定したプロトコルによって制御されます。

Oracle Objects for OLE C++クラス・ライブラリ

Oracle Objects for OLE(OO4O)C++クラス・ライブラリは、Oracle Object Serverに対するプログラム・アクセスを提供するC++クラスのコレクションです。このクラス・ライブラリはOLEオートメーションを使用して実装されていますが、クラス・ライブラリの使用にはOLE開発キットまたはOLE開発知識は必要ありません。このライブラリを使用すると、C++開発者は、OO4OインタフェースにアクセスするCOMクライアント・コードを作成する必要がありません。

参照:

- Oracle Objects for OLEの詳細は、OO4O製品とともに提供されている次のオンライン・ヘルプを参照してください。
Oracle Objects for OLEヘルプ

Oracle Objects for OLE C++クラス・ライブラリ・ヘルプ

- Oracle Objects for OLEの使用例は、次のドキュメントを参照してください。
Oracle DatabaseインストールのORACLE_HOME\OO4Oディレクトリ内のサンプル

Oracle Database SecureFiles and Large Objects開発者ガイド

『Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド』

14 複数のプログラミング言語を使用したアプリケーションの開発

この章では、他のプログラミング言語で記述された外部プロシージャをコールするデータベース・アプリケーションの開発方法について説明します。

内容は次のとおりです。

- 複数言語プログラムの概要

- 外部プロシージャの概要

- 外部プロシージャ用のコール仕様の概要

- 外部プロシージャのロード

- 外部プロシージャの公開

- Javaクラス・メソッドの発行

- 外部Cプロシージャの発行

- コール仕様の位置

- コール仕様による外部Cプロシージャへのパラメータの受渡し

- CALL文による外部プロシージャの実行

- 複数言語のプログラム・エラーおよび例外処理

- 外部Cプロシージャでのサービス・ルーチンの使用

- 外部Cプロシージャを使用したコールバックの実行

複数言語プログラムの概要

Oracle Databaseは、次に示す複数の異なる言語での操作が可能です。

- 『Oracle Database PL/SQL言語リファレンス』で説明されるPL/SQL

- 『Oracle Call Interfaceプログラマーズ・ガイド』で説明される、Oracle Call Interface(OCI)を使用したC

- 『Pro*C/C++プログラマーズ・ガイド』で説明される、Pro*C/C++プリコンパイラを使用したCまたはC++

- 『Pro*COBOLプログラマーズ・ガイド』で説明される、Pro*COBOLプリコンパイラを使用したCOBOL

- 『Oracle Data Provider for .NET開発者ガイド』で説明される、Oracle Data Provider for .NET(ODP.NET)を使用した.NET

- 『Oracle Objects for OLE開発者ガイド for Microsoft Windows』、および『Oracle Provider for OLE DB開発者ガイド for Microsoft Windows』で説明される、Oracle Objects for OLE(OO4O)およびOracle Provider for OLE DBを使用したVisual Basic。

- JDBCアプリケーション・プログラム・インタフェース(API)を使用したJava。『Oracle Database Java開発者ガイド』を参照してください。

これらの実装言語の中から何をどのように選択できるでしょうか。各言語には、それぞれ異なるメリットがあります。使用しやすさ、特定の専門知識を持つプログラマがいるかどうか、移植が必要かどうか、さらに既存コードの有無などが重要な決定要因になります。

ただし、アプリケーションでOracle Databaseをどのように使用するかによって、次のように選択範囲が狭くなる可能性があります。

- PL/SQLは、SQLトランザクション処理に特化した強力な開発ツールです。

- 演算集中型のタスクは、Cなどの下位レベル言語で最も効率的に実行されます。

- 移植性とセキュリティの両方を求める場合は、Javaを選択できます。

パフォーマンスに関して最も重要なことは、サーバーのアドレス空間内で実行されるのはPL/SQLおよびJavaメソッドのみであるということです。C/C++メソッドは外部プロシージャとしてディスパッチされ、サーバー・システム上で実行されますが、これはデータベース・サーバーのアドレス空間外です。Pro*COBOLおよびPro*C/C++はプリコンパイラであり、Visual BasicはCで実装されているOCIを介してOracle Databaseにアクセスします。

以上のすべての要因を考慮すると、アプリケーションを複数の言語で実装する必要がある場合があることがわかります。たとえば、サーバーのアドレス空間内で実行されるJavaの登場によって、既存のJavaアプリケーションをデータベース内にインポートし、PL/SQLおよびSQLからJava関数をコールしてこのテクノロジを利用するという方法も可能になります。

PL/SQL外部プロシージャにより、Cプロシージャ・コールをPL/SQLの本体として作成できます。このようなCプロシージャは、PL/SQLからは直接、またSQLからはPL/SQLプロシージャ・コールを介してコールできます。データベースでは、コール仕様というインタフェースが提供されています。コール仕様を使用すると、他の言語から外部プロシージャをコールできます。このサービスは、SQL、PL/SQL、CおよびJava間の相互通信用に設計されていますが、このような言語をコールできる基本言語ならどの言語からでもアクセスできます。たとえば、JavaまたはC以外の言語で作成したプロシージャでも、Cからコール可能なプロシージャであれば、SQLまたはPL/SQLからでも使用できます。したがって、候補となるC++プロシージャがある場合は、そのプロシージャでC++のextern "C"文を使用してそのプロシージャをCからコールできるようにします。

したがって、複数の異なる言語の強みおよび機能をプログラム環境に関係なく利用できます。固有の制約を持つ1つの言語に制限する必要はありません。外部プロシージャの使用によって、特定の目的に特定の言語をデプロイできるため、再利用性およびモジュール性が向上します。

外部プロシージャの概要

外部プロシージャとは、動的リンク・ライブラリ(DLL)に格納されているプロシージャ、またはJavaクラス・メソッドの場合はライブラリ・ユニットのことです。このプロシージャを基本言語に登録し、これをコールして特定の処理を実行できます。

たとえば、PL/SQLを使用する場合、PL/SQLが実行時にライブラリを動的にロードし、次に、プロシージャをPL/SQLプロシージャとみなしてコールします。このようなプロシージャは、現行のトランザクションに完全に組み込まれ、データベースをコールバックしてSQL操作を実行できます。

このようなプロシージャは必要なときにのみロードされるため、メモリーが節約されます。コール仕様が実装本体から切り離されているため、コール側プログラムに影響することなく、プロシージャを拡張できます。

外部プロシージャを使用すると、次のようなことができます。

- クライアント・アプリケーションの実行とデータベース・インスタンスからのプロセスを分離し、クライアント側で生じた問題がデータベースに悪影響を与えないようにすることができます。

- 演算集中型プログラムをクライアントから実行速度の速いサーバーへ移動できます(ネットワーク通信でのラウンドトリップを回避するため)。

- データベース・サーバーと外部システムおよびデータ・ソースとのインタフェースが実現します。

- データベース・サーバー自体の機能を拡張できます。

注意:
外部ライブラリ(DLLファイル)は静的なリンクである必要があります。他の外部ライブラリ(DLLファイル)からの外部記号を参照すべきではありません。Oracle Databaseはこういった記号を解決するため、外部プロシージャの原因による失敗がありません。

外部プロシージャ用のコール仕様の概要

外部プロシージャの発行は、コール仕様を介して行いますが、このコール仕様には、AS LANGUAGE句を介したAS EXTERNAL機能のスーパーセットが含まれます。AS LANGUAGEコール仕様を使用すると、外部Cプロシージャを発行できる他に、Javaクラス・メソッドも発行できます。

注意:
レガシー・アプリケーションをサポートするために、コール仕様では、AS EXTERNAL句を使用して発行することもできます。ただし、アプリケーションを開発する場合は、AS LANGUAGE句を使用することをお薦めします。

一般に、コール仕様を使用することによって、次のようなことができます。

- 適切なCまたはJavaのターゲット・プロシージャのディスパッチ

- データ型の変換

- パラメータ・モードのマッピング

- 自動的なメモリー割当ておよびクリーンアップ

- SQLからコールされるパッケージ・ファンクションに必要に応じて指定される純粋度制約。

- データベース・トリガーからのJavaメソッドまたはCプロシージャのコール

- 位置の柔軟性: パフォーマンスを最適化し実装の詳細を隠すために、AS LANGUAGEコール仕様を、パッケージ仕様または型仕様、あるいはパッケージ(または型)本体に入れることができます。

既存プログラムを外部プロシージャとして使用するには、そのプログラムをロードして発行した後、コールします。

外部プロシージャのロード

外部CプロシージャまたはJavaメソッドをPL/SQLで使用できるようにするには、プロシージャまたはメソッドをロードする必要があります。ロード方法は、プロシージャがCで作成されているかJavaで作成されているかによって異なります。

内容は次のとおりです。

- Javaクラス・メソッドのロード

- 外部Cプロシージャのロード

Javaクラス・メソッドのロード

Javaプログラムのロード方法の1つとして、SQL*Plusから対話形式で実行できるCREATE JAVA文を使用する方法があります。CREATE JAVA文からJava仮想マシン(JVM)ライブラリ・マネージャが暗黙的にコールされ、そのときにこのライブラリ・マネージャがJavaバイナリ(.classファイル)およびリソースをローカルなBFILEまたはLOB列からRDBMSライブラリ・ユニットにロードします。

コンパイル済のJavaクラスが次のオペレーティング・システム・ファイルhome/java/bin/Agent.classに格納されているとします。

ファイルAgent.classから、次のようにスキーマusernameにlibunitを作成します。

1. SYSTEMとしてデータベースに接続し、ユーザーusernameにCREATE ANY DIRECTORY権限を付与します。

2. usernameとしてデータベースにアクセスし、サーバーのファイル・システム上に次のようにディレクトリ・オブジェクトを作成します。

CREATE DIRECTORY Bfile_dir AS '/home/java/bin';

ディレクトリ・オブジェクトの名前は、Agent.classのディレクトリ・パスの別名です。

3. クラスlibunitを次のように作成します。

CREATE JAVA CLASS USING BFILE (Bfile_dir, 'Agent.class');

libunitの名前は、クラスの名前から導出されます。

別の方法として、コマンドライン・ユーティリティLoadJavaを使用できます。このユーティリティは、Javaバイナリおよびリソースを、システムによって生成されたデータベース表にアップロードしてから、CREATE JAVA文を使用してJavaファイルをRDBMSライブラリ・ユニットにロードします。Javaファイルは、ファイル・システム、Java IDE、イントラネットまたはインターネットからアップロードできます。

外部Cプロシージャのロード

注意:
外部Cプロシージャは、DLLをサポートするプラットフォームまたはSolarisの.soライブラリなどの動的にロード可能な共有ライブラリをサポートするプラットフォームのみで使用できます。

アプリケーションが外部Cプロシージャをコールすると、Oracle DatabaseまたはOracle Listenerが外部プロシージャ・エージェントextprocを起動します。アプリケーションは、Oracle DatabaseまたはOracle Listenerが確立したネットワーク接続を使用し、次の情報をextprocに渡します。

- DLLまたは共有ライブラリの名前

- 外部プロシージャの名前

- 外部プロシージャのすべてのパラメータ

その後、extprocはDLLまたは共有ライブラリをロードし、外部プロシージャを実行し、外部プロシージャによってアプリケーションに戻された値を渡します。アプリケーションとextprocは、同じコンピュータ上に存在する必要があります。

extprocは、使用されているコール規格に準拠するライブラリ内でプロシージャをコールできます。コール規格の詳細は、「CALLING STANDARD」を参照してください。

注意:
外部プロシージャのデフォルト構成では、Oracle Databaseおよびextprocと動作するネットワーク・リスナーは不要になりました。Oracle Databaseによってextprocが直接起動されるため、Oracle Listenerが誤ってextprocを起動する危険性が解消されました。セキュリティを最大限にするため、このデフォルト構成をお薦めします。
次のいずれかを使用する場合、Oracle Listenerがextprocを起動するようにデフォルトの構成を変更する必要があります。

- マルチスレッドのextprocエージェント

- Windows上の共有モードのOracle Database

- 外部プロシージャを別のextprocエージェントにリダイレクトする、LIBRARY仕様のAGENT句またはPROCEDURE仕様のAGENT IN句

デフォルト構成を変更すると、追加のネットワーク構成が必要になります。

Cで作成された外部プロシージャ、またはCアプリケーションからコール可能な外部プロシージャを使用できるようにデータベースを設定するには、開発者またはデータベース管理者が次の手順を実行します。

1. Cプロシージャの定義

2. 環境の設定

3. DLLを識別する

4. 外部プロシージャを公開する

Cプロシージャの定義

次のプロトタイプのいずれかを使用し、Cプロシージャを定義します。

- Kernighan & Ritchieスタイル・プロトタイプの定義は次のとおりです。

void C_findRoot(x)
float x;
...

- 全角ではない数値データ型(float、short、charなど)以外のISO/ANSIプロトタイプの定義は次のとおりです。

void C_findRoot(double x)
...

- デフォルトの引数格上げによってサイズの変わらないその他のデータ型。
デフォルトの引数格上げによってサイズが変わる定義の例は次のとおりです。

void C_findRoot(float x)
...

環境の設定

外部プロシージャでデフォルト構成を使用する場合、Oracle Databaseはextprocを直接起動します。listener.oraおよびtnsnames.oraの構成を変更する必要はありません。次の構文を使用し、外部プロシージャが使用する環境変数をextproc.oraファイルに定義します(ファイルは、UNIXオペレーティング・システムでは$ORACLE_HOME/hs/adminに、WindowsではORACLE_HOME\hs\adminにあります)。

SET name=value (environment_variable_name value)

extprocがロードするDLLを制限するEXTPROC_DLLS環境変数を次のいずれかの値に設定します。

- NULLの場合、次のとおり設定します。

SET EXTPROC_DLLS=

デフォルトのこの設定では、extprocは、ディレクトリ$ORACLE_HOME/binまたは$ORACLE_HOME/libにあるDLLのみをロードします。

- ONLYの後にコロンで区切られた(Windowsシステムではセミコロンで区切られた)DLLをリストして指定する場合、次のとおり設定します。

SET EXTPROC_DLLS=ONLY:DLL1:DLL2

この設定では、extprocはDLL1およびDLL2という名のDLLのみロードします。この設定で最大のセキュリティが得られます。

- コロンで区切られた(Windowsシステムではセミコロンで区切られた)DLLのリストの場合、次のとおり設定します。

SET EXTPROC_DLLS=DLL1:DLL2

この設定では、extprocは、DLL1およびDLL2という名のDLL、およびディレクトリ$ORACLE_HOME/binまたは$ORACLE_HOME/libに存在するDLLをロードします。

- ANYの場合、次のとおり設定します。

SET EXTPROC_DLLS=ANY

この設定では、extprocはすべてのDLLをロードします。

外部プロシージャのデフォルト構成を変更し、extprocエージェントをOracleリスナーから起動するには、Cで作成された外部プロシージャまたはCアプリケーションからコール可能な外部プロシージャを使用できるよう、データベース構成を次のように設定します。

1. エージェント用の構成パラメータ(デフォルト名extproc)を構成ファイルtnsnames.oraおよびlistener.ora内で設定します。この作業により、データベース起動時に外部プロシージャ・エージェントextprocとの接続が確立されます。

2. 外部プロシージャ専用のリスナー・プロセスを開始します。
リスナーは、extprocに必要な環境変数(ORACLE_HOME、ORACLE_SIDおよびLD_LIBRARY_PATHなど)をいくつか設定します。また、リスナーがlistener.oraエントリのENVSセクションで固有の環境変数を定義すると、その環境変数はエージェント・プロセスに渡されます。それ以外は、エージェントに対してクリーンな環境を提供します。エージェント用に設定される環境変数は、クライアントおよびサーバー用に設定される環境変数から独立しています。したがって、エージェント・プロセス内で実行される外部プロシージャは、クライアントまたはサーバーのプロセス用に設定される環境変数を読み込むことはできません。

注意:
環境変数自体は標準Cプロシージャのsetenvおよびgetenvを使用してそれぞれ設定し、読み込むことができます。この方法で設定された環境変数は、エージェント・プロセス専用です。そのプロセス内で実行されるすべての関数で読み込めますが、同一ホスト上で実行されている他のプロセスで読み込むことはできません。

3. 外部プロシージャ用のエージェントを専用モード(デフォルト)で実行するか、マルチスレッド・モードで実行するかを決定します。専用モードでは、各セッションに対して専用エージェントが1つ起動されます。マルチスレッド・スレッドモードでは、単一のマルチスレッドextprocエージェントが起動されます。マルチスレッドextprocエージェントは、ユーザーごとに異なるスレッドを使用してコールを処理します。外部プロシージャをコールするユーザーが多いような構成では、マルチスレッドのextprocエージェントを使用してシステム・リソースを節約することをお薦めします。
エージェントを専用モードで実行する場合、エージェント・プロセスの構成はこれ以上必要ありません。

エージェントをマルチスレッド・モードで実行する場合、データベース管理者はエージェントが(マルチスレッドextprocエージェントとして)マルチスレッド・モードで起動されるようにデータベース・システムを構成する必要があります。この構成は、エージェント制御ユーティリティagtctlを使用して行います。たとえば、次のコマンドを使用してextprocを起動します。

agtctl startup extproc agent_sid

この例のagent_sidは、このextprocエージェントが処理するシステム識別子です。このシステム識別子のエントリは、通常、tnsnames.oraファイルにエントリとして追加されています。extproc管理でのagtctlの使用の詳細は、「マルチスレッドextprocエージェントの管理」を参照してください。

注意:

- マルチスレッドextprocエージェントを使用する場合、破損コール・スタックなどのエラーを避けるために、コールするライブラリはスレッド・セーフである必要があります。

- エージェント・プロセスを起動する、データベース・サーバー、エージェント・プロセスおよびリスナー・プロセスは、すべて同じホスト上に存在する必要があります。

- デフォルトでは、エージェント・プロセスはメイン・アプリケーションと同じデータベース・インスタンスで実行されます。信頼性が非常に重要な場合は、外部プロシージャ用のエージェント・プロセスを別のデータベース・インスタンス(同じホスト上)で実行すると、エージェントで問題が生じてもプライマリ・データベース・サーバーに影響を与えません。このようにするには、データベース・リンクを使用して別のデータベース・インスタンスを指定します。

図A-1に、マルチスレッドextprocエージェントのアーキテクチャを示します。

DLLを識別する

ここでのDLLとは、外部プロシージャを格納する動的ロードが可能な任意のオペレーティング・システム・ファイルです。

セキュリティ上の理由から、DLLへのアクセスはDBAが制御します。DBAは、CREATE LIBRARY文を使用して、DLLを表す別名ライブラリというスキーマ・オブジェクトを作成します。次に、許可されているユーザーの場合は、DBAが別名ライブラリに対するEXECUTE権限を付与します。このかわりに、DBAは、ユーザーにCREATE ANY LIBRARY権限を付与することもあり、この場合、ユーザーは、次の構文を使用して自分の別名ライブラリを作成できます。

CREATE LIBRARY [schema_name.]library_name
{IS | AS} 'file_path'
[AGENT 'agent_link'];

注意:
ANY権限は強力なので、軽率に付与するべきではありません。詳細は次を参照してください。

- ANYを含む、システム権限の管理の詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

- ユーザー・アカウントと権限のセキュリティのガイドラインは、『Oracle Databaseセキュリティ・ガイド』を参照してください。

DLLには、名前のみではなく、DLLへのフル・パスを指定することをお薦めします。次の例では、DLLであるutils.soを表す別名ライブラリc_utilsを作成します。

CREATE LIBRARY C_utils AS '/DLLs/utils.so';

DLLを柔軟に指定するために、表記規則${VAR_NAME}を使用してパスのルート部分を環境変数として指定し、その変数をlistener.oraエントリのENVSセクションに設定できます。

次の例では、agent_linkという名前で指定されるエージェントを使用して、ライブラリC_Utilsで外部プロシージャを実行します。

create or replace database link agent_link using 'agent_tns_alias';
create or replace library C_utils is
'${EP_LIB_HOME}/utils.so' agent 'agent_link';

環境変数EP_LIB_HOMEは、エージェントによって/usr/bin/dllなどのそのインスタンス用の適切なパスに展開されます。変数EP_LIB_HOMEは、エージェントがアクセスできるように、listener.oraファイル内に設定する必要があります。

セキュリティ上の理由から、デフォルト状態のextprocは、ディレクトリ$ORACLE_HOME/binまたは$ORACLE_HOME/libに存在するDLLのみをロードするようになっています。また、extprocに接続できるのは、同じシステムで実行されているOracle Databaseのクライアント・プロセスであるローカル・セッションのみです。

他のディレクトリからDLLをロードするには、環境変数EXTPROC_DLLSを設定する必要があります。この環境変数の値には、完全パスで修飾したDLL名をコロンで区切った(Windowsシステムではセミコロンで区切った)リストを指定します。次に例を示します。

EXTPROC_DLLS=/private1/home/johndoe/dll/myDll.so:/private1/home/johndoe/dll/newDll.so

extprocの環境変数はlistener.oraファイルのENVSパラメータから設定できますが、$ORACLE_HOME/hs/adminディレクトリにあるextprocの初期化ファイルextproc.oraの環境変数も設定できます。extproc.oraおよびlistener.oraのENVSパラメータの両方が使用される場合、extproc.oraで定義された環境変数が優先されます。EXTPROC機能の詳細は、Oracle Netのマニュアルを参照してください。

注意:
Windowsシステム上のextproc.oraでは、パスの各円記号に対してドライブ文字および二重円記号(\\)を使用して、パスを指定します。(各二重円記号内の最初の円記号は、エスケープ文字として機能します。)

外部プロシージャを公開する

外部Cプロシージャを作成してから、これをDLLに追加します。プロシージャがDLL内にある場合、「外部プロシージャの公開」で説明されるコール仕様のメカニズムを使用して、プロシージャを公開します。

外部プロシージャの公開

Oracle Databaseで使用できる外部プロシージャは、コール仕様で公開される外部プロシージャのみです。Javaクラス・メソッドまたは外部Cプロシージャの名前、パラメータ型および戻り型が、対応するSQLの要素にマップされます。これはPL/SQLストアド・プロシージャと同様に作成しますが、本体には宣言やBEGIN ENDブロックではなく、AS LANGUAGE句を記述します。

AS LANGUAGE句では、次の指定を行います。

- プロシージャの作成言語。

- Javaメソッド

- Javaメソッドのシグネチャ。

- Cプロシージャ

- DLLに対応するCプロシージャ用の別名ライブラリ。

- DLL内のCプロシージャの名前。

- パラメータの受渡し方法を指定するための様々なオプション。

- 異なるシステム上でプロシージャを実行するための、外部プロシージャ・エージェントextprocの名前を保持するパラメータ(ある場合)

プロシージャ、ファンクション、パッケージ仕様部、パッケージ本体、型仕様または型本体用の通常のCREATE OR REPLACE構文を使用して、宣言を開始します。

コール仕様は、名前宣言およびパラメータ宣言の後に指定します。構文は次のとおりです。

{IS | AS} LANGUAGE {C | JAVA}

これに続いて、次のいずれかを指定します。

NAME  java_string_literal_name

java_string_literal_nameは、Javaメソッドのシグネチャです。

{ LIBRARY library_name [ NAME c_string_literal_name ] |
[ NAME c_string_literal_name ] LIBRARY library_name }
[ AGENT IN ( argument [, argument]... ) ]
[ WITH CONTEXT ]
[ PARAMETERS (external_parameter[, external_parameter]...) ];

library_nameは別名ライブラリの名前で、c_string_literal_nameは外部Cプロシージャの名前です。external_parameterは次を意味します。

{  CONTEXT
| SELF [{TDO | property}]
| {parameter_name | RETURN} [property] [BY REFERENCE] [external_datatype]}

propertyは次を意味します。

{INDICATOR [{STRUCT | TDO}] | LENGTH | DURATION | MAXLEN | CHARSETID | CHARSETFORM}

注意:
Javaと異なり、CではSQL型は認識されません。このため、構文がより複雑になります。

内容は次のとおりです。

- Javaクラス・メソッド用のAS LANGUAGE句

- 外部Cプロシージャ用のAS LANGUAGE句

Javaクラス・メソッド用のAS LANGUAGE句

AS LANGUAGE句は、PL/SQLとJavaクラス・メソッドの間のインタフェースです。

外部Cプロシージャ用のAS LANGUAGE句

次の副次句は、PL/SQLに対して、外部Cプロシージャを検索する場所、そのプロシージャのコール方法、プロシージャに何を渡すかを指示します。

- LIBRARY

- NAME

- LANGUAGE

- CALLING STANDARD

- WITH CONTEXT

- PARAMETERS

- AGENT IN

これらの副次句のうちLIBRARYのみが必須です。

LIBRARY

ローカルの別名ライブラリを指定します。(リモート・ライブラリの指定にデータベース・リンクは使用できません)。ライブラリ名はPL/SQL識別子です。このため、名前を二重引用符で囲むと、名前の大/小文字が区別されます。(デフォルトでは、名前は大文字で格納されます)。別名ライブラリにはEXECUTE権限が必要です。

NAME

コール対象の外部Cプロシージャを指定します。プロシージャ名を二重引用符で囲むと、名前の大/小文字が区別されます。(デフォルトでは、名前は大文字で格納されます)。この副次句を省略すると、プロシージャ名はPL/SQLプロシージャ名を大文字で表したものがデフォルト設定されます。

注意:
LANGUAGEおよびCALLING STANDARDは、旧版のAS EXTERNAL句のみに適用されます。

LANGUAGE

外部プロシージャが作成されている3GLを指定します。この副次句を省略すると、言語名はCにデフォルト設定されます。

CALLING STANDARD

外部プロシージャをコンパイルしたコール規格を指定します。サポートされているコール規格はCです。この副次句を省略すると、コール規格はCにデフォルト設定されます。

WITH CONTEXT

コンテキスト・ポインタが外部プロシージャに渡されることを指定します。コンテキスト・データ構造体は外部プロシージャに対して不透明ですが、外部プロシージャによってコールされるサービス・プロシージャでは使用できます。

PARAMETERS

外部プロシージャに渡されるパラメータの位置およびデータ型を指定します。現在の長さや最大長などのパラメータ・プロパティや、パラメータの受渡し方法(値によるか参照によるか)も指定できます。

AGENT IN

このプロシージャを実行するエージェント・プロセスの名前を保持するパラメータを指定します。これは、外部プロシージャ・エージェントextprocが、複数のエージェント・プロセスを使用して実行される場合を想定して行います。これによって、1つの外部プロシージャのエージェント・プロセスにエラーが発生した場合の信頼性が保証されます。エージェント・プロセスの名前(データベース・リンクの名前に対応)を渡すことができ、またtnsnames.oraおよびlistener.oraが両方のインスタンス間で正しく設定されている場合、外部プロシージャが、もう一方のインスタンスでコールされます。両方のインスタンスは、同じホスト上に存在する必要があります。

この操作は、CREATE LIBRARY文のAGENT句の場合と同様です。AGENT INを使用して実行時の値を指定すると、柔軟性が向上します。

このようにエージェント名を指定すると、別名ライブラリで宣言されるエージェント名はいずれもオーバーライドされます。エージェント名が指定されていない場合は、extprocエージェントがコール側プログラムと同じインスタンス上でデフォルト設定されます。

Javaクラス・メソッドの発行

Javaクラスおよびそのメソッドは、RDBMSライブラリ・ユニットに格納されます。この中には、LOADJAVAユーティリティまたはSQL文CREATEJAVAを使用して、Javaソース、バイナリおよびリソースをロードできます。ライブラリ・ユニットは、たとえばCで作成されたDLLに類似していますが、DLLには複数のプロシージャを入れられるのに対して、ライブラリ・ユニットはJavaクラスと1対1で対応します。

NAME句文字列は、Javaメソッドを一意に識別します。PL/SQLのファンクションまたはプロシージャおよびJavaには対応するパラメータが必要です。Javaメソッドがパラメータをとらない場合は、空のパラメータ・リストを作成する必要があります。

JavaクラスをRDBMSにロードするとき、クラスはSQLに対して自動的には発行されません。これは、ほとんどのJavaクラスのメソッドは他のJavaクラスからのみコールされるか、該当するSQL型が存在しないパラメータをとるためです。

次に、引数の階乗を戻すJavaメソッド(J_calcFactorial)を発行する場合を考えてみます。

package myRoutines.math;
public class Factorial {
public static int J_calcFactorial (int n) {
if (n == 1) return 1;
else return n * J_calcFactorial(n - 1);
}
}

次のコール仕様では、SQL*Plusを使用して、JavaメソッドJ_calcFactorialをPL/SQLストアド・ファンクションplsToJavaFac_funcとして発行します。

CREATE OR REPLACE FUNCTION Plstojavafac_func (N NUMBER) RETURN NUMBER AS
LANGUAGE JAVA
NAME 'myRoutines.math.Factorial.J_calcFactorial(int) return int';

外部Cプロシージャの発行

次の例では、C関数Cdivisor_funcを外部関数として発行するplsCallsCdivisor_funcというPL/SQLスタンドアロン・ファンクションを作成します。

CREATE OR REPLACE FUNCTION Plscallscdivisor_func (
/* Find greatest common divisor of x and y: */
x     PLS_INTEGER,
y     PLS_INTEGER)
RETURN PLS_INTEGER
AS LANGUAGE C
LIBRARY C_utils
NAME "Cdivisor_func"; /* Quotation marks preserve case. */

コール仕様の位置

Javaクラス・メソッドおよび外部Cプロシージャはともに、次のいずれかの位置にコール仕様を指定できます。

- スタンドアロンのPL/SQLプロシージャ

- PL/SQLパッケージ仕様部

- PL/SQLパッケージ本体

- ADT仕様

- ADT本体

注意:
Oracle Databaseバージョン8.0では、AS EXTERNALによりコール仕様をパッケージ本体または型本体に指定できませんでした。

参照:

- PL/SQLからの外部プロシージャのコールの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- SQLのCALL文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

例:

- 例: PL/SQLパッケージ内へのコール仕様の配置

- 例: PL/SQLパッケージ本体内へのコール仕様の配置

- 例: ADT仕様内へのコール仕様の配置

- 例: ADT本体内へのコール仕様の配置

- 例: AUTHIDを指定したJava

- 例: オプションのAUTHIDを指定したC

- 例: パッケージ内でのコール仕様の混合使用

注意:
次のいくつかの例では、コール仕様の完全指定にAUTHID句およびSQL_NAME_RESOLVE句が必要な場合があります。

例: PL/SQLパッケージ内へのコール仕様の配置

CREATE OR REPLACE PACKAGE Demo_pack
AUTHID DEFINER
AS
PROCEDURE plsToC_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE C
NAME "C_demoExternal"
LIBRARY SomeLib
WITH CONTEXT
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE);
END;

例: PL/SQLパッケージ本体内へのコール仕様の配置

CREATE OR REPLACE PACKAGE Demo_pack
AUTHID CURRENT_USER
AS
PROCEDURE plsToC_demoExternal_proc(x PLS_INTEGER, y VARCHAR2, z DATE);
END;

CREATE OR REPLACE PACKAGE BODY Demo_pack
SQL_NAME_RESOLVE CURRENT_USER
AS
PROCEDURE plsToC_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE JAVA
NAME 'pkg1.class4.methodProc1(int,java.lang.String,java.sql.Date)';
END;

例: ADT仕様内へのコール仕様の配置

注意:
この項の例が機能するには、次のデータ構造を設定する必要があります(これには、権限CREATE ANY LIBRARYが必要です)。

CREATE OR REPLACE LIBRARY SOMELIB AS '/tmp/lib.so';

CREATE OR REPLACE TYPE Demo_typ
AUTHID DEFINER
AS OBJECT
(Attribute1   VARCHAR2(2000), SomeLib varchar2(20),
MEMBER PROCEDURE plsToC_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE C
NAME "C_demoExternal"
LIBRARY SomeLib
WITH CONTEXT
--  PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE)
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE, SELF)
);

例: ADT本体内へのコール仕様の配置

CREATE OR REPLACE TYPE Demo_typ
AUTHID CURRENT_USER
AS OBJECT
(attribute1 NUMBER,
MEMBER PROCEDURE plsToJ_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
);

CREATE OR REPLACE TYPE BODY Demo_typ
AS
MEMBER PROCEDURE plsToJ_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE JAVA
NAME 'pkg1.class4.J_demoExternal(int,java.lang.String,java.sql.Date)';
END;

例: AUTHIDを指定したJava

スタンドアロンPL/SQLプロシージャ内にJavaクラス・メソッドを発行する例を示します。

CREATE OR REPLACE PROCEDURE plsToJ_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AUTHID CURRENT_USER
AS LANGUAGE JAVA
NAME 'pkg1.class4.methodProc1(int,java.lang.String,java.sql.Date)';

例: オプションのAUTHIDを指定したC

スタンドアロンPL/SQLプログラム内にCプロシージャをAS EXTERNALとして発行する例を次に示します。AUTHID句はオプションです。これによって、Oracle Databaseリリース8.0の外部プロシージャとの互換性が保たれます。

CREATE OR REPLACE PROCEDURE plsToC_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS
EXTERNAL
LANGUAGE C
NAME "C_demoExternal"
LIBRARY SomeLib
WITH CONTEXT
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE);

例: パッケージ内でのコール仕様の混合使用

CREATE OR REPLACE PACKAGE Demo_pack
AUTHID DEFINER
AS
PROCEDURE plsToC_InBodyOld_proc (x PLS_INTEGER, y VARCHAR2, z DATE);
PROCEDURE plsToC_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE);
PROCEDURE plsToC_InBody_proc (x PLS_INTEGER, y VARCHAR2, z DATE);
PROCEDURE plsToJ_InBody_proc (x PLS_INTEGER, y VARCHAR2, z DATE);

PROCEDURE plsToJ_InSpec_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
IS LANGUAGE JAVA
NAME 'pkg1.class4.J_InSpec_meth(int,java.lang.String,java.sql.Date)';

PROCEDURE C_InSpec_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE C
NAME "C_demoExternal"
LIBRARY SomeLib
WITH CONTEXT
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE);
END;

CREATE OR REPLACE PACKAGE BODY Demo_pack
AS
PROCEDURE plsToC_InBodyOld_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS EXTERNAL
LANGUAGE C
NAME "C_InBodyOld"
LIBRARY SomeLib
WITH CONTEXT
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE);
PROCEDURE plsToC_demoExternal_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE C
NAME "C_demoExternal"
LIBRARY SomeLib
WITH CONTEXT
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE);

PROCEDURE plsToC_InBody_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
AS LANGUAGE C
NAME "C_InBody"
LIBRARY SomeLib
WITH CONTEXT
PARAMETERS(CONTEXT, x INT, y STRING, z OCIDATE);
PROCEDURE plsToJ_InBody_proc (x PLS_INTEGER, y VARCHAR2, z DATE)
IS LANGUAGE JAVA
NAME 'pkg1.class4.J_InBody_meth(int,java.lang.String,java.sql.Date)';
END;

コール仕様による外部Cプロシージャへのパラメータの受渡し

コール仕様によって、PL/SQLデータ型とCデータ型とのマッピングが可能になります。データ型マッピングの詳細は、「データ型の指定」を参照してください。

外部Cプロシージャへのパラメータの受渡しは、次のような理由で複雑になります。

- 使用可能なPL/SQLのセットが、Cデータ型のセットと1対1で対応していない。

- Cとは異なり、PL/SQLにはNULLかどうかというRDBMS概念が含まれる。このため、PL/SQLパラメータはNULLにできるが、CパラメータはNULLにできない。

- 外部プロシージャで、CHAR、LONG RAW、RAWおよびVARCHAR2パラメータの現在の長さまたは最大長が必要。

- 外部プロシージャで、CHAR、VARCHAR2およびCLOBパラメータに関するキャラクタ・セット情報が必要。

- PL/SQLで、外部プロシージャによって戻された値の現在の長さ、最大長またはNULL状態が必要。

注意:
C外部プロシージャに渡すことができるパラメータの最大数は128です。ただし、FLOAT型またはDOUBLE型のパラメータを値渡しする場合は、最大数は127以下になります。どのくらい減るかは、パラメータの個数およびオペレーティング・システムによって異なります。目安としては、値渡しされるFLOAT型またはDOUBLE型のパラメータ1つを2つ分として数えます。

内容は次のとおりです。

- データ型の指定

- 外部データ型のマッピング

- BY VALUEまたはBY REFERENCEによるパラメータの受渡し

- 仮パラメータの宣言

- デフォルトのデータ型マッピングのオーバーライド

- プロパティの指定

データ型の指定

パラメータは外部プロシージャに直接渡さないでください。かわりに、パラメータのPL/SQLデータ型を指定し、外部プロシージャを発行したPL/SQLプロシージャに渡します。PL/SQLデータ型は、デフォルトの外部データ型にマップされます(表14-1を参照)。

注意:
PL/SQLデータ型のBINARY_INTEGERとPLS_INTEGERは同一です。わかりやすくするため、このドキュメントではBINARY_INTEGERとPLS_INTEGERの両方をPLS_INTEGERとします。

表14-1 パラメータ・データ型のマッピング

PL/SQLデータ型

サポートされている外部データ型

デフォルトの外部データ型

BINARY_INTEGER
BOOLEAN
PLS_INTEGER

[UNSIGNED] CHAR
[UNSIGNED] SHORT
[UNSIGNED] INT
[UNSIGNED] LONG
SB1, SB2, SB4
UB1, UB2, UB4
SIZE_T

INT

NATURALFoot 1
NATURALNFootref 1
POSITIVEFootref 1
POSITIVENFootref 1
SIGNTYPEFootref 1

[UNSIGNED] CHAR
[UNSIGNED] SHORT
[UNSIGNED] INT
[UNSIGNED] LONG
SB1, SB2, SB4
UB1, UB2, UB4
SIZE_T

UNSIGNED INT

FLOAT
REAL

FLOAT

FLOAT

DOUBLE PRECISION

DOUBLE

DOUBLE

CHAR
CHARACTER
LONG
NCHAR
NVARCHAR2
ROWID
VARCHAR
VARCHAR2

STRING
OCISTRING

STRING

LONG RAW
RAW

RAW
OCIRAW

RAW

BFILE
BLOB
CLOB
NCLOB

OCILOBLOCATOR

OCILOBLOCATOR

NUMBER
DECFootref 1
DECIMALFootref 1
INTFootref 1
INTEGERFootref 1
NUMERICFootref 1
SMALLINTFootref 1

OCINUMBER

OCINUMBER

DATE

OCIDATE

OCIDATE

TIMESTAMP
TIMESTAMP WITH TIME ZONE
TIMESTAMP WITH LOCAL TIME ZONE

OCIDateTime

OCIDateTime

INTERVAL DAY TO SECOND
INTERVAL YEAR TO MONTH

OCIInterval

OCIInterval

composite object types: ADTs

dvoid

dvoid

composite object types: collections (varrays, nested tables)

OCICOLL

OCICOLL

脚注1 このPL/SQLデータ型は、コール仕様でAS EXTERNALを使用する場合にのみ準拠します。

外部データ型のマッピング

外部データ型はそれぞれCデータ型にマップされ、データ型変換が暗黙的に実行されます。外部データ型はそれぞれCデータ型にマップされ、データ型変換が暗黙的に実行されます。Cプロトタイプ・パラメータの宣言時のエラーを回避するには、表14-2を参照してください。この表には、特定の外部データ型およびPL/SQLパラメータ・モードに指定するCデータ型が示されています。たとえば、OUTパラメータの外部データ型がSTRING型の場合は、Cプロトタイプにはデータ型char *を指定します。

表14-2 外部データ型のマッピング

PL/SL型に対応する外部データ型

INモードまたはRETURNモードの場合、Cプロトタイプで指定

参照によるINモードまたは参照によるRETURNモードの場合、Cプロトタイプで指定

IN OUTモードまたはOUTモードの場合、Cプロトタイプで指定

CHAR

char

char *

char *

UNSIGNED CHAR

unsigned char

unsigned char *

unsigned char *

SHORT

short

short *

short *

UNSIGNED SHORT

unsigned short

unsigned short *

unsigned short *

INT

int

int *

int *

UNSIGNED INT

unsigned int

unsigned int *

unsigned int *

LONG

long

long *

long *

UNSIGNED LONG

unsigned long

unsigned long *

unsigned long *

CHAR

char

char *

char *

UNSIGNED CHAR

unsigned char

unsigned char *

unsigned char *

SHORT

short

short *

short *

UNSIGNED SHORT

unsigned short

unsigned short *

unsigned short *

INT

int

int *

int *

UNSIGNED INT

unsigned int

unsigned int *

unsigned int *

LONG

long

long *

long *

UNSIGNED LONG

unsigned long

unsigned long *

unsigned long *

SIZE_T

size_t

size_t *

size_t *

SB1

sb1

sb1 *

sb1 *

UB1

ub1

ub1 *

ub1 *

SB2

sb2

sb2 *

sb2 *

UB2

ub2

ub2 *

ub2 *

SB4

sb4

sb4 *

sb4 *

UB4

ub4

ub4 *

ub4 *

FLOAT

float

float *

float *

DOUBLE

double

double *

double *

STRING

char *

char *

char *

RAW

unsigned char *

unsigned char *

unsigned char *

OCILOBLOCATOR

OCILobLocator *

OCILobLocator **

OCILobLocator **

OCINUMBER

OCINumber *

OCINumber *

OCINumber *

OCISTRING

OCIString *

OCIString *

OCIString *

OCIRAW

OCIRaw *

OCIRaw *

OCIRaw *

OCIDATE

OCIDate *

OCIDate *

OCIDate *

OCICOLL

OCIColl * or OCIArray * or OCITable *

OCIColl **
or OCIArray **
or OCITable **

OCIColl ** or OCIArray ** or OCITable **

OCITYPE

OCIType *

OCIType *

OCIType *

TDO

OCIType *

OCIType *

OCIType *

ADT
(final types)

dvoid*

dvoid*

dvoid*

ADT (nonfinal types)

dvoid*

dvoid*

dvoid**

コンポジット・データ型は、自己記述型ではありません。記述は、型記述子オブジェクト(TDO)に格納されています。オブジェクトおよびオブジェクトのインジケータ構造体に事前定義のOCIデータ型はありませんが、Oracle DatabaseのObject Type Translator(OTT)によって生成されるデータ型を使用する必要があります。INDICATORおよびコンポジット・オブジェクトのオプションのTDO引数には、通常、Cデータ型のOCIType*があります。

REFおよびコレクション引数のOCICOLLはオプションで、完全性を保つためにのみ存在しています。REFまたはコレクション型を別のデータ型にマップすること、および別のデータ型をREFまたはコレクション型にマップすることはできません。

BY VALUEまたはBY REFERENCEによるパラメータの受渡し

BY VALUEを指定すると、スカラーINおよびRETURN引数が値渡しされます(デフォルト)。また、BY REFERENCEを指定すると、参照によって渡すことができます。

デフォルトまたはBY REFERENCEを指定した場合は、スカラーIN OUTおよびOUT引数が参照によって渡されます。IN OUTおよびOUT引数でのBY VALUEの指定はC用にはサポートされていません。BY REFERENCE/VALUE句の使用は、デフォルトで値渡しされる外部データ型に制限されます。これは、次の外部データ型のINおよびRETURN引数に適用されます。

[UNSIGNED] CHAR
[UNSIGNED] SHORT
[UNSIGNED] INT
[UNSIGNED] LONG
SIZE_T
SB1
SB2
SB4
UB1
UB2
UB4
FLOAT
DOUBLE

このリストに記載されていない外部データ型のINおよびRETURN引数、IN OUTおよびOUT引数は、すべて参照によって渡されます。

仮パラメータの宣言

一般に、外部プロシージャを発行するPL/SQLプロシージャは、次の例に示されているように、仮パラメータのリストを宣言します。

注意:
この項の例には、次のようなデータ構造を設定しないと機能しないものもあります。

CREATE LIBRARY MathLib AS '/tmp/math.so';

CREATE OR REPLACE FUNCTION Interp_func (
/* Find the value of y at x degrees using Lagrange interpolation: */
x    IN FLOAT,
y    IN FLOAT)
RETURN FLOAT AS
LANGUAGE C
NAME "Interp_func"
LIBRARY MathLib;

それぞれの仮パラメータ宣言では、名前、パラメータ・モードおよび(デフォルトの外部データ型にマップされる)PL/SQLデータ型が指定されます。これが、外部プロシージャが必要とするすべての情報である可能性があります。これがすべてではない場合は、PARAMETERS句を使用して追加情報を指定できます。

- デフォルト以外の外部データ型

- パラメータの現在の長さまたは最大長

- パラメータのNULL/NOT NULLインジケータ

- キャラクタ・セットのIDおよび形式

- リスト内のパラメータの位置

- INパラメータを渡す方法(値による方法または参照による方法)

PARAMETERS句を使用する場合、次のことを認識しておく必要があります。

- 各仮パラメータには、PARAMETERS句に対応するパラメータが必要です。

- WITH CONTEXT句を含める場合は、パラメータ・リスト内でのコンテキスト・ポインタの位置を示すパラメータCONTEXTを指定する必要があります。

- 外部プロシージャがファンクションの場合は、パラメータRETURNを指定できますが、末尾に指定する必要があります。RETURNを指定しないときは、デフォルトの外部型が使用されます。

デフォルトのデータ型マッピングのオーバーライド

PARAMETERS句を使用して、デフォルトのデータ型マッピングをオーバーライドすることができる場合もあります。たとえば、外部データ型INTから外部データ型CHARにPL/SQLデータ型のBOOLEANをマッピングしなおすことができます。

プロパティの指定

PARAMETERS句は、PL/SQLの仮パラメータおよびファンクション結果に関する追加情報を外部プロシージャに渡すために使用することもできます。これは、次のプロパティを1つ以上指定して行います。

INDICATOR [{STRUCT | TDO}]
LENGTH
DURATION
MAXLEN
CHARSETID
CHARSETFORM
SELF

表14-3に、使用可能外部データ型とデフォルト外部データ型、PL/SQLデータ型および特定のプロパティに使用できるPL/SQLパラメータ・モードを示します。(CからPL/SQLにデータを戻す場合に指定する)MAXLENは、INパラメータには適用できません。

表14-3 プロパティおよびデータ型

プロパティ

使用可能外部データ型(C)

デフォルトの外部データ型(C)

使用可能PL/SQLデータ型

使用可能PL/SQLモード

デフォルトのPL/SQL受渡し方法

INDICATOR

SHORT

SHORT

all scalars

IN
IN OUT
OUT
RETURN

BY VALUE
BY REFERENCE
BY REFERENCE
BY REFERENCE

LENGTH

[UNSIGNED] SHORT
[UNSIGNED] INT
[UNSIGNED] LONG

INT

CHAR
LONG RAW
RAW
VARCHAR2

IN
IN OUT
OUT
RETURN

BY VALUE
BY REFERENCE
BY REFERENCE
BY REFERENCE

MAXLEN

[UNSIGNED] SHORT
[UNSIGNED] INT
[UNSIGNED] LONG

INT

CHAR
LONG RAW
RAW
VARCHAR2

IN OUT
OUT
RETURN

BY REFERENCE
BY REFERENCE
BY REFERENCE

CHARSETID
CHARSETFORM

UNSIGNED SHORT
UNSIGNED INT
UNSIGNED LONG

UNSIGNED INT

CHAR
CLOB
VARCHAR2

IN
IN OUT
OUT
RETURN

BY VALUE
BY REFERENCE
BY REFERENCE
BY REFERENCE

次の例では、PARAMETERS句はPL/SQLの仮パラメータおよびファンクション結果のプロパティを指定します。

CREATE OR REPLACE FUNCTION plsToCparse_func  (
x   IN PLS_INTEGER,
Y   IN OUT CHAR)
RETURN CHAR AS LANGUAGE C
LIBRARY c_utils
NAME "C_parse"
PARAMETERS (
x,            -- stores value of x
x INDICATOR,  -- stores null status of x
y,            -- stores value of y
y LENGTH,     -- stores current length of y
y MAXLEN,     -- stores maximum length of y
RETURN INDICATOR,
RETURN);

このPARAMETERS句を使用すると、Cプロトタイプは次のようになります。

char  *C_parse( int x, short x_ind, char *y, int *y_len, int *y_maxlen,
short *retind );

Cプロトタイプ内の追加パラメータは、INDICATOR(x用)、LENGTH(y用)およびMAXLEN(y用)の他に、PARAMETERS句のファンクション結果のINDICATORにも対応します。パラメータRETURNは結果値を格納し、C関数識別子に対応します。

内容は次のとおりです。

- INDICATOR

- LENGTHおよびMAXLEN

- CHARSETIDおよびCHARSETFORM

- パラメータの再配置

- SELF

- BY REFERENCE

- WITH CONTEXT

- 言語間のパラメータ・モードのマッピング

INDICATOR

INDICATORは、別のパラメータがNULLかどうかを示す値を持つパラメータです。PL/SQLでは、RDBMSにおけるNULLかどうかという概念が言語に組み込まれているため、インジケータは必要ありません。ただし、外部プロシージャでは、パラメータまたはファンクション結果がNULLかどうかを認識することが必要な場合があります。また、外部プロシージャでは、戻り値が実際にNULLでありそれに応じた処理が必要であることをサーバーに指示する必要がある場合もあります。

このような場合は、プロパティINDICATORを使用して、インジケータを仮パラメータに関連付けることができます。PL/SQLプロシージャがファンクションの場合は、前述のようにインジケータをファンクション結果に関連付けることもできます。

インジケータの値を調べるには、定数OCI_IND_NULLおよびOCI_IND_NOTNULLを使用できます。インジケータがOCI_IND_NULLと等しい場合は、関連付けられているパラメータまたはファンクション結果はNULLです。インジケータがOCI_IND_NOTNULLと等しい場合は、関連付けられているパラメータまたはファンクション結果はNULLではありません。

INパラメータは読込み専用ですが、この場合、INDICATORは(BY REFERENCEを指定しないかぎり)値渡しされ、(BY REFERENCEを指定しても)読込み専用です。OUT、IN OUTおよびRETURNパラメータの場合、INDICATORはデフォルトで参照によって渡されます。

INDICATORにはSTRUCTオプションまたはTDOオプションを指定することもできます。INDICATORをオブジェクトのプロパティとして指定することはサポートされていないため、また、オブジェクトの引数にはINDICATORスカラーのかわりに完全なインジケータ構造体があるため、STRUCTオプションを使用して指定する必要があります。コンポジット・オブジェクトおよびコレクションには、型記述子オブジェクト(TDO)を使用する必要があります。

LENGTHおよびMAXLEN

PL/SQLでは、RAWパラメータまたは文字列パラメータの長さを示す標準的な方法はありません。ただし、このようなパラメータの長さの受渡しを外部プロシージャとの間で行う必要がある場合が数多くあります。プロパティLENGTHおよびMAXLENを使用すると、仮パラメータの現在の長さおよび最大長を格納するパラメータを指定できます。

注意:
型がRAWまたはLONG RAWのパラメータの場合は、プロパティLENGTHを使用してください。また、そのパラメータがIN OUTおよびNULLか、またはOUTおよびNULLの場合は、対応するCパラメータを長さ0(ゼロ)に設定してください。

INパラメータの場合は、LENGTHは(BY REFERENCEを指定しないかぎり)値渡しされ、読込み専用です。OUT、IN OUTおよびRETURNパラメータの場合は、LENGTHはデフォルトで参照によって渡されます。

前述のように、MAXLENはINパラメータには適用されません。OUT、IN OUTおよびRETURNパラメータの場合、MAXLENは参照によって渡され、読込み専用です。

CHARSETIDおよびCHARSETFORM

Oracle Databaseではグローバリゼーション・サポートを提供していますが、これを使用すると、シングルバイトおよびマルチバイトの文字データを処理し、キャラクタ・セット間で変換を行うことができます。また、アプリケーションを異なる言語環境で実行することもできます。

デフォルトでは、サーバーおよびエージェントが同じ$ORACLE_HOME値を使用する場合、エージェントはサーバー(ALTER SESSION文で指定した設定を含む)と同一のグローバリゼーション・サポート設定を使用します。

エージェントが別の$ORACLE_HOME(2つの異なる別名およびシンボリック・リンクによって同じ場所が指定されている場合でも)で実行されている場合、キャラクタ・セット以外はサーバーと同じグローバリゼーション・サポート設定が使用されます。エージェント用のデフォルト・キャラクタ・セットはエージェントの環境設定NLS_LANGおよびNLS_NCHARによって定義されます。

プロパティCHARSETIDおよびCHARSETFORMでは、渡された文字データの生成元である、デフォルト以外のキャラクタ・セットが識別されます。CHAR、CLOBおよびVARCHAR2型パラメータにより、CHARSETIDおよびCHARSETFORMを使用してキャラクタ・セットのIDおよび形式を外部プロシージャに渡すことができます。

INパラメータの場合、CHARSETIDおよびCHARSETFORMは(BY REFERENCEを指定しないかぎり)値渡しされ、(BY REFERENCEを指定した場合でも)読込み専用です。OUT、IN OUTおよびRETURNパラメータの場合、CHARSETIDおよびCHARSETFORMは参照によって渡され、読込み専用です。

これらのプロパティのOCI属性名は、OCI_ATTR_CHARSET_IDおよびOCI_ATTR_CHARSET_FORMです。

参照:

- OCI_ATTR_CHARSET_IDとOCI_ATTR_CHARSET_FORMの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

- OCIで各国語データを使用する場合の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。

パラメータの再配置

外部プロシージャの仮パラメータは、それぞれPARAMETERS句の中に対応するパラメータが必要です。PL/SQLではパラメータを位置ではなく名前によって対応付けるため、対応するパラメータの位置は異なる可能性があります。ただし、PARAMETERS句および外部プロシージャのためのCプロトタイプでは、同数のパラメータが同じ順序で必要です。

SELF

SELFは、オブジェクト型のメンバーであるプロシージャに常に存在する引数で、オブジェクトのインスタンスそのものです。ほとんどの場合、この引数は暗黙的で、PL/SQLプロシージャの引数リストには含まれていません。ただし、SELFは、PARAMETERS句の引数として明示的に指定する必要があります。

たとえば、ユーザーが、個人の名前および生年月日で構成されるPersonオブジェクトを作成し、さらに、このオブジェクト型の表を作成するとします。ユーザーは、後でこの表の各Personの年令を判断する必要があるとします。

SQL*Plusでは、Personオブジェクト型は次のように作成できます。

CREATE OR REPLACE TYPE Person1_typ AS OBJECT (
Name_     VARCHAR2(30),
B_date    DATE,
MEMBER FUNCTION calcAge_func RETURN NUMBER
);
/

通常、メンバー関数はPL/SQLで実装しますが、この例では外部プロシージャとなっています。このメンバー関数の本文を次のように宣言します。

CREATE OR REPLACE TYPE BODY Person1_typ AS
MEMBER FUNCTION calcAge_func RETURN NUMBER
AS LANGUAGE C
NAME "age"
LIBRARY agelib
WITH CONTEXT
PARAMETERS (
CONTEXT,
SELF,
SELF INDICATOR STRUCT,
SELF TDO,
RETURN INDICATOR
);
END;
/

calcAge_funcメンバー関数は引数をとらず、数値を戻すのみです。メンバー関数は、常に、対応付けられているオブジェクト型のインスタンスに対してコールされます。オブジェクト・インスタンス自体は、常にメンバー関数の暗黙的な引数になります。暗黙的な引数を参照するには、SELFキーワードを使用します。これは、PARAMETERS句の中でSELFへの参照をサポートすることによって、外部プロシージャ構文内に組み込まれています。

対応表が作成され移入されます。

CREATE TABLE Person_tab OF Person1_typ;

INSERT INTO Person_tab
VALUES ('BOB', TO_DATE('14-MAY-85'));

INSERT INTO Person_tab
VALUES ('JOHN', TO_DATE('22-DEC-71'));

最後に、この表から対象の情報を取得します。

SELECT p.name, p.b_date, p.calcAge_func() FROM Person_tab p;

NAME                           B_DATE    P.CALCAGE_
------------------------------ --------- ----------
BOB                            14-MAY-85          0
JOHN                           22-DEC-71          0

外部メンバー関数と、Object-Type-Translator(OTT)によって生成される構造体の定義を実装するCコードを次に示します。

#include <oci.h>

struct PERSON
{
OCIString   *NAME;
OCIDate      B_DATE;
};
typedef struct PERSON PERSON;

struct PERSON_ind
{
OCIInd    _atomic;
OCIInd    NAME;
OCIInd    B_DATE;
};
typedef struct PERSON_ind PERSON_ind;

OCINumber *age (ctx, person_obj, person_obj_ind, tdo, ret_ind)
OCIExtProcContext *ctx;
PERSON         *person_obj;
PERSON_ind     *person_obj_ind;
OCIType        *tdo;
OCIInd         *ret_ind;
{
sword      err;
text       errbuf[512];
OCIEnv    *envh;
OCISvcCtx *svch;
OCIError  *errh;
OCINumber *age;
int        inum = 0;
sword      status;

/* get OCI Environment */
err = OCIExtProcGetEnv( ctx, &envh, &svch, &errh );

/* initialize return age to 0 */
age = (OCINumber *)OCIExtProcAllocCallMemory(ctx, sizeof(OCINumber));
status = OCINumberFromInt(errh, &inum, sizeof(inum), OCI_NUMBER_SIGNED,
age);
if (status != OCI_SUCCESS)
{
OCIExtProcRaiseExcp(ctx, (int)1476);
return (age);
}

/* return NULL if the person object is null or the birthdate is null */
if ( person_obj_ind->_atomic == OCI_IND_NULL ||
person_obj_ind->B_DATE  == OCI_IND_NULL )
{
*ret_ind = OCI_IND_NULL;
return (age);
}

/* The actual implementation to calculate the age is left to the reader,
but an easy way of doing this is a callback of the form:
select trunc(months_between(sysdate, person_obj->b_date) / 12)
from DUAL;
*/
*ret_ind = OCI_IND_NOTNULL;
return (age);
}

BY REFERENCE

Cでは、INスカラー・パラメータは値渡しされる(パラメータの値が渡される)か、参照によって渡す(値へのポインタが渡される)ことができます。スカラーを指すポインタが外部プロシージャで必要な場合は、BY REFERENCE句を指定し、参照によってパラメータを渡します。

CREATE OR REPLACE PROCEDURE findRoot_proc (
x IN DOUBLE PRECISION)
AS LANGUAGE C
LIBRARY c_utils
NAME "C_findRoot"
PARAMETERS (
x BY REFERENCE);

この場合、Cプロトタイプは次のように指定します。

void C_findRoot(double *x);

デフォルト(PARAMETERS句がない場合に使用)は次のように指定します。

void C_findRoot(double x);

WITH CONTEXT

WITH CONTEXT句を含めることによって、外部プロシージャで、パラメータ、例外、メモリー割当ておよびユーザー環境に関する情報にアクセスできるようになります。WITH CONTEXT句は、コンテキスト・ポインタが外部プロシージャに渡されることを指定します。たとえば、次のPL/SQLファンクションを作成するとします。

CREATE OR REPLACE FUNCTION getNum_func (
x IN REAL)
RETURN PLS_INTEGER AS LANGUAGE C
LIBRARY c_utils
NAME "C_getNum"
WITH CONTEXT
PARAMETERS (
CONTEXT,
x BY REFERENCE,
RETURN INDICATOR);

Cプロトタイプは次のとおりです。

int C_getNum(
OCIExtProcContext *with_context,
float *x,
short *retind);

コンテキスト・データ構造体は外部プロシージャに対して不透明ですが、外部プロシージャによってコールされるサービス・プロシージャでは使用できます。

PARAMETERS句も含める場合は、パラメータ・リスト内でのコンテキスト・ポインタの位置を示すパラメータCONTEXTを指定する必要があります。PARAMETERS句を省略すると、コンテキスト・ポインタは外部プロシージャに渡される最初のパラメータです。

言語間のパラメータ・モードのマッピング

PL/SQLは、IN、IN OUTおよびOUTパラメータ・モード、および値を戻すプロシージャのRETURN句をサポートします。

CALL文による外部プロシージャの実行

これで、Javaクラス・メソッドまたは外部Cプロシージャが発行されました。次は、これをコールします。

外部プロシージャは直接コールしないでください。かわりに、CALL文を使用して、外部プロシージャを発行したPL/SQLプロシージャをコールしてください。「CALL文の構文」を参照してください。

このようなコールは、通常のPL/SQLプロシージャに対するコールと同じようにコーディングして、次のような場所で利用できます。

- 無名ブロック

- スタンドアロンおよびパッケージ・プロシージャ

- オブジェクト型のメソッド

- データベース・トリガー

- SQL文(パッケージ関数のみへのコール)。

サーバー側またはクライアント側(たとえば、Oracle Formsのようなツール内)で実行されるPL/SQLブロックまたはプロシージャは、外部プロシージャをコールできます。サーバー側では、外部プロシージャは別のプロセスのアドレス空間内で実行されるため、データベースが保護されます。図14-1に、Oracle Databaseと外部プロシージャ間の処理を示します。

図14-1 Oracle Databaseと外部プロシージャ

内容は次のとおりです。

- 外部プロシージャの事前条件

- CALL文の構文

- Javaクラス・メソッドのコール

- 外部Cプロシージャのコール

外部プロシージャの事前条件

外部プロシージャをコールする前に、実行環境に存在する権限、許可およびシノニムを考慮する必要があります。

内容は次のとおりです。

- 外部プロシージャの権限

- 許可の管理

- 外部プロシージャのシノニムの作成

外部プロシージャの権限

外部プロシージャがCALL仕様経由でコールされるとき、プロシージャは実行者権限ではなく定義者権限によって実行されます。

実行者権限で実行されるプログラムは、特定のスキーマには限定されません。コール側のサイトで実行され、コールした側の可視性と許可でデータベース項目(表やビューなど)にアクセスします。一方、定義者権限で実行されるプログラムでは、プログラムが定義されているスキーマに限定されます。このプログラムは定義を行う側で、サイトの定義者のスキーマ内の定義サイトで実行され、定義者の可視性および許可でデータベース項目にアクセスします。

許可の管理

外部プロシージャをコールするには、ユーザーはコール仕様に対するEXECUTE権限が必要です。この権限を付与するには、SQL文GRANTを使用します(『Oracle Database SQL言語リファレンス』を参照)。たとえば、この文により、ユーザーjohndoeはコール仕様がplsToJ_demoExternal_procである外部プロシージャをコールできます。

GRANT EXECUTE ON plsToJ_demoExternal_proc TO johndoe;

プロシージャをコールする必要があるユーザーにのみ、コール仕様に対するEXECUTE権限を付与します。

外部プロシージャのシノニムの作成

開発者またはDBAは、便宜上、CREATE PUBLIC SYNONYM文を使用して外部プロシージャのシノニムを作成できます。次の例では、すべてのユーザーがアクセス可能なパブリック・シノニムをDBAが作成します。PUBLICを指定しない場合、シノニムはプライベートになり、そのスキーマ内以外ではアクセスできません。

CREATE PUBLIC SYNONYM Rfac FOR johndoe.RecursiveFactorial;

CALL文の構文

SQLのCALL文から外部プロシージャをコールします。CALL文はSQL*Plusから対話形式で実行できます。構文は次のとおりです。

CALL [schema.][{object_type_name | package_name}]procedure_name[@dblink_name]
[(parameter_list)] [INTO :host_variable][INDICATOR][:indicator_variable];

これは、SELECT myproc(...) FROM DUALという形式のSQL文を使用してプロシージャmyprocを実行することと基本的には同じです。ただし、この場合は、SELECTの実行に関連するオーバーヘッドが発生しません。

たとえば、この章で発行したplsToC_demoExternal_procを動的SQLを使用してコールする無名PL/SQLブロックを次に示します。PL/SQLは、外部CプロシージャC_demoExternal_procに3つのパラメータを渡します。

DECLARE
xx NUMBER(4);
yy VARCHAR2(10);
zz DATE;
BEGIN
EXECUTE IMMEDIATE
'CALL plsToC_demoExternal_proc(:xxx, :yyy, :zzz)' USING xx,yy,zz;
END;

CALL文のセマンティクスは、同等のBEGIN ENDブロックと同じです。

注意:
CALLは、単独でPL/SQLのBEGIN END ブロックに入れることのできない唯一のSQL文です。これは、BEGIN ENDブロック内でのEXECUTE IMMEDIATE 文の一部に使用できます。

Javaクラス・メソッドのコール

以前に発行されたJ_calcFactorialクラス・メソッドをコールする方法は次のとおりです。

1. 次のように、SQL*Plusのホスト変数を2つ宣言して初期化します。

VARIABLE x NUMBER
VARIABLE y NUMBER
EXECUTE :x := 5;

2. J_calcFactorialをコールします。

CALL J_calcFactorial(:x) INTO :y;
PRINT y

結果:

Y
------
120

外部Cプロシージャのコール

外部Cプロシージャをコールするには、PL/SQLが適切なDLLパスを検出する必要があります。PL/SQLエンジンは、プロシージャ宣言のAS LANGUAGE句からのライブラリ別名に基づいて、パスをデータ・ディクショナリから取得します。

次に、PL/SQLはリスナー・プロセスに警告を出し、リスナー・プロセスがセッション固有のエージェントを起動します。デフォルトでは、このエージェントをextprocといいますが、listener.oraファイルで別の名前で指定できます。リスナーは接続をエージェントに渡し、PL/SQLはDLLの名前、外部プロシージャの名前およびパラメータをエージェントに渡します。

次に、エージェントはDLLをロードし、外部プロシージャを実行します。また、エージェントは(例外を呼び出すなどの)サービス・コールおよびOracle Databaseへのコールバックも処理します。最後に、エージェントは、外部プロシージャによって戻された値をPL/SQLに渡します。

注意:
DLLのキャッシュはいくらか発生しますが、DLLはキャッシュ内に残らない可能性があります。したがって、グローバル変数はDLLには格納しないでください。

外部プロシージャが完了した後、エージェントはOracle Databaseセッションの終わりまでアクティブなまま残ります。ログオフするとエージェントが停止されます。この結果、何度コールしても、エージェントを起動するのは1回で済みますが、演算によるメリットがコールのコストを上回るときにのみ外部プロシージャをコールするようにします。

ここでは、この章で発行したPL/SQLファンクションplsCallsCdivisor_funcを無名ブロックからコールします。PL/SQLは整数パラメータを2つ外部関数Cdivisor_funcに渡し、この関数が最大公約数を戻します。

DECLARE
g    PLS_INTEGER;
a    PLS_INTEGER;
b    PLS_INTEGER;
CALL plsCallsCdivisor_func(a, b);
IF g IN (2,4,8) THEN ...

複数言語のプログラム・エラーおよび例外処理

AS EXTERNALコール仕様がTYPE仕様部またはPACKAGE仕様部で検出された場合、PL/SQLコンパイラはコンパイル時例外を呼び出します。

Cプログラムでは、OCIExtproc関数を使用して例外を呼び出すことができます。

外部Cプロシージャでのサービス・ルーチンの使用

サービス・ルーチンが外部プロシージャからコールされると、サービス・ルーチンは例外を呼び出し、メモリーを割り当て、サーバーへのコールバック用のOCIハンドルをコールします。サービス・ルーチンを使用するには、WITH CONTEXT句を指定する必要があります。WITH CONTEXT句を使用すると、コンテキスト構造体を外部プロシージャに渡すことができます。コンテキスト構造体は、ヘッダー・ファイルociextp.hの中に次のように宣言されています。

typedef struct OCIExtProcContext OCIExtProcContext;

注意:
ociextp.hは、LinuxおよびUNIXでは$ORACLE_HOME/plsql/publicにあります。

サービス・プロシージャ:

- OCIExtProcAllocCallMemory

- OCIExtProcRaiseExcp

- OCIExtProcRaiseExcpWithMsg

OCIExtProcAllocCallMemory

このサービス・ルーチンは、外部プロシージャ・コールの間、nバイトのメモリーを割り当てます。この関数によって割り当てられるメモリーは、PL/SQLに制御が戻った直後に自動的に解放されます。

注意:
外部プロシージャでは、このサービス・ルーチンによって割り当てられたメモリーが自動的に処理されるため、C関数のfreeをコールしないでください。

この関数のCプロトタイプは、次のとおりです。

dvoid *OCIExtProcAllocCallMemory(
OCIExtProcContext *with_context,
size_t amount);

パラメータwith_contextおよびamountは、それぞれ、コンテキスト・ポインタと割り当てられるバイト数です。この関数は、割り当てられたメモリーを指す型が未定のポインタを戻します。戻り値が0(ゼロ)の場合は、失敗を示します。

SQL*Plusで、外部関数plsToC_concat_funcを次のように発行するとします。

CREATE OR REPLACE FUNCTION plsToC_concat_func (
str1 IN VARCHAR2,
str2 IN VARCHAR2)
RETURN VARCHAR2 AS LANGUAGE C
NAME "concat"
LIBRARY stringlib
WITH CONTEXT
PARAMETERS (
CONTEXT,
str1   STRING,
str1   INDICATOR short,
str2   STRING,
str2   INDICATOR short,
RETURN INDICATOR short,
RETURN LENGTH short,
RETURN STRING);

C_concatは、コールされたときに2つの文字列を連結し、結果を戻します。

select plsToC_concat_func('hello ', 'world') from DUAL;
PLSTOC_CONCAT_FUNC('HELLO','WORLD')
-----------------------------------------------------------------------------
hello world

いずれの文字列もNULLの場合は、結果もNULLになります。次の例で示されるように、C_concatはOCIExtProcAllocCallMemoryを使用して結果文字列のメモリーを割り当てます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oci.h>
#include <ociextp.h>

char *concat(ctx, str1, str1_i, str2, str2_i, ret_i, ret_l)
OCIExtProcContext *ctx;
char   *str1;
short  str1_i;
char   *str2;
short  str2_i;
short  *ret_i;
short  *ret_l;
{
char *tmp;
short len;
/* Check for null inputs. */
if ((str1_i == OCI_IND_NULL) || (str2_i == OCI_IND_NULL))
{
*ret_i = (short)OCI_IND_NULL;
/* PL/SQL has no notion of a NULL ptr, so return a zero-byte string. */
tmp = OCIExtProcAllocCallMemory(ctx, 1);
tmp[0] = '\0';
return(tmp);
}
/* Allocate memory for result string, including NULL terminator. */
len = strlen(str1) + strlen(str2);
tmp = OCIExtProcAllocCallMemory(ctx, len + 1);

strcpy(tmp, str1);
strcat(tmp, str2);

/* Set NULL indicator and length. */
*ret_i = (short)OCI_IND_NOTNULL;
*ret_l = len;
/* Return pointer, which PL/SQL frees later. */
return(tmp);
}

#ifdef LATER
static void checkerr (/*_ OCIError *errhp, sword status _*/);

void checkerr(errhp, status)
OCIError *errhp;
sword status;
{
text errbuf[512];
sb4 errcode = 0;

switch (status)
{
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
(void) printf("Error - OCI_SUCCESS_WITH_INFO\n");
break;
case OCI_NEED_DATA:
(void) printf("Error - OCI_NEED_DATA\n");
break;
case OCI_NO_DATA:
(void) printf("Error - OCI_NODATA\n");
break;
case OCI_ERROR:
(void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode,
errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
(void) printf("Error - %.*s\n", 512, errbuf);
break;
case OCI_INVALID_HANDLE:
(void) printf("Error - OCI_INVALID_HANDLE\n");
break;
case OCI_STILL_EXECUTING:
(void) printf("Error - OCI_STILL_EXECUTE\n");
break;
case OCI_CONTINUE:
(void) printf("Error - OCI_CONTINUE\n");
break;
default:
break;
}
}

char *concat(ctx, str1, str1_i, str2, str2_i, ret_i, ret_l)
OCIExtProcContext *ctx;
char   *str1;
short  str1_i;
char   *str2;
short  str2_i;
short  *ret_i;
short  *ret_l;
{
char *tmp;
short len;
/* Check for null inputs. */
if ((str1_i == OCI_IND_NULL) || (str2_i == OCI_IND_NULL))
{
*ret_i = (short)OCI_IND_NULL;
/* PL/SQL has no notion of a NULL ptr, so return a zero-byte string. */
tmp = OCIExtProcAllocCallMemory(ctx, 1);
tmp[0] = '\0';
return(tmp);
}
/* Allocate memory for result string, including NULL terminator. */
len = strlen(str1) + strlen(str2);
tmp = OCIExtProcAllocCallMemory(ctx, len + 1);

strcpy(tmp, str1);
strcat(tmp, str2);

/* Set NULL indicator and length. */
*ret_i = (short)OCI_IND_NOTNULL;
*ret_l = len;
/* Return pointer, which PL/SQL frees later. */
return(tmp);
}

/*======================================================================*/
int main(char *argv, int argc)
{
OCIExtProcContext *ctx;
char           *str1;
short          str1_i;
char           *str2;
short          str2_i;
short          *ret_i;
short          *ret_l;
/* OCI Handles */
OCIEnv        *envhp;
OCIServer     *srvhp;
OCISvcCtx     *svchp;
OCIError      *errhp;
OCISession    *authp;
OCIStmt       *stmthp;
OCILobLocator *clob, *blob;
OCILobLocator *Lob_loc;

/* Initialize and Logon */
(void) OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0,
(dvoid * (*)(dvoid *, size_t)) 0,
(dvoid * (*)(dvoid *, dvoid *, size_t))0,
(void (*)(dvoid *, dvoid *)) 0 );

(void) OCIEnvInit( (OCIEnv **) &envhp,
OCI_DEFAULT, (size_t) 0,
(dvoid **) 0 );

(void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR,
(size_t) 0, (dvoid **) 0);

/* Server contexts */
(void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,
(size_t) 0, (dvoid **) 0);

/* Service context */
(void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,
(size_t) 0, (dvoid **) 0);

/* Attach to Oracle Database */
(void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0);

/* Set attribute server context in the service context */
(void) OCIAttrSet ((dvoid *) svchp, OCI_HTYPE_SVCCTX,
(dvoid *)srvhp, (ub4) 0,
OCI_ATTR_SERVER, (OCIError *) errhp);

(void) OCIHandleAlloc((dvoid *) envhp,
(dvoid **)&authp, (ub4) OCI_HTYPE_SESSION,
(size_t) 0, (dvoid **) 0);

(void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,
(dvoid *) "samp", (ub4)4,
(ub4) OCI_ATTR_USERNAME, errhp);

(void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,
(dvoid *) "password", (ub4) 4,
(ub4) OCI_ATTR_PASSWORD, errhp);

/* Begin a User Session */
checkerr(errhp, OCISessionBegin ( svchp,  errhp, authp, OCI_CRED_RDBMS,
(ub4) OCI_DEFAULT));

(void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX,
(dvoid *) authp, (ub4) 0,
(ub4) OCI_ATTR_SESSION, errhp);

/* -----------------------User Logged In------------------------------*/
printf ("user logged in \n");

/* allocate a statement handle */
checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp,
OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0));

checkerr(errhp, OCIDescriptorAlloc((dvoid *)envhp, (dvoid **) &Lob_loc,
(ub4) OCI_DTYPE_LOB,
(size_t) 0, (dvoid **) 0));

/* ------- subprogram called  here-----------------------*/
printf ("calling concat...\n");
concat(ctx, str1, str1_i, str2, str2_i, ret_i, ret_l);

return 0;
}

#endif

OCIExtProcRaiseExcp

このサービス・ルーチンは、事前定義の例外を呼び出します。1から32,767の範囲の有効なOracle Databaseエラー番号を含む必要があります。この例外には、1から32,767の有効なOracle Databaseエラー番号が含まれている必要があります。クリーン・アップ処理後、外部プロシージャをすぐに戻す必要があります(OUTまたはIN OUTパラメータには値は何も割り当てられません)。この関数のCプロトタイプは、次のとおりです。

int OCIExtProcRaiseExcp(
OCIExtProcContext *with_context,
size_t errnum);

パラメータwith_contextおよびerror_numberは、それぞれ、コンテキスト・ポインタおよびOracle Databaseエラー番号です。戻り値のOCIEXTPROC_SUCCESSおよびOCIEXTPROC_ERRORは、正常終了および失敗を示します。

SQL*Plusで、外部プロシージャplsTo_divide_procを次のように発行するとします。

CREATE OR REPLACE PROCEDURE plsTo_divide_proc (
dividend IN PLS_INTEGER,
divisor  IN PLS_INTEGER,
result   OUT FLOAT)
AS LANGUAGE C
NAME "C_divide"
LIBRARY MathLib
WITH CONTEXT
PARAMETERS (
CONTEXT,
dividend INT,
divisor  INT,
result   FLOAT);

C_divideは、コールされたときに2つの数値の比率を計算します。次の例で示すように、除数が0(ゼロ)の場合、C_divideはOCIExtProcRaiseExcpを使用して事前定義の例外ZERO_DIVIDEを次のように呼び出します。

void C_divide (ctx, dividend, divisor, result)
OCIExtProcContext *ctx;
int    dividend;
int    divisor;
float  *result;
{
/* Check for zero divisor. */
if (divisor == (int)0)
{
/* Raise exception ZERO_DIVIDE, which is Oracle Database error 1476. */
if (OCIExtProcRaiseExcp(ctx, (int)1476) == OCIEXTPROC_SUCCESS)
{
return;
}
else
{
/* Incorrect parameters were passed. */
assert(0);
}
}
*result = (float)dividend / (float)divisor;
}

OCIExtProcRaiseExcpWithMsg

このサービス・ルーチンはユーザー定義例外を呼び出し、ユーザー定義エラー・メッセージを戻します。この関数のCプロトタイプは、次のとおりです。

int OCIExtProcRaiseExcpWithMsg(
OCIExtProcContext *with_context,
size_t  error_number,
text   *error_message,
size_t  len);

パラメータwith_context、error_number、error_messageは、それぞれ、コンテキスト・ポインタ、Oracle Databaseエラー番号、エラー・メッセージ・テキストです。パラメータlenは、エラー・メッセージの長さを格納します。メッセージがNULLで終了する文字列の場合、lenは0(ゼロ)です。戻り値のOCIEXTPROC_SUCCESSおよびOCIEXTPROC_ERRORは、正常終了および失敗を示します。

この前の例では、外部プロシージャplsTo_divide_procを発行しました。次の例では、別の実装方法を使用します。ここでは、除数が0(ゼロ)の場合、C_divideはOCIExtProcRaiseExcpWithMsgを使用してユーザー定義例外を呼び出します。

void C_divide (ctx, dividend, divisor, result)
OCIExtProcContext *ctx;
int    dividend;
int    divisor;
float  *result;
/* Check for zero divisor. */
if (divisor == (int)0)
{
/* Raise a user-defined exception, which is Oracle Database error 20100,
and return a null-terminated error message. */
if (OCIExtProcRaiseExcpWithMsg(ctx, (int)20100,
"divisor is zero", 0) == OCIEXTPROC_SUCCESS)
{
return;
}
else
{
/*  Incorrect parameters were passed. */
assert(0);
}
}
*result = dividend / divisor;

}

外部Cプロシージャを使用したコールバックの実行

コールバックを有効にするには、OCIExtProcGetEnv関数を使用します。

内容は次のとおりです。

- OCIExtProcGetEnv

- OCIコールバック用のオブジェクト・サポート

- コールバックに関する制限事項

- 外部プロシージャのデバッグ

- 例: 外部プロシージャのコール

- 外部Cプロシージャのグローバル変数

- 外部Cプロシージャの静的変数

- 外部Cプロシージャに関する制限事項

OCIExtProcGetEnv

このサービス・ルーチンを使用すると、外部プロシージャ・コール中にデータベースへのOCIコールバックが可能になります。この関数によって取得された環境ハンドルは、既存の接続を再利用してデータベースに戻ります。データベースとの接続を新しく確立する必要がある場合は、このハンドルを使用できません。自分でハンドルを作成する必要があります。

この関数のCプロトタイプは、次のとおりです。

sword OCIExtProcGetEnv ( OCIExtProcContext *with_context,
OCIEnv envh,
OCISvcCtx svch,
OCIError errh )

パラメータwith_contextはコンテキスト・ポインタで、パラメータenvh、svch、errhは、それぞれ、OCI環境、サービス、エラー・ハンドルです。戻り値のOCIEXTPROC_SUCCESSおよびOCIEXTPROC_ERRORは、正常終了および失敗を示します。

外部CプロシージャおよびJavaクラス・メソッドでは、どちらもデータベースをコールバックしてSQL操作を実行できます。実際の例は、「例: 外部プロシージャのコール」を参照してください。

注意:
コールバックは、必ずしも同一セッションで発生するとはかぎりません。OCIlogonを使用して、別セッション内でSQL文を実行することができます。

Oracle Database上で実行される外部Cプロシージャでは、サービス・ルーチンをコールしてOCI環境およびサービス・ハンドルを取得できます。OCIを使用すると、SQL文およびPL/SQLサブプログラムの実行、データのフェッチ、およびLOBの操作のためにコールバックを使用することができます。コールバックおよび外部プロシージャは同一のユーザー・セッションおよびトランザクション・コンテキストで動作するため、ユーザー権限も同一です。

SQL*Plusで、次のスクリプトを実行するとします。

CREATE TABLE Emp_tab (empno NUMBER(10))

CREATE PROCEDURE plsToC_insertIntoEmpTab_proc (
empno PLS_INTEGER)
AS LANGUAGE C
NAME "C_insertEmpTab"
LIBRARY insert_lib
WITH CONTEXT
PARAMETERS (
CONTEXT,
empno LONG);

後で、次のように外部プロシージャplsToC_insertIntoEmpTab_procからサービス・ルーチンOCIExtProcGetEnvをコールできます。

#include <stdio.h>
#include <stdlib.h>
#include <oratypes.h>
#include <oci.h>   /* includes ociextp.h */
...
void C_insertIntoEmpTab (ctx, empno)
OCIExtProcContext *ctx;
long empno;
{
OCIEnv    *envhp;
OCISvcCtx *svchp;
OCIError  *errhp;
int        err;
...
err = OCIExtProcGetEnv(ctx, &envhp, &svchp, &errhp);
...
}

コールバックを使用しない場合は、oci.hを含める必要はなく、ociextp.hのみを含めます。

OCIコールバック用のオブジェクト・サポート

外部プロシージャからオブジェクト関連コールバックを実行するために、extprocエージェント内のOCI環境がオブジェクト・モードで完全に初期化されています。この環境へのハンドルは、OCIExtProcGetEnvプロシージャを使用して取得します。

オブジェクト・ランタイム環境を使用すると、OCIによって提供される静的および動的なオブジェクト・サポートが使用できます。静的サポートを使用するには、OTTを使用して該当するオブジェクト型用のC構造体を生成し、次に、従来のCコードを使用してオブジェクトの属性にアクセスします。

外部プロシージャの作成時に型がわからないオブジェクトについては、かわりの動的なオブジェクト・アクセス方法によって、OCIDescribeAnyがコールされてその型の属性およびメソッド情報が取得されます。その後、OCIObjectGetAttrおよびOCIObjectSetAttrをコールして、属性値を取得して設定します。

現在の外部プロシージャ・モデルはステートレスのため、コールバックを実行する外部プロシージャごとにOCIExtProcGetEnvをコールするか、または、OCIExtProcサービス・ルーチンをコールします。外部プロシージャがコールされるたびに、コール後にコールバック・メカニズムがクリーン・アップされ、OCIハンドルが解放されます。

コールバックに関する制限事項

コールバックでは、次のSQL文およびOCIサブプログラムはサポートされていません。

- COMMITなどのトランザクション制御文

- CREATEなどのデータ定義文

- 次のオブジェクト指向OCIサブプログラム

OCIObjectNew
OCIObjectPin
OCIObjectUnpin
OCIObjectPinCountReset
OCIObjectLock
OCIObjectMarkUpdate
OCIObjectUnmark
OCIObjectUnmarkByRef
OCIObjectAlwaysLatest
OCIObjectNotAlwaysLatest
OCIObjectMarkDeleteByRef
OCIObjectMarkDelete
OCIObjectFlush
OCIObjectFlushRefresh
OCIObjectGetTypeRef
OCIObjectGetObjectRef
OCIObjectExists
OCIObjectIsLocked
OCIObjectIsDirtied
OCIObjectIsLoaded
OCIObjectRefresh
OCIObjectPinTable
OCIObjectArrayPin
OCICacheFlush,
OCICacheFlushRefresh,
OCICacheRefresh
OCICacheUnpin
OCICacheFree
OCICacheUnmark
OCICacheGetObjects
OCICacheRegister

- OCIGetPieceInfoなどのポーリング・モードOCIサブプログラム

- 次のOCIサブプログラム

OCIEnvInit
OCIInitialize
OCIPasswordChange
OCIServerAttach
OCIServerDetach
OCISessionBegin
OCISessionEnd
OCISvcCtxToLda
OCITransCommit
OCITransDetach
OCITransRollback
OCITransStart

また、OCIサブプログラムOCIHandleAllocでは、次のハンドル・タイプはサポートされていません。

OCI_HTYPE_SERVER
OCI_HTYPE_SESSION
OCI_HTYPE_SVCCTX
OCI_HTYPE_TRANS

外部プロシージャのデバッグ

外部プロシージャが失敗する場合は、通常、そのプロトタイプに不具合があります。プロトタイプが、PL/SQLによって内部的に生成されたプロトタイプと一致しないということです。これは、互換性のないCデータ型を指定した場合に発生する可能性があります。たとえば、型がREALのOUTパラメータを渡すためにfloat *を指定したとします。float、double *または他のCデータ型を指定すると、結果が不一致になります。

このような場合は、次のエラーを受け取ることがあります。

lost RPC connection to external routine agent

このエラーは、外部プロシージャによってコア・ダンプが発生したため、extprocが異常終了したことを表します。Cプロトタイプ・パラメータの宣言時にエラーを回避するには、前述の表を参照してください。

PL/SQLでは、外部プロシージャのデバッグを支援する目的でユーティリティ・パッケージDEBUG_EXTPROCが提供されています。このパッケージをインストールするには、PL/SQLデモ・ディレクトリにあるスクリプトdbgextp.sqlを実行します。(ディレクトリの場所については、ご使用のOracle Databaseのインストール・ガイドまたはユーザーズ・ガイドを参照してください。)

このパッケージを使用するには、dbgextp.sqlの指示に従ってください。Oracle Databaseアカウントに、パッケージに対するEXECUTE権限およびCREATE LIBRARY権限が必要です。

注意:
DEBUG_EXTPROCは、実行中のプロセスにアタッチできるデバッガ付きのプラットフォームでのみ動作します。

例: 外部プロシージャのコール

PL/SQLデモ・ディレクトリには、外部プロシージャのコール方法を示すスクリプトextproc.sqlもあります。付属ファイルextproc.cには、外部プロシージャ用のCソース・コードが含まれています。

デモを実行するには、extproc.sqlにある指示に従ってください。SCOTTアカウントを使用する必要があり、このアカウントにはCREATE LIBRARY権限が必要です。

外部Cプロシージャのグローバル変数

グローバル変数は関数の外で宣言され、その値はプログラムのすべての関数によって共有されます。したがって、外部プロシージャの場合、DLL内のすべての関数がグローバル変数の値を共有します。グローバル変数は関数の存続期間を超えて存続するデータの格納にも使用されます。しかし、グローバル変数の使用は、次の2つの理由のため、お薦めしません。

- スレッド
エージェント・プロセスは非スレッド構成になっているため、一度にアクティブになる関数は1つのみです。マルチスレッドのextprocエージェントの場合は、一度に複数の関数をアクティブにできます。その場合は、それらが同時にグローバル変数にアクセスしようとして、正常な結果が得られなくなる可能性があります。

- DLLのキャッシング
グローバル変数にデータを格納することで、関数func1が関数func2にデータを渡すとします。func1の完了後DLLキャッシュはアンロードされ、この結果、グローバル変数のすべての値が失われる可能性があります。次に、func2が実行されるときに、DLLは再ロードされ、グローバル変数はすべて0(ゼロ)に初期化されます。

外部Cプロシージャの静的変数

静的変数には外部変数および内部変数の2種類があります。外部静的変数は、特殊なグローバル変数であり、使用をお薦めしません。内部静的変数は、特定の関数に対するローカルな変数ですが、関数がアクティブになるたびに生成、消滅するのではなく、存在したまま残ります。このため、この変数は1つの関数内にプライベートで永続的な記憶域を提供します。このような変数は、同一関数を後でコールするときにデータを渡すために使用します。ただし、DLLには前述のキャッシュ機能があるため、DLLがコールごとにアンロードおよび再ロードされる可能性があります。これは、内部静的変数がその値を失う可能性があることを表します。

参照:
動的リンク・ライブラリの作成方法は、RDBMSサブディレクトリ/publicにあるテンプレートmakefileを参照してください。

外部プロシージャをコールする場合:

- INパラメータには書込みを行わないでください。OUTパラメータの容量をオーバーフローさせないようにしてください。(PL/SQLでは、実行時にこの2つのエラー状態はチェックしません。)

- OUTパラメータまたは関数結果を読み込まないでください。

- IN OUTパラメータとOUTパラメータおよび関数結果には、必ず値を代入してください。代入しないと、外部プロシージャが正常に戻りません。

- WITH CONTEXTおよびPARAMETERS句を含める場合は、パラメータ・リスト内でのコンテキスト・ポインタの位置を示すパラメータCONTEXTを指定する必要があります。

- PARAMETERS句を含めたときに、外部プロシージャが関数の場合は、パラメータRETURNを最後の位置に指定する必要があります。

- 各仮パラメータには、PARAMETERS句に対応するパラメータが必要です。また、PARAMETERS句のパラメータのデータ型が、Cプロトタイプのデータ型と互換性があることも確認します。これは、暗黙的変換が実行されないためです。

- 型がRAWまたはLONG RAWのパラメータの場合は、プロパティLENGTHを使用してください。また、そのパラメータがIN OUTまたはOUTおよびNULLの場合は、対応するCパラメータの長さを0(ゼロ)に設定する必要があります。

外部Cプロシージャに関する制限事項

外部プロシージャには次の制限が適用されます。

- この機能は、DLLをサポートするプラットフォームのみで使用可能です。

- CプロシージャまたはCからコール可能なプロシージャのみがサポートされます。

- 分散トランザクションと組み合せた外部プロシージャ・コールアウトはサポートされません。

- PL/SQLカーソル変数またはレコードを外部プロシージャに渡すことはできません。レコードについては、かわりにオブジェクト型のインスタンスを使用できます。

- LIBRARY副次句には、リモート・ライブラリを指定するデータベース・リンクは使用できません。

- 外部プロシージャに渡すことができるパラメータの最大数は128です。ただし、FLOAT型またはDOUBLE型のパラメータを値渡しする場合は、最大数は127以下になります。どのくらい減るかは、パラメータの個数およびオペレーティング・システムによって異なります。目安としては、値渡しされるFLOAT型またはDOUBLE型のパラメータ1つを2つ分として数えます。

15 Oracle XAを使用したアプリケーションの開発

この章では、Oracle XAライブラリの使用方法について説明します。通常、このライブラリはトランザクション・モニターで作業するアプリケーションで使用します。XAの機能は、トランザクションが複数のデータベースと相互処理するアプリケーションで最も効果的です。

内容は次のとおりです。

- X/Open DTP

- Oracle XAライブラリ・サブプログラム

- XAアプリケーションの開発およびインストール

- XAアプリケーションのトラブルシューティング

- Oracle XAの問題および制限事項

参照:

- 基本的なアーキテクチャなど、XAの概要は、X/Open Document Number XO/CAE/91/300、『X/Open CAE Specification - Distributed Transaction Processing: The XA Specification』を参照してください。このドキュメントには、http://www.opengroup.org/pubs/catalog/c193.htmでアクセスできます。

- Oracle XAライブラリのバックグラウンドおよび参照情報は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

- ライブラリ・リンク・ファイル名の詳細は、プラットフォーム固有のOracle Databaseのマニュアルを参照してください。

- プラットフォーム固有のOracle XAライブラリの変更点、不具合および制限事項については、READMEを参照してください。

X/Open DTP

X/Open Distributed Transaction Processing(DTP)アーキテクチャは、複数のアプリケーション・プログラム(AP)が複数の異なるリソース・マネージャ(RM)から提供されるリソースを共有できるようにするための、標準のアーキテクチャまたはインタフェースを定義しています。APとRM間の作業を調整し、グローバル・トランザクションを実現します。

Oracle XAライブラリは、X/Openソフトウェア・アーキテクチャのXAインタフェース仕様に準拠しています。Oracle XAライブラリは外部インタフェースであり、Oracleのクライアント側トランザクション・マネージャ(TM)以外のクライアント側TMがグローバル・トランザクションを調整可能にすることで分散トランザクションにOracle Database以外のRMを組み込めるようにします。たとえば、クライアント・アプリケーションでは、Oracle DatabaseトランザクションとNTFSファイル・システム内のトランザクションを1つのグローバル・トランザクションとして管理できます。

図15-1に、X/Open DTPモデルの例を示します。

図15-1 DTPモデルの例

内容は次のとおりです。

- DTP用語

- 必須のパブリック情報

DTP用語

- リソース・マネージャ(RM)

- 分散トランザクション

- ブランチ

- トランザクション・マネージャ(TM)

- トランザクション処理モニター(TPM)

- 2フェーズ・コミット・プロトコル

- アプリケーション・プログラム(AP)

- TXインタフェース

- 密結合と疎結合

- 動的登録と静的登録

リソース・マネージャ(RM)

リソース・マネージャは、障害発生後に通常の状態に戻すことができる共有かつリカバリ可能なリソースを制御します。たとえば、リレーショナル・データベース、トランザクション・キューおよびトランザクション・ファイル・システムなどです。Oracle DatabaseはRMであり、障害発生後にREDOログおよびロールバック・セグメントを使用して一貫性のある状態に復帰します。

分散トランザクション

分散トランザクションは、複数の分散リソースに対する更新を伴い、分散RM間で「すべてまたはなし」のセマンティクスを必要とするクライアント・トランザクションであり、グローバル・トランザクションとも呼ばれます。

ブランチ

ブランチは、1つのRMに含まれる1つの作業単位です。複数のブランチが1つのグローバル・トランザクションを構成します。Oracle Databaseの場合、各ブランチはデータベース・サーバー内のローカル・トランザクションにマップします。

トランザクション・マネージャ(TM)

トランザクション・マネージャは、トランザクション境界を指定するためのAPIを提供し、コミットおよびリカバリを管理します。TMでは、分散RM間で「すべてまたはなし」のセマンティクスを提供する2フェーズ・コミット・エンジンが実装されます。

外部TMとは、Oracle Databaseの外部に常駐する中間層コンポーネントです。通常、データベースには固有の内部TMがあります。業界標準に準拠したTMを使用することで、Oracle Databaseは単一のトランザクション内で他の異機種間RMと共存できます。

トランザクション処理モニター(TPM)

TMは、通常、次のようなトランザクション処理モニター(TPM)が提供します。

- Oracle Tuxedo

- IBM Transarc Encina

- IBM CICS

TPMは、トランザクション要求を発行するクライアント・プロセスとその要求を処理するバックエンド・サーバー間の要求フローを調整します。TPMは、基本的にネットワーク上に分散されているアプリケーション・サーバーやRMなどのように、様々な種類のバックエンド・プロセスに対してサービスを要求するトランザクションを調整します。

TPMは、分散トランザクションを完了するために必要なコミットまたはロールバックを同期化します。TPMのTM部分が、分散コミットおよび分散ロールバックの発生するタイミングを制御します。このため、分散APでTPMを利用する場合、TPMのTM部分が2フェーズ・コミット・プロトコルを制御します。RMを使用して、TMはこのタスクを実行します。

TMは分散コミットまたはロールバックを制御するため、XAインタフェースを介してOracle Database(または他のRM)と直接通信する必要があります。TMは、トランザクション内のすべてのRMに関する情報に基づいて、「Oracle XAライブラリ・サブプログラム」で説明するOracle XAライブラリ・サブプログラムを使用してOracle Databaseにトランザクションの処理方法を指示します。

2フェーズ・コミット・プロトコル

Oracle XAライブラリ・インタフェースは、2フェーズ・コミット・プロトコルに従います。各イベントの順序は次のとおりです。

1. 準備フェーズでは、TMは各RMに対して、トランザクションの任意の部分をコミットできるように要求します。これが可能な場合は、RMは準備ができた状態を記録し、TMに肯定的に応答します。可能でない場合は、RMはすべての作業をロールバックし、TMに否定的に応答し、そのトランザクションに関する情報を消去します。プロトコルによって、アプリケーションまたはRMは、準備フェーズが完了する前にトランザクションを一方的にロールバックできます。

2. フェーズ2では、TMはコミット決定を記録し、トランザクションに参加しているすべてのRMに対してコミットまたはロールバックを発行します。TMは、すべてのRMがフェーズ1に対して肯定的に応答した場合にのみ、RMのコミットを発行できます。

アプリケーション・プログラム(AP)

アプリケーション・プログラムは、トランザクション境界を定義し、トランザクションを構成するアクションを指定します。たとえば、APはプリコンパイラでもOracle Call Interface(OCI)プログラムでもかまいません。APは、RMのネイティブ・インタフェース(たとえばSQL)を使用して、RMのリソースを操作します。

TXインタフェース

アプリケーション・プログラムは、TMを介し、TXと呼ばれるインタフェースを使用してすべてのトランザクション制御操作を開始および完了します。APがXAインタフェースを直接使用することはありません。APが中間層で分岐するブランチを認識することはありません。アプリケーション・スレッドがブランチの作業を明示的に結合、休止、一時停止および再開するかわりに、トランザクション処理モニターのTM部分がAPのためにグローバル・トランザクションのブランチを管理します。最終的に、APはTMをコールしてすべてをコミットするか、または何もコミットしません。

注意:
TXインタフェースおよびその関連のサブプログラムのネーミング規則はベンダー固有です。たとえば、tx_openコールは、使用中のシステムではtp_openと呼ばれている場合があります。また、トランザクションRPCへの入力時など、このコールが暗黙的な場合もあります。詳細は、トランザクション処理モニターに付属のマニュアルを参照してください。

密結合と疎結合

RMですべての分離セマンティクスについて単一エンティティとみなされるアプリケーション・スレッドは、密結合となります。密結合ブランチは、相互の変更を認識する必要があります。さらに、外部クライアントは、密結合セットの変更をすべて認識するか、まったく認識しない必要があります。アプリケーション・スレッドが密結合されていない場合は、疎結合となります。

動的登録と静的登録

Oracle Databaseは、動的登録と静的登録の両方をサポートします。動的登録の場合、RMは最初にアプリケーション・コールバックを実行します。静的登録の場合、関係のないRMがあっても、最初に、各RMに対してxa_startをコールする必要があります。

必須のパブリック情報

Oracle Databaseは、リソース・マネージャとして、表15-1に示す情報を発行する必要があります。

表15-1 Oracle Databaseが発行する必要のあるXA機能

XA機能

Oracle Databaseの詳細

xa_switch_t構造体

Oracle Databaseのxa_switch_t構造体名は、静的登録の場合はxaosw、動的登録の場合はxaoswdです。これらの構造体には、RMのエントリ・ポイントおよびその他の情報が含まれています。

xa_switch_tリソース・マネージャ

xa_switch_t構造体内のOracle DatabaseのRM名はOracle_XAです。

クローズ文字列

xa_closeで使用されるクローズ文字列は無視され、NULLとして扱われます。

オープン文字列

xa_openで使用されるオープン文字列の書式の詳細は、「xa_open文字列の定義」を参照してください。

ライブラリ

Oracle XAを使用するアプリケーションをリンクするために必要なライブラリには、プラットフォーム固有の名前が付けられています。TPM固有のライブラリをリンクする必要があることを除けば、通常のプリコンパイラまたはOCIプログラムをリンクする手順と同じです。

sqllibを使用していない場合は、必ず$ORACLE_HOME/rdbms/lib/xaonsl.oまたは$ORACLE_HOME/rdbms/lib32/xaonsl.o(32ビット・アプリケーションを64ビット・プラットフォーム上で作成する場合)をリンクしてください。

要件

ありません。XAをサポートする機能はStandard EditionおよびEnterprise Editionに含まれています。

Oracle XAライブラリ・サブプログラム

Oracle XAライブラリ・サブプログラムを使用することで、TMはトランザクションの処理方法をOracle Databaseに指示できます。一般に、TMはxa_openを使用してリソースをオープンする必要があります。通常、リソースはAPでtx_openをコールした結果としてオープンされます。一部のTMでは、アプリケーションが開始したときに、暗黙的にxa_openをコールします。

同様に、アプリケーションがリソースの使用を完了したときに発生するクローズがあります(xa_closeを使用)。このクローズが発生するのは、APがtx_closeをコールしたとき、またはアプリケーションが終了したときです。

TMはRMに対して、次のように他の複数のタスクを実行するように指示します。

- トランザクションの開始、およびトランザクションに対するIDの対応付け

- トランザクションのロールバック

- トランザクションの準備およびコミット

内容は次のとおりです。

- Oracle XAライブラリ・サブプログラム

- Oracle XAインタフェース拡張機能

Oracle XAライブラリ・サブプログラム

表15-2に、XAライブラリ・サブプログラムを示します。

表15-2 XAライブラリ・サブプログラム

XAサブプログラム

説明

xa_open

RMに接続します。

xa_close

RMとの接続を切断します。

xa_start

トランザクションを開始し、指定のトランザクションID(XID)に対応付けるか、またはプロセスと既存トランザクションを対応付けます。

xa_end

指定されたXIDからプロセスを切断します。

xa_rollback

指定されたXIDに対応付けられているトランザクションをロールバックします。

xa_prepare

指定されたXIDに対応付けられているトランザクションを準備します。これは、2フェーズ・コミット・プロトコルの第1のフェーズです。

xa_commit

指定されたXIDに対応付けられているトランザクションをコミットします。これは、2フェーズ・コミット・プロトコルの第2のフェーズです。

xa_recover

準備されたヒューリスティックにコミットまたはロールバックされたトランザクションのリストを取得します。

xa_forget

指定されたXIDに対応付けられているヒューリスティックに完了したトランザクションの情報を消去します。

一般に、APでは、xa_open文字列で実行されるロールを理解する以外に、表15-2に示したサブプログラムについて考慮する必要はありません。

Oracle XAインタフェース拡張機能

表15-3に示すように、Oracle DatabaseのXAインタフェースには、いくつかの関数が追加されています。

表15-3 Oracle XAインタフェース拡張機能

関数

説明

OCISvcCtx *xaoSvcCtx(text *dbname)

指定されたXA接続のOCIサービス・ハンドルを戻します。dbnameパラメータは、xa_open文字列で渡されたDBパラメータと同じである必要があります。OCIアプリケーションでは、接続ハンドルを取得するために、sqlld2コールのかわりにこのルーティングを使用できます。このため、OCIアプリケーションはsqllibライブラリにリンクする必要はありません。サービス・ハンドルは、OCISvcCtxToLda(OCIバージョン8)を使用してOCIバージョン7のログイン・データ領域(LDA)に変換できます。クライアント・アプリケーションは、OCIコールを完了した後で、OCILdaToSvcCtxを使用してOracle7のLDAをサービス・ハンドルに変換する必要があります。

OCIEnv *xaoEnv(text *dbname)

指定されたXA接続のOCI環境ハンドルを戻します。dbnameパラメータは、xa_open文字列で渡されたDBパラメータと同じである必要があります。

int xaosterr(OCISvcCtx *SvcCtx,sb4 error)

Oracle Databaseエラー・コードをXAエラー・コードに変換します(動的登録にのみ適用可能)。最初のパラメータは、データベースで作業を実行するために使用するサービス・ハンドルです。2番目のパラメータは、Oracle Databaseから戻されるエラー・コードです。この関数は、OCI文から戻されたエラーがxa_startの違反によって発生したものかどうかを判断するために使用します。この関数は、エラーがXAモジュールによって生成されたものでない場合はXA_OKを戻し、エラーがXAモジュールによって生成されたものである場合は有効なXAエラーを戻します。

XAアプリケーションの開発およびインストール

この項では、Oracle XAライブラリの開発およびインストールについて説明します。

- DBAまたはシステム管理者の責任

- アプリケーション開発者の責任

- xa_open文字列の定義

- XAアプリケーションの開発およびインストール

- Oracle XAを使用したトランザクション制御の管理

- プリコンパイラまたはOCIアプリケーションのTPMアプリケーションへの移行

- Oracle XAライブラリ・スレッド・セーフティの管理

- DBMS_XAパッケージの使用

DBAまたはシステム管理者の責任

DBAまたはシステム管理者の責任は次のとおりです。

1. アプリケーション開発者の支援によってオープン文字列を定義します。詳細は、「xa_open文字列の定義」を参照してください。

2. 静的データ・ディクショナリ・ビューDBA_PENDING_TRANSACTIONSが存在することを確認し、xa_open文字列で指定したすべてのOracleユーザーに対して、このビューのSELECT権限を付与します。
自分が作成したペンディング(インダウト)トランザクションをコミットまたはロールバックするOracleユーザーにFORCE TRANSACTION権限を付与します。権限の付与には、コマンドCOMMIT FORCE local_tran_idまたはROLLBACK FORCE local_tran_idを使用します。

他のユーザーが作成したXAトランザクションをコミットまたはロールバックするOracleユーザーにFORCE ANY TRANSACTION権限を付与します。たとえば、ユーザーBが作成したトランザクションをユーザーAがコミットまたはロールバックする場合、ユーザーAにはFORCE ANY TRANSACTION権限が必要となります。

Oracle Databaseリリース7のクライアント・アプリケーションの場合は、Oracle XAライブラリで使用されるすべてのOracle Databaseアカウントに対して、動的パフォーマンス・ビューV$XATRANS$のSELECT権限を付与する必要があります。このビューは、XAライブラリのインストール時に作成されている必要があります。必要な場合は、Oracle DatabaseユーザーSYSとしてSQLスクリプトxaview.sqlを実行し、このビューを手動で作成できます。

参照:
catxpend.sqlスクリプトの位置は、使用中のプラットフォーム固有のOracle Databaseのマニュアルを参照してください。

3. オープン文字列情報を使用して、RMをTPM構成にインストールします。TPMベンダーの指示に従ってください。
DBAまたはシステム管理者は、Oracle Databaseに接続するプロセスをTPMシステムが開始することを認識する必要があります。TPMのマニュアルを参照して、このプロセスのためにどのような環境が存在するのか、ユーザーIDは何である必要があるかを判断してください。この環境で$ORACLE_HOMEおよび$ORACLE_SIDに正しい値が設定されていることを確認してください。

4. XAトレース・ファイルが書き込まれるディレクトリに対する書込み許可を、そのユーザーIDに対して付与します。

参照:
デフォルトとは異なるOracleシステム識別子(SID)またはトレース・ディレクトリを指定する方法の詳細は、「xa_open文字列の定義」を参照してください。

5. Oracle XAアプリケーションをオンラインにするために、適切なデータベース・インスタンスを起動します。このタスクは、TPMサーバーを開始する前に実行してください。

アプリケーション開発者の責任

アプリケーション開発者の責任は次のとおりです。

1. DBAまたはシステム管理者の支援によってオープン文字列を定義します。「xa_open文字列の定義」を参照してください。

2. アプリケーションを開発します。
プリコンパイラ用のトランザクション指向のSQL文に関する特別な制限事項を守ってください。

参照:
「XAアプリケーションの開発およびインストール」

3. TPMベンダーの指示に従ってアプリケーションをリンクします。

xa_open文字列の定義

オープン文字列は、トランザクション・モニターがデータベースをオープンするために使用します。オープン文字列内の最大文字数は256文字です。

内容は次のとおりです。

- xa_open文字列の構文

- xa_open文字列の必須フィールド

- xa_open文字列のオプション・フィールド

xa_open文字列の構文

例15-1に示す構文を使用してオープン文字列を定義できます。

例15-1 xa_open文字列

ORACLE_XA{+required_fields...} [+optional_fields...]

次の文字列は、サンプル・パラメータ設定を示しています。

ORACLE_XA+DB=MANAGERS+SqlNet=SID1+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/xalog
ORACLE_XA+DB=PAYROLL+SqlNet=SID2+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/xalog
ORACLE_XA+SqlNet=SID3+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/xalog

次の各項では、required_fieldsおよびoptional_fieldsプレースホルダに有効なパラメータについて説明します。

- xa_open文字列の必須フィールド

- xa_open文字列のオプション・フィールド

注意:

- オープン文字列の作成時には、必須フィールドおよびオプションのフィールドをどのような順序でも入力できます。

- すべてのフィールド名は大/小文字が区別されません。その値の大/小文字が区別されるかどうかは、プラットフォームによって異なります。

- 実際の情報文字列の一部にプラス文字(+)を使用することはできません。

xa_open文字列の必須フィールド

例15-1に示したrequired_fieldsプレースホルダは、表15-4に示す名前/値ペアのいずれかを指します。

表15-4 xa_open文字列の必須フィールド

構文要素

説明

Acc=P//

ユーザーおよびパスワード情報が明示的には提供されないことと、オペレーティング・システム認証フォームが使用されることを指定します。詳細は、『Oracle Database管理者ガイド』を参照してください。

Acc=P/user/password

有効なOracle Databaseアカウントのユーザー名とパスワードを指定します。「DBAまたはシステム管理者の責任」で説明したとおり、HRにDBA_PENDING_TRANSACTIONS表のSELECT権限があることを確認してください。

SesTm=session_time_limit

システムによりトランザクションが終了されるまでの、あるサービスから次のサービスまで、あるいはサービスからトランザクションのコミットまたはトランザクションまでの最大許容秒数を指定します。たとえば、SesTM=15は、セッション・アイドル時間の上限が15秒であることを示します。

たとえば、TPMでクライアントとサーバー間にリモート・サブプログラム・コールが使用されている場合は、SesTMは、あるRPCの完了から次のRPCの初期化の間、tx_commitまたはtx_rollbackとの間に適用されます。

値が0(ゼロ)の場合は、制限がないことを示します。値0(ゼロ)はできるだけ指定しないでください。問題があった場合に、リソースを長時間拘束することがあります。また、子プロセスにSesTM=0がある場合、親プロセスが終了した後は、SesTM設定の効果がなくなります。

xa_open文字列のオプション・フィールド

例15-1に示したoptional_fieldsプレースホルダは、表15-5に示す名前/値ペアのいずれかを指します。

表15-5 xa_open文字列のオプション・フィールド

構文要素

説明

NoLocal= true | false

ローカル・トランザクションが許可されるかどうかを指定します。デフォルト値はfalseです。アプリケーションでローカル・トランザクションを禁止する必要がある場合は、値をtrueに設定します。

DB=db_name

Oracle Databaseプリコンパイラがデータベースの識別に使用する名前を指定します。たとえば、DB=payrollは、データベース名がpayrollであり、アプリケーション・サーバー・プログラムがこの名前をAT句で使用することを指定します。

Oracle Databaseプリコンパイラのデフォルトのデータベースのみを使用する(SQL文でAT句を使用しない)APでは、オープン文字列のDB=db_name句を省略する必要があります。明示的に指定したデータベースを使用するアプリケーションは、DB=db_nameフィールドにそのデータベース名を指定する必要があります。Oracle Databaseバージョン7のOCIプログラムでは、OCIサービス・コンテキストと等価のログイン・データ領域(Lda_Def)の正しいコンテキストを取得するために、sqlld2関数をコールする必要があります。バージョン8のOCIプログラムでは、xaoSvcCtx関数をコールして、OCISvcCtxサービス・コンテキストを取得する必要があります。

db_nameはSIDではありません。オープンするデータベースを検索するためには使用されません。このオープン文字列でオープンされたデータベースと、SQL文を実行するためにAPで使用される名前とを対応付けます。SIDは、TPMアプリケーション・サーバーのORACLE_SID環境変数か、オープン文字列のOracle Net句で指定したSIDから設定されます。Oracle Net句については、この項で後述します。一部のTPMベンダーは、同じオープン文字列を使用するサーバー・グループの名前を指定する方法を提供しています。グループ名とdb_nameの両方に対して同じ名前を選択する方が便利な場合があります。

LogDir=log_dir

Oracle XAライブラリのエラーとトレース情報が格納されるローカル・システム上のパス名を示します。デフォルトは、ORACLE_HOMEが設定されている場合は$ORACLE_HOME/rdbms/logで、それ以外の場合は現行のディレクトリを指定します。たとえば、LogDir=/xa_traceは、/xa_traceディレクトリにロギング情報があることを示しています。指定したディレクトリが存在し、アプリケーション・サーバーでそのディレクトリに確実に書き込めるようにしてください。

Objects= true | false

アプリケーションをオブジェクト・モードで初期化するかどうかを指定します。デフォルト値はfalseです。アプリケーションが、OCIRawAssignBytesなどのオブジェクト・モードを必要とする特定のAPIコールを使用する必要がある場合、trueを指定します。

MaxCur=maximum_#_of_open_cursors

データベースのオープン時に割り当てられるカーソルの数を指定します。これは、プリコンパイラ・オプションmaxopencursorsと同じ用途で機能します。たとえば、MaxCur=5は、プリコンパイラで5つのオープン・カーソルがキャッシュされることを示します。このパラメータは、ソース・コード内またはコンパイル時に指定したプリコンパイラ・オプションmaxopencursorsをオーバーライドします。

SqlNet=db_link

システムにログインするために使用するOracle Netデータベース・リンクを示します。この文字列は、tnsnames.oraのエントリである必要があります。たとえば、文字列SqlNet=inst1_dispの場合は、tnsnames.oraに定義されていれば、インスタンス1の共有サーバーに接続できます。

サーバー環境変数を制御できない場合は、SqlNetパラメータを使用してORACLE_SIDを指定できます。また、サーバーが複数のOracle Databaseインスタンスにアクセスする必要があるときにも、このパラメータを使用する必要があります。実際にリモート・データベースにアクセスせずにOracle Net文字列を使用するには、パイプ・ドライバを使用します。たとえば、SqlNet=localsid1と指定します。localsid1は、tnsnames.oraファイルで定義されている別名です。

Loose_Coupling=true | false

ロックが共有されるかどうかを示します。同じグローバル・トランザクション内の複数のOracle Databaseトランザクション・ブランチには、密結合または疎結合のどちらの方法も使用できます。ブランチが疎結合の場合は、ロックを共有できません。疎結合ブランチの場合は、値をtrueに設定します。ブランチが密結合の場合は、ロックを共有できます。密結合ブランチの場合は、値をfalseに設定します。デフォルト値はfalseです。

注意: Oracle RACの実行時に、トランザクション・ブランチが別のOracle RACインスタンスにある場合は、Loose_Coupling=falseであってもこれらは疎結合です。

SesWt=session_wait_limit

XA_RETRYが戻される前にOracle Databaseが別のセッションに使用されているトランザクション・ブランチを待機する秒数を示します。デフォルト値は60秒です。

Threads=true | false

アプリケーションがマルチスレッドかどうかを指定します。デフォルト値はfalseです。アプリケーションがマルチスレッドである場合、設定はtrueです。

プリコンパイラでのOracle XAの使用

カーソルは、Oracle XAアプリケーションで使用する場合はトランザクションの存続期間のみ有効です。明示的カーソルは、トランザクションが開始した後にオープンし、コミットまたはロールバックの前にクローズする必要があります。

プリコンパイラとのインタフェースでは、次の2つのオプションがあります。

- デフォルトのデータベースでのプリコンパイラの使用

- 指定されたデータベースでのプリコンパイラの使用

この項の例では、プリコンパイラPro*C/C++を使用しています。

デフォルトのデータベースでのプリコンパイラの使用

デフォルトのデータベースでプリコンパイラにインタフェースするには、オープン文字列で使用されるDB=db_nameフィールドが存在しないことを確認してください。このフィールドが存在しない場合は、デフォルトの接続が指定されます。プロセスごとに1つのデフォルト接続のみが使用できます。

次に、デフォルトのPro*C/C++接続を識別するオープン文字列の例を示します。

ORACLE_XA+SqlNet=maildb+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/logs

DB=db_nameが存在せず、空のデータベースID文字列であることを示しています。

SQL文の構文は次のようになります。

EXEC SQL UPDATE Emp_tab SET Sal = Sal*1.5;

指定されたデータベースでのプリコンパイラの使用

指定されたデータベースでプリコンパイラにインタフェースするには、オープン文字列にDB=db_nameフィールドを含めます。参照するすべてのデータベースは、対応するオープン文字列で指定した同一のdb_nameを参照する必要があります。

アプリケーションには、デフォルト・データベースの他に、名前を指定されたデータベースが1つ以上含まれることがあります。たとえば、あるデータベースで従業員の給与を更新し、別のデータベースでその従業員の部門番号(DEPTNO)を、第3のデータベースでその従業員の管理者を更新するとします。トランザクション・マネージャに例15-2のようなオープン文字列を構成します。

例15-2 オープン文字列構成のサンプル

ORACLE_XA+DB=MANAGERS+SqlNet=SID1+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/xalog
ORACLE_XA+DB=PAYROLL+SqlNet=SID2+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/xalog
ORACLE_XA+SqlNet=SID3+ACC=P/username/password
+SesTM=10+LogDir=/usr/local/xalog

例15-2の最後のオープン文字列にDB=db_nameフィールドはありません。

アプリケーション・サーバー・プログラムでは、次のような宣言を入力します。

EXEC SQL DECLARE PAYROLL DATABASE;
EXEC SQL DECLARE MANAGERS DATABASE;

ここでも、デフォルトの接続(DBフィールドを含まない3番目のオープン文字列に対応)には宣言は必要ありません。

更新を実行するときは、次に示すような文を入力します。

EXEC SQL AT PAYROLL UPDATE Emp_Tab SET Sal=4500 WHERE Empno=7788;
EXEC SQL AT MANAGERS UPDATE Emp_Tab SET Mgr=7566 WHERE Empno=7788;
EXEC SQL UPDATE Emp_Tab SET Deptno=30 WHERE Empno=7788;

最後の文は、デフォルトのデータベースを参照しているためAT句はありません。

Oracle Databaseプリコンパイラのリリース1.5.3以上では、次に示す例のように、AT句に文字ホスト変数を使用できます。

EXEC SQL BEGIN DECLARE SECTION;
DB_NAME1 CHARACTER(10);
DB_NAME2 CHARACTER(10);
EXEC SQL END DECLARE SECTION;
...
SET DB_NAME1 = 'PAYROLL'
SET DB_NAME2 = 'MANAGERS'
...
EXEC SQL AT :DB_NAME1 UPDATE...
EXEC SQL AT :DB_NAME2 UPDATE...

注意:
XAアプリケーションでは、xa_openを介して作成された以外の接続を作成しないでください。XA以外の接続で実行されるすべての作業は、グローバル・トランザクションの範囲から外れることになり、個別にコミットする必要があります。

OCIでのOracle XAの使用

Oracle XAライブラリを使用するOracle Call Interfaceアプリケーションでは、リソース・マネージャにログインするためにOCISessionBeginをコールしないでください。ログインは、TPMを介して行うようにしてください。そのようなアプリケーションでは、関数xaoSvcCtxを実行して、リソース・マネージャへのアクセスに必要なサービス・コンテキスト構造体を取得できます。

環境ハンドルをOCI関数に渡す必要があるアプリケーションでは、そのハンドルを検索するためにxaoEnvもコールする必要があります。

アプリケーション・サーバーでは同時に複数のOracle DatabaseのRMをオープンできるため、適切なサービス・コンテキストを取得するためには適切な引数を使用して関数xaoSvcCtxをコールする必要があります。

参照:
『Oracle Call Interfaceプログラマーズ・ガイド』

Oracle XAを使用したトランザクション制御の管理

XAライブラリを使用する場合、トランザクションは、トランザクションをコミットまたはロールバックするSQL文によっては制御されません。制御は、トランザクションを開始および終了するTMに受け入れられるAPIによって行われます。表15-2に示したXAライブラリ・サブプログラムではなく、表15-6に示したTXインタフェースなど、トランザクション・マネージャにより提供されるAPIをコールします。

TMは、通常、XAインタフェースを介してトランザクションを制御します。このインタフェースには、表15-2に示す関数が含まれています。

表15-6 TXインタフェース関数

TX関数

説明

tx_open

RMにログインします。

tx_close

RMからログアウトします。

tx_begin

トランザクションを開始します。

tx_commit

トランザクションをコミットします。

tx_rollback

トランザクションをロールバックします。

ほとんどのTPMアプリケーションは、アプリケーション・クライアントがサービスを要求し、アプリケーション・サーバーがサービスを提供するというクライアント/サーバー・アーキテクチャを使用しています。「プリコンパイラ・アプリケーションの例」に示す例では、そのようなクライアント/サーバー・モデルを使用しています。サービスとは論理作業単位であり、Oracle DatabaseがRMである場合は、関連する作業単位を実行する一連のSQL文で構成されます。

たとえば、「貸方記入」というサービスが口座番号および貸方記入額を受け取ると、このサービスは、データベース内の特定の表にある情報を更新するSQL文を実行します。さらに、サービスはその他のサービスを要求することもあります。たとえば、「振替」サービスの場合は、「貸方記入」および「借方記入」にサービスを要求します。

通常、アプリケーション・クライアントは、トランザクション内で作業を実行するためにアプリケーション・サーバーにサービスを要求します。ただし、一部のTPMシステムでは、アプリケーション・クライアント自身がローカルにサービスを提供できます。「プリコンパイラ・アプリケーションの例」に示すとおり、トランザクション制御文は、クライアントまたはサーバーのどちらの側でも記述できます。

複数のプロセスを同一のトランザクションに参加させるために、TPMは参加プロセス間でトランザクション情報が伝達できる通信APIを提供しています。通信APIの例として、RPC、疑似RPC関数、送信/受信関数があります。

主要ベンダーが異なる通信関数をサポートしているため、次の例では、通信APIを汎用化するために通信疑似関数tpm_serviceを使用しています。

X/Openの準備段階の仕様には、通信関数を提供する代替方法がいくつか取り入れられています。主要TPMベンダーでは、これらの代替方法を1つ以上はサポートしています。

プリコンパイラ・アプリケーションの例

次の例は、プリコンパイラ・アプリケーションを示しています。アプリケーション・サーバーがTPM固有の方法でRMシステムにログインしているとします。例15-3に、アプリケーション・サーバーによって開始されるトランザクションを示します。

例15-3 アプリケーション・サーバーによって開始されるトランザクション

/***** Client: *****/
tpm_service("ServiceName");              /*Request Service*/

/***** Server: *****/
ServiceName()
{
<get service specific data>
tx_begin();                             /* Begin transaction boundary */
EXEC SQL UPDATE ...;

/* This application server temporarily becomes */
/* a client and requests another service. */

tpm_service("AnotherService");
tx_commit();                             /* Commit the transaction */
<return service status back to the client>
}

例15-4に、アプリケーション・クライアントによって開始されるトランザクションを示します。

例15-4 アプリケーション・クライアントによって開始されるトランザクション

/***** Client: *****/
tx_begin();                            /* Begin transaction boundary */
tpm_service("Service1");
tpm_service("Service2");
tx_commit();                           /* Commit the transaction */

/***** Server: *****/
Service1()
{
<get service specific data>
EXEC SQL UPDATE ...;
<return service status back to the client>
}
Service2()
{
<get service specific data>
EXEC SQL UPDATE ...;
...
<return service status back to client>
}

プリコンパイラまたはOCIアプリケーションのTPMアプリケーションへの移行

既存のプリコンパイラまたはOCIアプリケーションを、Oracle XAライブラリを使用するTPMアプリケーションに移行するには、次の手順に従います。

1. アプリケーション・クライアントがアプリケーション・サーバーにサービスを要求できるように、アプリケーションを「サービス」のフレームワークに再編成します。TPMには、アプリケーションでtx_open関数およびtx_close関数を使用するように要求するTPMと、ログインおよびログオフを暗黙的に実行するTPMがあります。
オープン文字列にSqlNetパラメータを指定しないと、アプリケーションはデフォルトのOracle Netドライバを使用します。このため、ORACLE_HOMEおよびORACLE_SID環境変数を正しく定義して、アプリケーション・サーバーを立ち上げる必要があります。これは、TPMに固有の方法で行われます。これを行う方法の詳細は、TPMベンダーのマニュアルを参照してください。

2. アプリケーションで正規の接続文および切断文を置き換えます。たとえば、接続文EXEC SQL CONNECT(プリコンパイラの場合)またはOCISessionBegin、OCIServerAttachおよびOCIEnvCreate(OCIの場合)をtx_openで置き換えます。切断文EXEC SQL COMMIT/ROLLBACK WORK RELEASE(プリコンパイラの場合)またはOCISessionEnd/OCIServerDetach(OCIの場合)をtx_closeで置き換えます。

3. アプリケーションで、グローバル・トランザクションの正規のコミット文またはロールバック文を置き換え、トランザクションを明示的に開始します。
たとえば、tx_commit/tx_rollbackによってCOMMIT/ROLLBACK文のEXEC SQL COMMIT/ROLLBACK WORK(プリコンパイラの場合)またはOCITransCommit/OCITransRollback(OCIの場合)を置き換え、tx_beginをコールすることによってトランザクションを開始します。

注意:
前述の例は、ローカル・トランザクションではなくグローバル・トランザクションにのみ該当します。ローカル・トランザクションは、Oracle APIでコミットまたはロールバックする必要があります。

4. アプリケーションで、トランザクションを終了する前にフェッチ状態をリセットします。一般的には、release_cursor=noを使用します。release_cursor=yesは、文が1回しか実行されないことが確実なときにのみ使用します。

表15-7に、プリコンパイラまたはOCIアプリケーションをTPMアプリケーションに移行するときに、正規のOracle Database文を置き換えるTPM関数を示します。

表15-7 TPM用に置き換える文

正規のOracle Database文

TPM関数

CONNECTuser/password

tx_open(暗黙の可能性あり)

トランザクションの暗黙的な開始

tx_begin

SQL

SQLを実行するサービス

COMMIT

tx_commit

ROLLBACK

tx_rollback

切断

tx_close(暗黙の可能性あり)

Oracle XAライブラリ・スレッド・セーフティの管理

スレッドをサポートするトランザクション・モニターを使用する場合は、Oracle XAライブラリを使用してスレッド・セーフなアプリケーションを作成できます。ただし、注意が必要な問題がいくつかあります。

制御のスレッド(またはスレッド)とは、RMへの一連の接続のことです。スレッド化されていないシステムでは、各プロセスは制御のスレッドとみなされます。これは、各プロセスにはRMへの接続がそれぞれ独自にあり、それぞれが独立したRM表をメンテナンスしているためです。スレッド化されているシステムでは、各スレッドにはRMとの自律型接続があり、プライベートなRM表をメンテナンスします。このプライベートな表はスレッドのそれぞれに対して割り当てる必要があり、またスレッドが終了したときは(異常終了であっても)割当てを解除する必要があります。

注意:
Oracle Databaseでは、データベースにアクセスする各スレッドに独自の接続が必要です。

内容は次のとおりです。

- オープン文字列でのスレッドの指定

- Oracle XAのスレッドにおける制限事項

オープン文字列でのスレッドの指定

xa_open文字列では、Threads=句が指定されます。TMでスレッドを使用できるようにするには、この句をtrueに指定する必要があります。デフォルトはfalseです。ほとんどの場合、スレッドはTMによって作成され、アプリケーションはスレッドがいつ作成されたのか認識しません。このため、サービス・コンテキストは、TMアプリケーション用に作成される各サービス内のスタック上に割り当てることをお薦めします。そのサービス内でOracle Database関連のコールを実行する前に、xaoSvcCtx関数をコールして初期化済のOCIサービス・コンテキストを取得する必要があります。このコンテキストをサービス内でOCIコールに使用できます。

Oracle XAのスレッドにおける制限事項

スレッドを使用するときは、次の制限事項が適用されます。

- アプリケーション・スレッドがそれぞれいつ開始されるかが明示的にトランザクション・モニターに通知されないかぎり、トランザクション・モニター上でアプリケーション・サーバー・プロセスの一部として実行されるPro*またはOCIコードをスレッド化することはできません。通常、これは、TMベンダーが提供する特別なCコンパイラを使用して実現されます。

- Pro*文EXEC SQL ALLOCATEおよびEXEC SQL USEはサポートされません。このため、スレッド化が使用可能であるときは、埋込みSQL文を非XA接続にまたがって使用することはできません。

- プロセスの1つのスレッドがXAを介してOracle Databaseに接続した場合、そのプロセスの他のすべてのスレッドもXAを介してOracle Databaseに接続する必要があります。1つのスレッドでEXEC SQL CONNECTを介して接続し、他のスレッドでxa_openを介して接続することはできません。

DBMS_XAパッケージの使用

PL/SQLアプリケーションは、DBMS_XAパッケージとともにOracle XAライブラリを使用できます。このパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例15-5では、1つ目のPL/SQLセッションがトランザクションを開始しますがコミットせず、2つ目のセッションがトランザクションを再開し、3つ目のセッションがコミットします。3つのセッションはすべてHRスキーマに接続されます。

例15-5 DBMS_XAパッケージの使用

REM Session 1 starts a transaction and does some work.
DECLARE
rc  PLS_INTEGER;
oer PLS_INTEGER;
xae EXCEPTION;
BEGIN
rc  := DBMS_XA.XA_START(DBMS_XA_XID(123), DBMS_XA.TMNOFLAGS);

IF rc!=DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('ORA-' || oer || ' occurred, XA_START failed');
RAISE xae;
ELSE DBMS_OUTPUT.PUT_LINE('XA_START(new xid=123)     OK');
END IF;

UPDATE employees SET salary=salary*1.1 WHERE employee_id = 100;
rc  := DBMS_XA.XA_END(DBMS_XA_XID(123), DBMS_XA.TMSUSPEND);

IF rc!=DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('ORA-' || oer || ' occurred, XA_END failed');
RAISE xae;
ELSE DBMS_OUTPUT.PUT_LINE('XA_END(suspend xid=123)   OK');
END IF;

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE
('XA error('||rc||') occurred, rolling back the transaction ...');
rc := DBMS_XA.XA_END(DBMS_XA_XID(123), DBMS_XA.TMSUCCESS);
rc := DBMS_XA.XA_ROLLBACK(DBMS_XA_XID(123));

IF rc != DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('XA-'||rc||', ORA-' || oer ||
' XA_ROLLBACK does not return XA_OK');
raise_application_error(-20001, 'ORA-'||oer||
' error in rolling back a failed transaction');
END IF;

raise_application_error(-20002, 'ORA-'||oer||
' error in transaction processing, transaction rolled back');
END;
/
SHOW ERRORS
DISCONNECT

REM Session 2 resumes the transaction and does some work.
DECLARE
rc  PLS_INTEGER;
oer PLS_INTEGER;
s   NUMBER;
xae EXCEPTION;
BEGIN
rc  := DBMS_XA.XA_START(DBMS_XA_XID(123), DBMS_XA.TMRESUME);

IF rc!=DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('ORA-' || oer || ' occurred, xa_start failed');
RAISE xae;
ELSE DBMS_OUTPUT.PUT_LINE('XA_START(resume xid=123)  OK');
END IF;

SELECT salary INTO s FROM employees WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('employee_id = 100, salary = ' || s);
rc  := DBMS_XA.XA_END(DBMS_XA_XID(123), DBMS_XA.TMSUCCESS);

IF rc!=DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('ORA-' || oer || ' occurred, XA_END failed');
RAISE xae;
ELSE DBMS_OUTPUT.PUT_LINE('XA_END(detach xid=123)    OK');
END IF;

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE
('XA error('||rc||') occurred, rolling back the transaction ...');
rc := DBMS_XA.XA_END(DBMS_XA_XID(123), DBMS_XA.TMSUCCESS);
rc := DBMS_XA.XA_ROLLBACK(DBMS_XA_XID(123));

IF rc != DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('XA-'||rc||', ORA-' || oer ||
' XA_ROLLBACK does not return XA_OK');
raise_application_error(-20001, 'ORA-'||oer||
' error in rolling back a failed transaction');
END IF;

raise_application_error(-20002, 'ORA-'||oer||
' error in transaction processing, transaction rolled back');
END;
/
SHOW ERRORS
DISCONNECT

REM Session 3 commits the transaction.
DECLARE
rc  PLS_INTEGER;
oer PLS_INTEGER;
xae EXCEPTION;
BEGIN
rc  := DBMS_XA.XA_COMMIT(DBMS_XA_XID(123), TRUE);

IF rc!=DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('ORA-' || oer || ' occurred, XA_COMMIT failed');
RAISE xae;
ELSE DBMS_OUTPUT.PUT_LINE('XA_COMMIT(commit xid=123)  OK');
END IF;

EXCEPTION
WHEN xae THEN
DBMS_OUTPUT.PUT_LINE
('XA error('||rc||') occurred, rolling back the transaction ...');
rc := DBMS_XA.XA_ROLLBACK(DBMS_XA_XID(123));

IF rc != DBMS_XA.XA_OK THEN
oer := DBMS_XA.XA_GETLASTOER();
DBMS_OUTPUT.PUT_LINE('XA-'||rc||', ORA-' || oer ||
' XA_ROLLBACK does not return XA_OK');
raise_application_error(-20001, 'ORA-'||oer||
' error in rolling back a failed transaction');
END IF;

raise_application_error(-20002, 'ORA-'||oer||
' error in transaction processing, transaction rolled back');
END;
/
SHOW ERRORS
DISCONNECT
QUIT

XAアプリケーションのトラブルシューティング

内容は次のとおりです。

- Oracle XAトレース・ファイルへのアクセス

- インダウトまたはペンディングのOracle XAトランザクションの管理

- SYSアカウント表を使用したOracle XAトランザクションの監視

Oracle XAトレース・ファイルへのアクセス

Oracle XAライブラリでは、すべてのエラーおよびトレース情報がトレース・ファイルに記録されます。この情報は、XAエラー・コードを補足するときに役立ちます。たとえばxa_open障害が発生したとき、その原因として、オープン文字列が正しくなかったか、Oracle Databaseインスタンスの検索が正常に実行されなかったか、またはログイン認可が正常に実行されなかったかを示します。

トレース・ファイル名はxa_db_namedate.trcです。db_nameはオープン文字列のフィールドDB=db_nameで指定したデータベース名で、dateは情報がトレース・ファイルに記録された日付です。オープン文字列でDB=db_nameを指定しない場合、自動的にデフォルトでNULLになります。

たとえば、xa_NULL06022005.trcは、2005年6月2日に作成されたトレース・ファイルを示しています。RMがオープンされたときに、DBフィールドがオープン文字列に指定されていませんでした。ファイル名xa_Finance12152004.trcは、2004年12月15日に作成されたトレース・ファイルを示しています。RMがオープンされたときに、DBフィールドはオープン文字列で「Finance」と指定されていました。

注意:
オープン文字列に同一のDBフィールドおよびLogDirフィールドを持つ複数のOracle XAライブラリRMは、同じ日に発生したすべてのトレース情報を同じトレース・ファイルに記録します。

トレース・ファイルに次の内容が含まれているとします。

1032.12345.2:  ORA-01017:  invalid username/password;  logon denied
1032.12345.2:  xaolgn:  XAER_INVAL;  logon denied

表15-8に、各要素の意味を示します。

表15-8 サンプル・トレース・ファイルの内容

文字列

説明

1032

情報が記録された時刻。

12345

プロセスID(PID)。

2

リソース・マネージャID

xaolgn

モジュール名

XAER_INVAL

XA標準での指定に従って戻されたエラー

ORA-01017

戻されたOracle Database情報

内容は次のとおりです。

- xa_open文字列DbgFl

- トレース・ファイルの位置

xa_open文字列DbgFl

通常、XAトレース・ファイルはエラーが検出された場合にのみオープンされます。xa_open文字列DbgFlは、XAライブラリに関する詳細を記録するトレース機能を提供します。デフォルト値は0(ゼロ)です。次の組合せのいずれかに設定できます。

- 0x1: XAインタフェース内の各サブプログラムの入口および出口をトレースできます。この値は、TPモニターがどのXAコールを作成し、どのトランザクション識別子を生成しているかを正確に調べるときに役立ちます。

- 0x2: 他の非公開XAライブラリ・プログラムへの入口および出口をトレースできます。通常、これはOracle Database開発者用の機能です。

- 0x4: OCIに対する専用コールのように、XAライブラリが作成する他の様々な関心のあるコールをトレースできます。通常、これはOracle Database開発者用の機能です。

注意:
各フラグはub4の独立ビットであるため、複数のフラグから出力を取得するには、フラグの値の組合せを設定する必要があります。

トレース・ファイルの位置

XAアプリケーションでは、トレース・ファイルの位置が次のアルゴリズムに従って判別されます。

1. オープン文字列で指定されているLogDirディレクトリ。

2. オープン文字列にLogDirを指定しないと、Oracle XAアプリケーションは(Oracleホームがアクセス可能な場合は)次のディレクトリにトレース・ファイルを作成しようとします。

- %ORACLE_HOME%\rdbms\trace(Windowsの場合)

- $ORACLE_HOME/rdbms/log(LinuxおよびUNIXの場合)

3. Oracle XAアプリケーションでは、Oracleホームの位置を判別できない場合、トレース・ファイルは現在の作業ディレクトリに作成されます。

インダウトまたはペンディングのOracle XAトランザクションの管理

インダウト・トランザクションまたはペンディング・トランザクションとは、準備はできているがデータベースに対してコミットされていないトランザクションです。一般的に、TPMシステムが提供するTMは、インダウト・トランザクションまたはペンディング・トランザクションの障害を解決し、リカバリします。次の状況では、DBAがインダウト・トランザクションをオーバーライドする必要がある場合があります。

- 他のトランザクションが必要とするデータをロックしている場合。

- 適切な時間の経過後も解決されない場合。

前述のような状況でインダウト・トランザクションをオーバーライドする方法の詳細、およびインダウト・トランザクションをコミットまたはロールバックするかどうかを決定する方法の詳細は、TPMのマニュアルを参照してください。

SYSアカウント表を使用したOracle XAトランザクションの監視

Oracle DatabaseのSYSアカウントには次のビューがあり、正規のOracle DatabaseアプリケーションおよびOracle XAアプリケーションによって生成されたトランザクションが含まれています。

- DBA_PENDING_TRANSACTIONS

- V$GLOBAL_TRANSACTION

- DBA_2PC_PENDING

- DBA_2PC_NEIGHBORS

Oracle XAアプリケーションによって生成されたトランザクションの場合は、次に示す列情報がDBA_2PC_NEIGHBORS表に適用されます。

- DBID列は常にxa_orcl

- DBUSER_OWNER列は常にdb_namexa.oracle.com

db_nameは、オープン文字列で常にDB=db_nameと指定されることに注意してください。オープン文字列にこのフィールドを指定しないと、この列の値はOracle XAアプリケーションが生成するトランザクションについてはNULLxa.oracle.comになります。

たとえば、次のSQL文を使用すると、Oracle XAアプリケーションによって生成されたインダウト・トランザクションの詳細情報を取得できます。

SELECT *
FROM DBA_2PC_PENDING p, DBA_2PC_NEIGHBORS n
WHERE p.LOCAL_TRAN_ID = n.LOCAL_TRAN_ID
AND n.DBID = 'xa_orcl';

別の方法として、TPMが使用するフォーマットIDがわかっている場合は、DBA_PENDING_TRANSACTIONSまたはV$GLOBAL_TRANSACTIONSを使用できます。DBA_PENDING_TRANSACTIONSでは準備済トランザクションの両方のリストが提供されますが、V$GLOBAL_TRANSACTIONSでは、すべてのアクティブなグローバル・トランザクションのリストが提供されます。

Oracle XAの問題および制限事項

内容は次のとおりです。

- Oracle XAアプリケーションでのデータベース・リンクの使用

- Oracle XAアプリケーションでのトランザクション・ブランチの管理

- Oracle Real Application Clusters(Oracle RAC)でのOracle XAの使用

- SQLに基づくOracle XAの制限事項

- その他の制限事項

Oracle XAアプリケーションでのデータベース・リンクの使用

Oracle XAアプリケーションは、次の制限事項に違反しないかぎり、データベース・リンク経由で他のOracle Databaseインスタンスにアクセスできます。

- 共有サーバー構成を使用する必要があります。
トランザクション処理モニター(TPM)は、共有サーバーを使用してOracle Database Aへの接続をオープンします。データベース・リンクに必要なオペレーティング・システム・ネットワーク接続は、専用サーバー・プロセスではなくディスパッチャによってオープンされます。このため、様々なサービスやスレッドでトランザクションを操作できます。

この制限事項が満たされていない場合、XAトランザクション内でデータベース・リンクを使用すると、専用サーバー・プロセスと他方のOracle Database Bの間にオペレーティング・システム・ネットワーク接続が作成されます。このネットワーク接続は専用サーバー・プロセス間で移動できないため、データベースAのこの専用サーバー・プロセスから連結解除することはできません。データベース・リンクを介してデータベースBにアクセスするときに、ORA-24777エラーが戻されます。

- アクセスする他のデータベースは、別のOracle Databaseである必要があります。

この制限事項が満たされている場合、Oracle Databaseはデータベース・リンクを許可し、トランザクション・プロトコルを他のOracle Databaseインスタンスに伝播(準備、ロールバックおよびコミット)します。

共有サーバー構成を使用できない場合は、リモート・データベースにEXEC SQL AT構文を使用してPro*C/C++アプリケーション経由でアクセスします。

init.oraパラメータOPEN_LINKS_PER_INSTANCEは、移行可能なオープン・データベース・リンク接続の数を指定します。これらのdblink接続は、トランザクションのコミット後に接続をキャッシュできるように、XAトランザクションによって使用されます。接続を作成したユーザーがトランザクションも作成した場合、別のトランザクションがデータ・リンク接続を使用できます。このパラメータは、1つのセッションにおけるリモート・データベースへの同時オープン接続の最大数(データベース・リンクを含む)を指定するinit.oraパラメータOPEN_LINKSとは異なります。OPEN_LINKSパラメータは、XAアプリケーションには適用できません。

Oracle XAアプリケーションでのトランザクション・ブランチの管理

同じグローバル・トランザクション内の複数のOracle Databaseトランザクション・ブランチには、密結合または疎結合のどちらの方法も使用できます。トランザクション・ブランチが密結合の場合は、ロックを共有できます。そのため、あるトランザクション・ブランチでのCOMMIT前更新は、同じグローバル・トランザクションに属する他のブランチで参照可能です。疎結合トランザクション・ブランチの場合、ブランチはロックを共有せず、他のブランチでの更新を認識しません。

密結合ブランチの場合、Oracle Databaseは文を実行する前にDXロックを取得します。システムが文の実行前にロックを取得しないため、疎結合トランザクション・ブランチの同時実行性が増します。デメリットは、すべてのトランザクション・ブランチが2フェーズ・コミットを実行する必要があることです。XAの1フェーズ最適化は使用できません。

表15-9に、密結合ブランチと疎結合ブランチのトレードオフを示します。

表15-9 密結合および疎結合トランザクション・ブランチ

属性

密結合ブランチ

疎結合ブランチ

2フェーズ・コミット

読取り専用最適化

[全ブランチについて準備、最後のブランチについてコミット]

2フェーズ

[全ブランチについて準備およびコミット]

シリアライズ

データベース・コール

なし

Oracle Real Application Clusters(Oracle RAC)でのOracle XAの使用

Oracle Database 11gリリース1では、XAトランザクションは複数のOracle RACインスタンスにまたがって、XAを使用するすべてのアプリケーションでOracle RAC環境を活用し、アプリケーションの可用性とスケーラビリティを拡張できるようになりました。

注意:
分散トランザクションと組み合せた外部プロシージャ・コールアウトはサポートされません。

内容は次のとおりです。

- GLOBAL_TXN_PROCESSES初期化パラメータ

- Oracle RACでのトランザクション・ブランチの管理

- Oracle RACでのDTPサービスを使用したインスタンス・リカバリの管理

- Oracle RACのXIDのグローバル一意性

- 密結合と疎結合

GLOBAL_TXN_PROCESSES初期化パラメータ

初期化パラメータGLOBAL_TXN_PROCESSESは、各Oracle RACインスタンスのGTXnバックグラウンド・プロセス数を指定します。デフォルト値は1です。

分散トランザクションが複数のOracle RACインスタンスにまたがる場合、このパラメータはクラスタ全体でデフォルト値のままとします。これにより、Oracle RACインスタンス全体にわたって実行される作業単位は、リソースを共有し、単一のトランザクションとして機能します(つまり、作業単位は密結合となります)。また、クラスタ内の任意のノードへの2フェーズ・コミット要求の送信も可能となります。

参照:
GLOBAL_TXN_PROCESSESの詳細は、『Oracle Databaseリファレンス』を参照してください。

Oracle RACでのトランザクション・ブランチの管理

注意:
このトピックは、次のいずれかが当てはまる場合に適用されます。

- 初期化パラメータGLOBAL_TXN_PROCESSESはすべてのOracle RACインスタンスの初期化ファイルのデフォルト値でない。

- Oracle XAアプリケーションが以前に連結解除されたトランザクションのブランチを再開または結合 する。

Oracle Databaseでは、様々なインスタンスがOracle RACの異なるトランザクション・ブランチで操作できます。たとえば、ノード1がブランチAで操作し、ノード2がブランチBで操作できます。Oracle Database 11gリリース1より前は、トランザクション・ブランチが異なるインスタンスにある場合は疎結合であり、ロックを共有しませんでした。この場合、Oracle Databaseでは、様々なアプリケーション・スレッドの異なる作業単位が、リソースを共有しない個別エンティティとして処理されました。

また、複数のインスタンスが1つのトランザクション・ブランチで操作する場合もあります。たとえば、次のように1つのトランザクションがノード1およびノード2にあるとします。

ノード1

1. xa_start

2. SQL操作

3. xa_end (SUSPEND)

ノード2

1. xa_start (RESUME)

2. xa_prepare

3. xa_commit

4. xa_end

直前の順序では、ノード2は物理的に異なるノード(ノード1)にあるブランチを再開しないため、Oracle Databaseではエラーが戻されます。

Oracle Database 11gリリース1より前のリリースでは、Oracle RACで密結合を実現する方法として分散トランザクション処理(DTP)サービス、つまりカーディナリティ(1)によって、ロード・バランシングが有効かどうかに関係なくすべての密結合ブランチが確実に同じインスタンスに配置されるサービスを使用していました。中間層コンポーネントは、常に1つのOracle RACインスタンスにマップする共通の論理データベース・サービス名を使用して、Oracle Databaseをアドレス指定しました。データベース・インスタンスの物理特性は、データベース・サービスの中間名リゾルバによって隠されました。DTPサービスを使用すると、密結合グローバル・トランザクションの参加者はすべて1つのインスタンス上でブランチを作成できました。

Oracle Database 11gリリース1では、密結合ブランチでのXAトランザクションのサポートにDTPサービスは不要になりました。デフォルトでは、異なるOracle RACインスタンスにある密結合ブランチは密結合のままとなります。つまり、Oracle RACインスタンス全体でロックとリソースを共有します。

たとえば、DTPサービスを使用すると、次の一連のアクションが同じインスタンス上で発生します。

1. xa_start

2. SQL操作

3. xa_end (SUSPEND)

4. xa_start (RESUME)

5. SQL操作

6. xa_prepare

7. xa_commitまたはxa_rollback

さらに、それぞれが同じDTPサービスでOracle RMをアドレス指定する場合は、複数の密結合ブランチが同じインスタンスにあります。

クラスタのインスタンスをすべて活用するには、分散トランザクションを管理する各ノードに1つ以上、複数のDTPサービスを作成します。グローバル分散トランザクションのブランチは、すべて同じインスタンスに存在します。そのため、Oracle RACクラスタのすべてのインスタンスおよびノードを利用して多数の分散XAトランザクションのロード・バランシングを実行し、アプリケーションのスループットを最大化できます。

参照:
Real Application Clusters構成で分散トランザクションを管理する方法は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください。

Oracle RACでのDTPサービスを使用したインスタンス・リカバリの管理

Oracle Database 10gリリース2より前は、Oracle RACでの障害検出とフェイルオーバーおよびフェイルバックのトリガーはTMで実行されていました。インダウト・トランザクションに関する情報をDBA_2PC_PENDINGに確実に伝播させるために、TMではインダウト・トランザクションの解決に進む前にxa_recoverを起動する必要がありました。インスタンスに障害が発生した場合、XAクライアント・ライブラリはSYS.DBMS_XA.DIST_TXN_SYNCプロシージャを実行して障害を起こしたインスタンスのUNDOセグメントがリカバリされたことを確認するまで、他のインスタンスにフェイルオーバーできませんでした。Oracle Database 10gリリース2では、処理中のトランザクションに関する十分な情報がTMにあれば、このようにxa_recoverを起動するという要件はありません。

注意:
Oracle Database 9gリリース2以降のリリースでは、xa_recoverはリモート・サイトで分散データ操作言語(DML)文が完了するまで待機する必要があります。

Oracle RACでDTPサービスを使用すると、次のようなメリットがあります。

- インスタンス障害の検出が自動化されます。

- インスタンスのフェイルオーバーとフェイルバックが自動化されます。インスタンスに障害が発生すると、このインスタンスで管理されているDTPサービスが他のインスタンスにフェイルオーバーします。このフェイルオーバーにより、クライアントは強制的に再接続されますが、サービスの論理名は変わりません。フェイルオーバーは自動的で、管理者が介入する必要はありません。管理者は、サービス再配置文を使用してフェイルバックを実行できますが、フェイルバック関連のリカバリはすべてデータベース・サーバー内で自動的に処理されます。

- クライアントではなくOracle Databaseがインスタンスのリカバリを実行できます。データベースでは、中間層TMの関与を必要とせずに、他のインスタンスによって準備されたトランザクションの状態を判別できます。

参照:

- インスタンス・リカバリ方法は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください。

- Oracle RACでのサービスおよび分散トランザクション処理の詳細は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください。

Oracle RACのXIDのグローバル一意性

Oracle Database 11gリリース1より前のリリースでは、Oracle RACデータベースでは指定されたXIDがクラスタ内のXAトランザクションで一意であるかどうかは判断できません。

たとえば、Oracle RACインスタンス1にXID Fmt(x).Tx(1).Br(1)、Oracle RACインスタンス2に別のXID Fmt(x).Tx(1).Br(1)があるとします。XIDがOracle RACインスタンス間で一意ではありませんが、どちらもブランチを開始してSQLを実行できます。

Oracle Database 11gリリース1では、Oracle RACデータベースはOracle RACインスタンス間の重複するXIDを検出し、重複したXIDを持つブランチが開始しないようにしています。

参照:
Oracle RACでのサービスおよび分散トランザクション処理の詳細は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください。

密結合と疎結合

同じグローバル・トランザクション内の複数のOracle Databaseトランザクション・ブランチには、密結合または疎結合のどちらの方法も使用できます(詳細は、「Oracle XAアプリケーションでのトランザクション・ブランチの管理」を参照してください)。通常、結合のタイプはxa_open文字列のLoose_Couplingフィールドで定義します(詳細は、表15-5を参照してください)。ただし、Oracle RACの実行時に、ブランチが別のOracle RACインスタンスにある場合は、Loose_Coupling=falseであってもこれらは疎結合です。

参照:
Oracle RACでのサービスおよび分散トランザクション処理の詳細は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください。

SQLに基づくOracle XAの制限事項

この項では、次のSQL操作に関する制限事項について説明します。

- ロールバックおよびコミット

- DDL文

- セッション状態

- EXEC SQL

ロールバックおよびコミット

グローバル・トランザクションの進行状況の調整および監視はトランザクション・マネージャが行うため、グローバル・トランザクションのロールバックまたはコミットを独立して行うOracle Database固有の文をアプリケーションに入れないでください。ただし、ローカル・トランザクションではロールバックおよびコミットを使用できます。

グローバル・トランザクションの途中で、プリコンパイラ・アプリケーションにEXEC SQL ROLLBACK WORKを使用しないでください。同様に、OCIアプリケーションでは、OCITransRollbackまたはバージョン7で同等のorolを実行しないでください。グローバル・トランザクションをロールバックするには、tx_rollbackをコールします。

同様に、グローバル・トランザクションの途中で、プリコンパイラ・アプリケーションにEXEC SQL COMMIT WORK文を使用しないでください。OCIアプリケーションでは、OCITransCommitまたはバージョン7で同等のocomを実行しないでください。たとえば、tx_commitまたはtx_rollbackを使用して、グローバル・トランザクションを終了してください。

DDL文

CREATE TABLEなどのデータ定義言語(DDL)文は、暗黙的なコミットを意味するためOracle XAアプリケーションでは実行できません。

セッション状態

Oracle Databaseでは、セッション状態が複数のTPMサービス間で有効であることを保証しません。たとえば、あるTPMサービスがセッション変数(グローバル・パッケージ変数など)を更新した場合、同じグローバル・トランザクションの一部として実行している別のTPMサービスにはこの変更が認識されないことがあります。セーブポイントは1つのTPMサービス内で使用してください。アプリケーションが、別のTPMサービスで作成されたセーブポイントを参照しないようにしてください。同様に、アプリケーションが、別のTPMサービスで実行されたカーソルからフェッチしないようにしてください。

EXEC SQL

- 接続および切断にEXEC SQL文を使用しないでください。つまり、EXEC SQL CONNECT、EXEC SQL COMMIT WORK RELEASEまたはEXEC SQL ROLLBACK WORK RELEASEを使用しないでください。

- EXEC SQL SET TRANSACTIONはトランザクションの最初の操作である必要があります。
トランザクションに複数のブランチがある場合、1つのブランチのみにトランザクション名を設定することができます。それ以外の場合は、エラーORA-1453が発生します。

その他の制限事項

- Oracle XAとゲートウェイの両方を同じセッションで使用できません。

- Oracle Databaseでは、関連付けの移行はサポートされません(関連付けの移行とは、トランザクション・マネージャが中断中のブランチ関連付けを別のブランチで再開する手段です)。

- XAのオプションの機能である非同期XAコールはサポートされません。

- TRANSACTIONS初期化パラメータを、グローバル・トランザクションの同時実行予測数に設定します。初期化パラメータOPEN_LINKS_PER_INSTANCEは、移行可能なオープン・データベース・リンク接続の数を指定します。これらのデータベース・リンク接続は、トランザクションのコミット後に接続をキャッシュできるように、XAトランザクションによって使用されます。

参照:
「Oracle XAアプリケーションでのデータベース・リンクの使用」

- スレッドごとのxa_openコールの最大数は32です。

- TPモニター・ベースのXAアプリケーションを構築する場合、リンク・ラインで、TPモニター・ライブラリ(ax_regおよびax_unreg記号を定義する)をOracle Databaseクライアント共有ライブラリの前に指定する必要があります。プラットフォームで共有ライブラリがサポートされていない場合、またはリンカーがリンク・ライン内のライブラリの順序を区別しない場合は、Oracle Databaseの非共有クライアント・ライブラリを使用します。これらのリンク制限は、XAの動的登録(Oracle XAスイッチxaoswd)を使用する場合のみ適用できます。

16 パブリッシュ・サブスクライブ・モデルでのアプリケーションの開発

この章では、パブリッシュ・サブスクライブ・モデルでアプリケーションを開発する方法について説明します。

内容は次のとおりです。

- パブリッシュ・サブスクライブ・モデルの概要

- パブリッシュ・サブスクライブのアーキテクチャ

- パブリッシュ・サブスクライブの概念

- パブリッシュ・サブスクライブ・メカニズムの例

パブリッシュ・サブスクライブ・モデルの概要

データベースは企業内の最も重要な情報資源であるため、この役割を補完するために、Oracleでは、企業の情報配信およびメッセージ交換用にパブリッシュ・サブスクライブ・ソリューションを作成しました。

ネットワーキング・テクノロジおよびネットワーキング製品によって、多数のコンピュータ、アプリケーションおよびユーザーにまたがる高度な接続が可能です。これらの環境では、疎結合で自律的に動作する分散システムに非同期通信を提供することが重要であり、ネットワーク障害に強い操作性が要求されます。この要件は、メッセージ機能、メッセージ指向ミドルウェア(MOM)、メッセージ・キューイング、パブリッシュ・サブスクライブなどの特長を持つ様々なミドルウェア製品によって満たされています。

パブリッシュ・サブスクライブ・パラダイムを介して通信するアプリケーションには、受信者を明示的に指定したり意図された受信者を知らせなくても、メッセージを発行できる送信アプリケーション(パブリッシャ)が必要です。同様に、受信アプリケーション(サブスクライバ)は、サブスクライバが登録しているメッセージのみを受信する必要があります。

この送信者と受信者の切離しは、通常、パブリッシャとサブスクライバの間に存在して間接的なレベルとして機能するエンティティによって実現されます。このエンティティが、サブジェクトまたはチャネルを表すキューです。図16-1に、パブリッシュおよびサブスクライブの機能を示します。

図16-1 Oracleのパブリッシュ・サブスクライブの機能

サブスクライバは、あるキューにエンキューされたメッセージに関心を示すことによって、また、サブジェクト・ベースまたはコンテンツ・ベースのルールをフィルタとして使用することによって、キューをサブスクライブします。この結果、指定されたキューに一連のルールベースのサブスクリプションが対応付けられます。

実行時、パブリッシャは様々なキューにメッセージを転送します。次に、キュー(基礎となるインフラストラクチャの配信メカニズム)は、様々なサブスクリプションに一致したメッセージを該当するサブスクライバに配信します。

パブリッシュ・サブスクライブのアーキテクチャ

Oracle Databaseには、データベースに対応したパブリッシュ・サブスクライブのメッセージ機能をサポートする機能が含まれています。

- データベース・イベント

- Oracle Advanced Queuing

- クライアント通知

データベース・イベント

データベース・イベントは、データベース・イベントを公開するための宣言定義、検出およびこれらのイベントの実行時の発行をサポートします。この機能によって、イベント駆動方式でエンドユーザーに情報を能動的に発行し、従来のプル型の情報アクセスの方法を補足することができます。

参照:
『Oracle Database PL/SQL言語リファレンス』

Oracle Advanced Queuing

Oracle Advanced Queuing(AQ)では、キュー・ベースのパブリッシュ・サブスクライブ・パラダイムがサポートされます。データベース・キューは、メッセージの永続的な格納場所として機能し、キューを基にしたパブリッシュおよびサブスクライブが可能になります。ルール・エンジンおよびサブスクリプション・サービスが、設定された関心事項に基づいて、受信者にメッセージを動的に送付します。これによって、送信者と受信者の間のアドレス関係が切り離され、送信者と受信者間での明示的なメッセージ・アドレッシングを補足することができます。

参照:
『Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド』

クライアント通知

クライアント通知は、メッセージに関心を持つサブスクライバに対するメッセージの非同期配信をサポートします。これによって、データベース・クライアントは特定のキューに対する関心を登録し、そのようなキューで発行が発生した場合に通知を受け取ることができます。データベース・クライアントへのメッセージの非同期配信は、情報を取得するために使用される従来のポーリングとは対照的な技法です。

参照:
『Oracle Call Interfaceプログラマーズ・ガイド』

パブリッシュ・サブスクライブの概念

キュー

キューは、名前付きの関心対象サブジェクトをサポートするエンティティです。キューは永続または非永続(軽量)の特性を持ちます。

永続キューは、メッセージの永続的なコンテナとして機能します。メッセージは、遅延付き高信頼モードで配信されます。

非永続(軽量)キューの基礎となるインフラストラクチャでは、公開されたメッセージを接続クライアントに対して最高で1回送信します。

エージェント

パブリッシャおよびサブスクライバは、内部的にはエージェントとして表されます。

エージェントは、サブスクリプションを介してキューに関心を示す持続的で論理的なサブスクライブ・エンティティです。エージェントには、関連するサブスクリプション、アドレス、メッセージの配信モードなどのプロパティがあります。この意味では、エージェントはパブリッシャまたはサブスクライバの電子的なプロキシです。

クライアント

クライアントは、一時的な物理エンティティです。クライアントの属性には、クライアント・プログラムが実行される物理プロセス、ノード名、クライアント・アプリケーション・ロジックが含まれます。単一のエージェントにかわって複数のクライアントが動作する場合もあります。認証されている場合は、同一のクライアントが複数のエージェントにかわって動作できます。

キューでのルール

キューでのルールは、メッセージ形式属性またはメッセージ・ヘッダー属性に関する一連の事前定義済演算子を使用する条件式として指定されます。各キューには、そのキューが示すメッセージの構造を記述したメッセージ内容形式が対応付けられています。メッセージ形式は、構造化されていなくても(RAW)、正しく定義された構造体(ADT)であってもかまいません。これによって、サブジェクト・ベースおよびコンテンツ・ベースの両方のサブスクリプションが可能です。

サブスクライバ

サブスクライバ(エージェント)は、ルールを使用してキューにサブスクリプションを指定できます。サブスクライバは永続的であり、カタログに格納されます。

データベース・イベント発行フレームワーク

データベースは、重要な情報公開元を表します。イベント・フレームワークは、データベース・イベント発行の宣言定義ができるように提案されたものです。これらの事前定義済イベントが発生すると、このフレームワークがイベントを検出および公開します。これによって、パブリッシュ・サブスクライブ機能の一部として、エンドユーザーに対してイベント駆動方式によるアクティブな情報配信が可能になります。

登録

登録は、エージェントにかわって動作する所定のクライアントによって対応付けられた配信情報のプロセスです。エージェントとクライアントの区別に関連して、サブスクリプションと登録の間には重要な区別があります。

サブスクリプションは、エージェントによる特定のキューへの関心を示します。配信の場所および方法は指定しません。配信情報は、クライアントに対応付けられた物理的なプロパティで、論理エージェント(サブスクライバ)の一時的な発現です。エージェントにかわって動作する特定のクライアント・プロセスは、配信を行う 場所を示すホストとポート、および配信の方法を示すコールバックを対応付けることによって、配信情報を登録します。

メッセージの公開

パブリッシャは、適切なキューイング・インタフェースを使用して、キューにメッセージを公開します。インタフェースは、キューが実装されているモデルに依存することがあります。たとえば、エンキュー・コールは、メッセージの公開を表します。

ルール・エンジン

指定されたキューにメッセージが転送または公開されると、ルール・エンジンはそのキューに関して定義されたすべてのルールから、公開されたメッセージと一致する一連の候補となるルールを取得します。

サブスクリプション・サービス

指定されたキュー上の候補ルールのリストに応じて、候補ルールに一致する一連のサブスクライバを評価できます。次に、このサブスクリプション・リストに対応する一連のエージェントが決定され、通知されます。

ポスト

キューは、登録されたすべてのクライアントに対して、公開された該当メッセージを通知します。この概念はポストと呼ばれます。関心があるすべてのクライアントに通知が必要な場合、キューは、登録されたすべてのクライアントにメッセージをポストします。

メッセージの受信

サブスクライバは、次のメカニズムのいずれかを介して、メッセージを受信できます。

- サブスクライバにかわって動作するクライアント・プロセスが、登録メカニズムを使用してコールバックを指定します。その後、メッセージがサブスクライバのサブスクリプションと一致する場合、ポスト・メカニズムによってコールバックが非同期に起動されます。メッセージ・コンテンツは、コールバック関数に渡される場合があります(非永続キューの場合のみ)。

- サブスクライバにかわって動作するクライアント・プロセスが、登録メカニズムを使用してコールバックを指定します。その後、ポスト・メカニズムによってコールバック関数が非同期に起動されますが、完全なメッセージ・コンテンツは渡されません。コールバック関数はクライアントへの通知として機能し、これに続いてプル型の方法でメッセージ・コンテンツを取得します(永続的キューの場合のみ)。

- サブスクライバにかわって動作するクライアント・プロセスが、周期的またはその他の方法で適宜キューから単純にメッセージを取得します。メッセージの遅延がある場合、エンド・クライアントへの非同期配信は行われません。

パブリッシュ・サブスクライブ・メカニズムの例

この例では、データベース・イベント、クライアント通知、AQがどのように連携してパブリッシュ・サブスクライブを実装するかを示します。

- ユーザー・スキーマの下で、パブリッシュ・サブスクライブ・メカニズムをサポートするために必要なすべてのオブジェクトを持つpubsubを作成します。このコードでは、エージェントsnoopは、ログイン・イベントで公開されるメッセージをサブスクライブします。ユーザーpubsubがAQ機能を使用するには、AQ_ADMINISTRATOR_ROLE権限と、DBMS_AQおよびDBMS_AQADMのEXECUTE権限が必要です。

Rem ------------------------------------------------------
REM create queue table for persistent multiple consumers:
Rem ------------------------------------------------------

Rem  Create or replace a queue table
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
Queue_table        =>  'Pubsub.Raw_msg_table',
Multiple_consumers =>   TRUE,
Queue_payload_type =>  'RAW',
Compatible         =>  '8.1');
END;
/
Rem ------------------------------------------------------
Rem  Create a persistent queue for publishing messages:
Rem ------------------------------------------------------

Rem  Create a queue for logon events
BEGIN
DBMS_AQADM.CREATE_QUEUE(
Queue_name     =>   'Pubsub.Logon',
Queue_table    =>   'Pubsub.Raw_msg_table',
Comment        =>   'Q for error triggers');
END;
/

Rem ------------------------------------------------------
Rem  Start the queue:
Rem ------------------------------------------------------

BEGIN
DBMS_AQADM.START_QUEUE('pubsub.logon');
END;
/

Rem ------------------------------------------------------
Rem  define new_enqueue for convenience:
Rem ------------------------------------------------------

CREATE OR REPLACE PROCEDURE New_enqueue(
Queue_name      IN VARCHAR2,
Payload         IN RAW ,
Correlation     IN VARCHAR2 := NULL,
Exception_queue IN VARCHAR2 := NULL)
AS

Enq_ct     DBMS_AQ.Enqueue_options_t;
Msg_prop   DBMS_AQ.Message_properties_t;
Enq_msgid  RAW(16);
Userdata   RAW(1000);

BEGIN
Msg_prop.Exception_queue := Exception_queue;
Msg_prop.Correlation := Correlation;
Userdata := Payload;

DBMS_AQ.ENQUEUE(Queue_name, Enq_ct, Msg_prop, Userdata, Enq_msgid);
END;
/

Rem ------------------------------------------------------
Rem  add subscriber with rule based on current user name,
Rem  using correlation_id
Rem ------------------------------------------------------

DECLARE
Subscriber Sys.Aq$_agent;
BEGIN
Subscriber := sys.aq$_agent('SNOOP', NULL, NULL);
DBMS_AQADM.ADD_SUBSCRIBER(
Queue_name         => 'Pubsub.logon',
Subscriber         => subscriber,
Rule               => 'CORRID = ''HR'' ');
END;
/

Rem ------------------------------------------------------
Rem  create a trigger on logon on database:
Rem ------------------------------------------------------

Rem  create trigger on after logon:
CREATE OR REPLACE TRIGGER pubsub.Systrig2
AFTER LOGON
ON DATABASE
BEGIN
New_enqueue('Pubsub.Logon', HEXTORAW('9999'), Dbms_standard.login_user);
END;
/

- サブスクリプションが作成された後、次の手順として、クライアントがコールバック関数を使用した通知を登録します。これにはOracle Call Interface(OCI)を使用します。次のコードは、登録に必要な手順を実行します。セッション・ハンドルの割当ておよび初期化を行う最初の手順は、例をわかりやすくするために、ここでは省略します。

ub4 namespace = OCI_SUBSCR_NAMESPACE_AQ;

/* callback function for notification of logon of user 'HR' on database: */

ub4 notifySnoop(ctx, subscrhp, pay, payl, desc, mode)
dvoid *ctx;
OCISubscription *subscrhp;
dvoid *pay;
ub4 payl;
dvoid *desc;
ub4 mode;
{
printf("Notification : User HR Logged on\n");
}

int main()
{
OCISession *authp = (OCISession *) 0;
OCISubscription *subscrhpSnoop = (OCISubscription *)0;

/*****************************************************
Initialize OCI Process/Environment
Initialize Server Contexts
Connect to Server
Set Service Context
******************************************************/

/* Registration Code Begins */

/* Each call to initSubscriptionHn allocates
and Initialises a Registration Handle */

initSubscriptionHn(    &subscrhpSnoop,    /* subscription handle */
"ADMIN:PUBSUB.SNOOP", /* subscription name */
/* <agent_name>:<queue_name> */
(dvoid*)notifySnoop); /* callback function */

/*****************************************************
The Client Process does not need a live Session for Callbacks
End Session and Detach from Server
******************************************************/

OCISessionEnd ( svchp,  errhp, authp, (ub4) OCI_DEFAULT);

/* detach from server */
OCIServerDetach( srvhp, errhp, OCI_DEFAULT);

while (1)     /* wait for callback */
sleep(1);

}

void initSubscriptionHn (subscrhp,
subscriptionName,
func)

OCISubscription **subscrhp;
char* subscriptionName;
dvoid * func;
{

/* allocate subscription handle: */

(void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)subscrhp,
(ub4) OCI_HTYPE_SUBSCRIPTION,
(size_t) 0, (dvoid **) 0);

/* set subscription name in handle: */

(void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
(dvoid *) subscriptionName,
(ub4) strlen((char *)subscriptionName),
(ub4) OCI_ATTR_SUBSCR_NAME, errhp);

/* set callback function in handle: */

(void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
(dvoid *) func, (ub4) 0,
(ub4) OCI_ATTR_SUBSCR_CALLBACK, errhp);

(void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
(dvoid *) 0, (ub4) 0,
(ub4) OCI_ATTR_SUBSCR_CTX, errhp);

/* set namespace in handle: */

(void) OCIAttrSet((dvoid *) *subscrhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
(dvoid *) &namespace, (ub4) 0,
(ub4) OCI_ATTR_SUBSCR_NAMESPACE, errhp);

checkerr(errhp, OCISubscriptionRegister(svchp, subscrhp, 1, errhp,

OCI_DEFAULT));
}

ユーザーHRがデータベースにログインすると、クライアントに通知され、コールバック関数notifySnoopが起動されます。

17 識別コード・パッケージの使用

識別コード・パッケージは、電子製品コード(EPC)などOracle Databaseの各種製品コードや識別コード間の格納、取出し、エンコード、デコード、および翻訳を行うツールや手法を提供する、Oracle Databaseの機能です。また、データ型、メタデータ表およびビュー、およびEPC標準RFIDタグまたは新型RFIDタグをユーザー表に格納するためのPL/SQLパッケージも提供します。

識別コード・パッケージによって、Oracle Databaseは、EPCコード体系の認識、効率的な記憶域およびコンポーネント・レベルのEPCデータの取得、EPCglobal Tag Data Translation 1.0(TDT)標準に準拠することが可能になります。TDT標準は、各種EPC RFIDタグ表現間のデコード、エンコード、および翻訳の方法について定義したものです。

このパッケージはまた、EPC標準には含まれていない既存のコード体系をアプリケーションで使用するための拡張可能なフレームワークを提供します。このフレームワークにより、Oracle Databaseは古いシステムにも、今後EPC標準に含まれる可能性のある、進化する識別コードにも対応可能となります。

また、識別コード・パッケージでは、最初にエンコード・カテゴリを登録してエンコード・タイプを登録し、次にエンコード・タイプに関連付けられた新しいコンポーネントを登録して、開発者は独自の識別コードを作成できます。

内容は次のとおりです。

- 識別の概念

- 識別コード・パッケージの概要

- 識別コード・パッケージの使用

- 識別コード・パッケージ・タイプ

- DBMS_MGD_ID_UTLパッケージ

- 識別コード・メタデータ表およびビュー

- 電子製品コード(EPC)の概念

- Oracle Database Tag Data Translationスキーマ

識別の概念

データベース・オブジェクトMGD_IDが定義され、独自に作成した既存の識別コードとEPC標準の識別コードの使用が可能になりました。EPCの概念の概要は、「電子製品コード(EPC)の概念」を参照してください。MGD_IDオブジェクトは、特定のカテゴリが属するベース・コード・オブジェクトとして、または、EPCカテゴリ、NASAカテゴリなど数多くのカテゴリのRFIDタグの型としての役割を果します。各カテゴリには、タグ表現構造およびそのコンポーネントを定義する一連のタグ・スキームまたは文書が存在します。EPCカテゴリにおいて、様々なエンコーディングのタイプ(EPC標準バージョン1.1で定義)を表すコード体系(SGTIN-64、SGTIN-96、GID-96など)の定義に必要なメタデータは、デフォルトではデータベースにロードされます。ユーザーは、図17-1で示すように独自のカテゴリとスキームのエンコーディングの定義が可能であり、データベースにもロードできます。

図17-1 RFIDコード・カテゴリおよびそのスキーム

MGD_IDオブジェクトには、2つの属性、category_id、および名前/値ペアのコンポーネントで構成されるリストが含まれます。MGD_IDオブジェクトが格納されると、オブジェクトの作成時にタグ表現をこれらのコンポーネントの名前/値ペアに解析する必要があります。

EPC標準バージョン1.1は、既存で既知のコード体系に依存しない汎用識別子(GID)タイプを1つ、EAN.UCC仕様に基づくDomain Identifierのタイプを5つ定義します。さらに、米国防総省(USDOD)の識別タイプも定義します。EAN.UCCに基づく識別タイプは、serialized global trade identification number(SGTIN)、serial shipping container code(SSCC)、serialized global location number(SGLN)、global returnable asset identifier(GRAI)、およびglobal individual asset identifier(GIAI)の5つです。

ビットレベルのエンコーディングを1つのみ持つGID以外の識別タイプはすべて、長さが64ビットか96ビットかによって、それぞれ2つのエンコーディングがあります。合計すると、EPCタグには13種類の異なる標準エンコーディングが存在することになります。さらに、タグURIおよび純粋な識別表現などバイナリ以外の表現でのエンコーディングも可能です。

各EPCエンコーディングには、独自の構造と編成があります。表17-1を参照してください。EPCエンコーディング構造フィールド名は、識別コード・パッケージAPIのparameter_listパラメータの名前/値ペアに関連しています。たとえば、SGTIN-64では、構造フィールド名はFilter Value、Company Prefix Index、Item Reference、およびSerial Numberです。

表17-1 EPCエンコーディングの一般的な構造

エンコーディング名

ヘッダー長(ビット)

フィールド名(parameter_listの名前/値ペア)およびフィールド長(ビット)

GID-96

8

General Manager Number (8)、Object Class (24)、Serial Number (36)

SGTIN-64

2

Filter Value (3)、Company Prefix Index (14)、Item Reference (20)、Serial Number (25)

SGTIN-96

8

Filter Value (3)、Partition (3)、Company Prefix (20-40)、Item Reference (24-4)、Serial Number (38)

SSCC-64

8

Filter Value (3)、Company Prefix Index (14)、Serial Reference (39)

SSCC-96

8

Filter Value (3)、Partition (3)、Company Prefix (20-40)、Serial Reference (38-18)、Unallocated (24)

SGLN-64

8

Filter Value (3)、Company Prefix Index (14)、Location Reference (20)、Serial Number (19)

SGLN-96

8

Filter Value (3)、Partition (3)、Company Prefix (20-40)、Location Reference (21-1)、Serial Number (41)

GRAI-64

8

Filter Value (3)、Company Prefix Index (14)、Asset Type (20)、Serial Number (19)

GRAI-96

8

Filter Value (3)、Partition (3)、Company Prefix (20-40)、Asset Type (24-4)、Serial Number (38)

GIAI-64

8

Filter Value (3)、Company Prefix Index (14)、Individual Asset Reference (39)

GIAI-96

8

Filter Value (3)、Partition (3)、Company Prefix (20-40)、Individual Asset Reference (62-42)

USDOD-64

8

Filter Value (2)、Government Managed Identifier (30)、Serial Number (24)

USDOD-96

8

Filter Value (4)、Government Managed Identifier (48)、Serial Number (36)

EPCglobalは11個のタグ・スキーム(GID-96、SGTIN-64、SGTIN-96など)を定義しています。これらのスキームにはそれぞれ多くの表現がありますが、現在最も頻繁に使用されているのはBINARY、TAG_URI、およびPURE_IDENTITYです。たとえば、SGTIN-64の情報は次のように表現できます。

BINARY: 1001100000000000001000001110110001000010000011111110011000110010
PURE_IDENTITY:  urn:epc:id:sgtin:0037000.030241.1041970
TAG_URI: urn:epc:tag:sgtin-64:3.0037000.030241.1041970
LEGACY: gtin=00037000302414;serial=1041970
ONS_HOSTNAME: 030241.0037000.sgtin.id.example.com

これらの表現にはタグに関するすべての情報が含まれているものがありますが(BINARYおよびTAG_URI)、他の表現には一部の情報しか含まれていません(PURE_IDENTITY)。そのため、タグをTAG_URIからPURE_IDENTITY表現へ翻訳することはできますが、フィルタ値などの詳細情報がないかぎり、逆への翻訳は実行できません。

EPCglobalは、様々なEPC RFIDタグ表現間のデコード、エンコードおよび翻訳を定義したTag Data Translation 1.0(TDT)標準をリリースしました。デコーディングは、ある表現をフィールド/値ペアに解析することを意味し、エンコーディングはこれらのフィールドから表現を再構成することを意味します。翻訳とは、ある表現をデコーディングし、すぐに別の表現にエンコーディングすることを意味します。TDTはそれぞれがスキームを表す一連のXMLファイルを使用してこの情報を定義します。たとえば、SGTIN-64スキームは、バイナリと純粋な識別など様々なSGTIN-64表現間でのデコード、エンコードおよび翻訳を定義します。EPCglobal TDTスキーマの詳細は、EPCglobal Tag Data Translationの仕様を参照してください。

TDT仕様の主な機能は、同じXMLスキーマを使用してすべてのEPCスキームを定義できることです。この方法により、RFIDアプリケーションがパーサー、エンコーダ、およびトランスレータの記述に使用するEPCメタデータを定義する標準的な方法が作成されます。TDT仕様に従ってアプリケーションを記述した場合、そのアプリケーションから一連のEPCタグ・スキームの更新と、メタデータに従ったアクションの変更が可能である必要があります。

Oracle Databaseメタデータ構造はTDT標準と類似していますが、同一なものではありません。EPCglobal TDT仕様に合せるには、Oracle RFIDパッケージですべてのTDT互換スキームを取り込み、定義された汎用のOracle Databaseメタデータにシームレスに翻訳できる必要があります。詳細は、表17-4のEPC_TO_ORACLE関数を参照してください。

フィールドからのタグ表現の再構築、つまり、タグ・データの事前定義済の表現へのエンコーディングは、MGD_ID.format関数を使用して簡単に実行できます。同様に、タグ表現のMGD_IDオブジェクトへのデコーディングおよびこれらのオブジェクトのタグ表現へのエンコーディングも、MGDID.translate関数を使用して簡単に実行できます。詳細は、表17-3のFORMATメンバー関数およびTRANSLATE静的関数を参照してください。

EPCglobal TDT標準は強力で拡張性も高いため、Oracle RFID標準メタデータはTDT仕様と密接に関連しています。実際のOracle Database TDT XMLスキーマは、「Oracle Database Tag Data Translationスキーマ」を参照してください。開発者は、このOracle Database TDT XMLスキーマを参照し、独自のタグ構造を定義できます。

図17-2に、Oracle Database Tag Data Translationマークアップ言語スキーマ図を示します。

図17-2 Oracle Database Tag Data Translationマークアップ言語スキーマ図

タグ・データ翻訳XMLのトップレベル要素は「スキーム」です。それぞれのスキームは、様々なタグ・エンコーディング表現またはレベルを定義します。SGTIN-64およびGID-96は、タグ・コード体系の例です。また、BINARYまたはPURE_IDENTITYは、これらのスキーム内のレベルの例です。各レベルには、様々な表現のフィールドへの解析方法を定義した一連のオプション、および追加の作業が必要なフィールドからの値の導出方法を定義したルールがあります。ルールには、外部表参照または解析された他のフィールドとの連結などがあります。詳細は、EPCGlobalのタグ翻訳仕様を参照してください。

識別コード・パッケージの概要

識別コード・パッケージは、現在のRFIDタグとサポートされるエンコーディング・タイプのEPCビット・エンコーディングの標準ファミリ、および現在のEPC標準には含まれていない進化するタグ・エンコーディングの両方をサポートする、拡張可能なフレームワークを提供します。

識別コード・パッケージは次のADTを定義します。

- MGD_ID -- 次の項目を定義します(詳細は、表17-2のMGD_ID ADTを参照してください)。

- category_idおよびcomponentsの2つの属性。

- RFIDタグを表現する識別コード・タイプ・オブジェクトを構成するための4つのMGD_IDコンストラクタ関数。

- これらのADTを操作する一連のメンバー・サブプログラム。

「識別コード・パッケージの使用」は、これらのADTとメンバー関数の使用方法について説明しています。

「識別コード・パッケージ・タイプ」と「DBMS_MGD_ID_UTLパッケージ」では、これらのADTと一連のユーティリティ・サブプログラムの参照情報を簡単に説明しています。参照情報の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- MGD_ID_COMPONENT - コンポーネント名を識別するcomp_nameと、コンポーネント値を識別するcomp_valueの2つの属性を定義します。

- MGD_ID_COMPONENT_VARRAY - MGD_IDCOMPONENT型の要素を最大128個格納できる配列型を定義します。この配列型は、コンポーネントのリストがある識別コード・タイプ・オブジェクトを作成するための2つのコンストラクタ関数で使用します。

識別コード・パッケージは、事前定義済のEPC_ENCODING_CATEGORY encoding_category属性定義とサポートされるエンコーディング・タイプのビット・エンコーディング構造を提供することで、EPC仕様バージョン1.1をサポートします。この情報は、提供されるエンコーディング・メタデータ・ビューMGD_USR_ID_CATEGORYとMGD_USR_ID_SCHEME、読取り専用ビューMGD_ID_CATEGORYとMGD_ID_SCHEME、およびその基礎となる表MGD_ID_CATEGORY_TAB、MGD_ID_SCHEME_TABとMGD_ID_XML_VALIDATORでメタ情報として格納されます。詳細は、次の項およびファイルを参照してください。

- 「電子製品コード(EPC)の概念」は、EPC仕様バージョン1.1の製品コードおよびコード体系ファミリについて説明しています。

- 「識別コード・メタデータ表およびビュー」は、識別コード・メタ表とビューの構造、および様々なRFIDタグを解釈するために識別コード・パッケージがメタデータをどのように使用するかについて説明しています。

- mgdmeta.sqlファイルは、EPC_ENCODING_CATEGORYカテゴリおよびそれぞれの特定のコード体系のメタ表データを示します。

何千ものRFIDタグをユーザー表のMGD_ID列型の列に格納した後に、この列に索引を作成することで、問合せのパフォーマンスが向上します。詳細は、次の項を参照してください。

- 「MGD_ID列型のメンバー関数を使用したファンクション索引の作成」は、MGD_ID ADTのメンバー関数を使用したファンクション索引またはビットマップ・ファンクション索引の作成について説明しています。

識別コード・パッケージは様々なユーティリティ・サブプログラムから構成されるユーティリティ・パッケージを提供します。詳細は、次の項を参照してください。

- 「識別コード・パッケージ・タイプ」および「DBMS_MGD_ID_UTLパッケージ」は、各メンバー・サブプログラムについて説明しています。プロキシ情報の設定および削除には、プロキシ・ユーティリティを使用します。メタデータ・ユーティリティは、カテゴリIDの取得、カテゴリのタグ・スキームのリフレッシュ、カテゴリのタグ・スキームの削除、およびタグ・スキームの検証に使用できます。変換ユーティリティは、標準のEPCglobal Tag Data Translation(TDT)のOracle Database TDTファイルへの翻訳に使用します。

識別コード・パッケージは拡張可能であり、新規または進化するRFIDタグ固有の識別コード・タイプを独自に作成できます。エンコーディング・タイプに応じて、識別コード・タイプ、catagory_id属性値、およびコンポーネント構造が定義可能です。詳細は、次の項を参照してください。

- 「識別コードの新規カテゴリの作成」では、独自の識別コードの作成方法について説明しています。その手順では、まずエンコーディング・カテゴリを登録し、その後にエンコーディング・カテゴリに関連するスキームを登録します。

- 「識別コード・メタデータ表およびビュー」は、識別コード・メタ表とビューの構造、およびメタデータ表とビューにメタ情報を格納して情報を登録する方法について説明しています。

識別コード・パッケージの使用

内容は次のとおりです。

- MGD_ID ADTを使用したOracle DatabaseへのRFIDタグの格納

- MGD_ID列型のメンバー関数を使用したファンクション索引の構築

- MGD_ID ADT関数の使用

- 識別コードのカテゴリの定義と既存のカテゴリへのコード体系の追加

MGD_ID ADTを使用したOracle DatabaseへのRFIDタグの格納

内容は次のとおりです。

- MGD_ID列型を使用した表の作成と、列へのEPCタグ・エンコーディングの格納

- RFIDタグを表現するMGD_IDオブジェクトの構成

- データベース表へのMGD_IDオブジェクトの挿入

- MGD_ID列型の問合せ

MGD_ID列型を使用した表の作成と、列へのEPCタグ・エンコーディングの格納

RFIDタグを表現する列型としてMGD_IDを使用し、表を作成できます。次に例を示します。

例1.MGD_ID列型の使用

CREATE TABLE Warehouse_info (
Code          MGD_ID,
Arrival_time  TIMESTAMP,
Location      VARCHAR2(256);
...);

SQL*Plusコマンド:

describe warehouse_info;

結果:

Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
CODE                                      NOT NULL MGDSYS.MGD_ID
ARRIVAL_TIME                                       TIMESTAMP(6)
LOCATION                                           VARCHAR2(256)

RFIDタグを表現するMGD_IDオブジェクトの構成

MGD_IDオブジェクトを構成するには、複数の方法があります。

- MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリIDとコンポーネントのリストの受渡し

- MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリID、タグ識別子と追加の必須パラメータのリストの受渡し

- MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリ名、カテゴリ・バージョン(NULLの場合、最新のバージョンを使用)とコンポーネントのリストの受渡し

- MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリ名、カテゴリ・バージョン、タグ識別子と追加の必須パラメータのリストの受渡し

MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリIDとコンポーネントのリストの受渡し

RFIDタグがEPC標準に準拠している場合、そのカテゴリIDとコンポーネントのリストを使用してMGD_IDオブジェクトを作成できます。次に例を示します。

call DBMS_MGD_ID_UTL.set_proxy('example.com', '80');
call DBMS_MGD_ID_UTL.refresh_category('1');
select MGD_ID ('1',
MGD_ID_COMPONENT_VARRAY(
MGD_ID_COMPONENT('companyprefix','0037000'),
MGD_ID_COMPONENT('itemref','030241'),
MGD_ID_COMPONENT('serial','1041970'),
MGD_ID_COMPONENT('schemes','SGTIN-64')
)
) from DUAL;
call DBMS_MGD_ID_UTL.remove_proxy();

@constructor11.sql
.
.
.
MGD_ID ('1', MGD_ID_COMPONENT_VARRAY
(MGD_ID_COMPONENT('companyprefix', '0037000'),
MGD_ID_COMPONENT('itemref', '030241'),
MGD_ID_COMPONENT('serial', '1041970'),
MGD_ID_COMPONENT('schemes', 'SGTIN-64')))
.
.
.

MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリID、タグ識別子と追加の必須パラメータのリストの受渡し

MGD_IDオブジェクトの作成に追加の必須パラメータのリストが存在する場合、このコンストラクタを使用します。次に例を示します。

call DBMS_MGD_ID_UTL.set_proxy('example.com', '80');
call DBMS_MGD_ID_UTL.refresh_category('1');
select MGD_ID('1',
'urn:epc:id:sgtin:0037000.030241.1041970',
'filter=3;scheme=SGTIN-64') from DUAL;
call DBMS_MGD_ID_UTL.remove_proxy();

@constructor22.sql
.
.
.
MGD_ID('1', MGD_ID_COMPONENT_VARRAY(MGD_ID_COMPONENT('filter', '3'),
MGD_ID_COMPONENT('schemes', 'SGTIN-64'),
MGD_ID_COMPONENT('companyprefixlength', '7'),
MGD_ID_COMPONENT('companyprefix', '0037000'),
MGD_ID_COMPONENT('scheme', 'SGTIN-64'),
MGD_ID_COMPONENT('serial', '1041970'),
MGD_ID_COMPONENT('itemref', '030241')))
.
.
.

MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリ名、カテゴリ・バージョン(NULLの場合、最新のバージョンを使用)とコンポーネントのリストの受渡し

カテゴリIDとコンポーネントのリストとともにカテゴリ・バージョンを指定する必要がある場合、このコンストラクタを使用します。次に例を示します。

call DBMS_MGD_ID_UTL.set_proxy('example.com', '80');
call DBMS_MGD_ID_UTL.refresh_category
(DBMS_MGD_ID_UTL.get_category_id('EPC', NULL));
select MGD_ID('EPC', NULL,
MGD_ID_COMPONENT_VARRAY(
MGD_ID_COMPONENT('companyprefix','0037000'),
MGD_ID_COMPONENT('itemref','030241'),
MGD_ID_COMPONENT('serial','1041970'),
MGD_ID_COMPONENT('schemes','SGTIN-64')
)
) from DUAL;
call DBMS_MGD_ID_UTL.remove_proxy();

@constructor33.sql
.
.
.
MGD_ID('1', MGD_ID_COMPONENT_VARRAY
(MGD_ID_COMPONENT('companyprefix', '0037000'),
MGD_ID_COMPONENT('itemref', '030241'),
MGD_ID_COMPONENT('serial', '1041970'),
MGD_ID_COMPONENT('schemes', 'SGTIN-64')
)
)
.
.
.

MGD_IDオブジェクト(SGTIN-64)の構成、およびカテゴリ名、カテゴリ・バージョン、タグ識別子と追加の必須パラメータのリストの受渡し

カテゴリ・バージョンと追加のパラメータのリストが必要な場合、このコンストラクタを使用します。

call DBMS_MGD_ID_UTL.set_proxy('example.com', '80');
call DBMS_MGD_ID_UTL.refresh_category
(DBMS_MGD_ID_UTL.get_category_id('EPC', NULL));
select MGD_ID('EPC', NULL,
'urn:epc:id:sgtin:0037000.030241.1041970',
'filter=3;scheme=SGTIN-64') from DUAL;
call DBMS_MGD_ID_UTL.remove_proxy();

@constructor44.sql
.
.
.
MGD_ID('1', MGD_ID_COMPONENT_VARRAY
(MGD_ID_COMPONENT('filter', '3'),
MGD_ID_COMPONENT('schemes', 'SGTIN-64'),
MGD_ID_COMPONENT('companyprefixlength', '7'),
MGD_ID_COMPONENT('companyprefix', '0037000'),
MGD_ID_COMPONENT('scheme', 'SGTIN-64'),
MGD_ID_COMPONENT('serial', '1041970'),
MGD_ID_COMPONENT('itemref', '030241')
)
)
.
.
.

データベース表へのMGD_IDオブジェクトの挿入

次の例は、表に各MGD_IDオブジェクトと追加の列値を挿入し、WAREHOUSE_INFO表を移入する方法を示しています。

call DBMS_MGD_ID_UTL.set_proxy('example.com', '80');

call DBMS_MGD_ID_UTL.refresh_category
(DBMS_MGD_ID_UTL.get_category_id('EPC', NULL));

INSERT INTO WAREHOUSE_INFO (code, arrival_time, location)
values (MGDSYS.MGD_ID ('EPC',
NULL,
'urn:epc:id:sgtin:0037000.030241.1041970',
null
),
SYSDATE,
'SHELF_123');

INSERT INTO WAREHOUSE_INFO (code, arrival_time, location)
values (MGDSYS.MGD_ID ('EPC',
NULL,
'urn:epc:id:sgtin:0037000.053021.1012353',
null
),
SYSDATE,
'SHELF_456');
INSERT INTO WAREHOUSE_INFO (code, arrival_time, location)
values (MGDSYS.MGD_ID ('EPC',
NULL,
'urn:epc:id:sgtin:0037000.020140.10174832',
null
),
SYSDATE,
'SHELF_1034');

COMMITT;
call DBMS_MGD_ID_UTL.remove_proxy();

MGD_ID列型の問合せ

MGD_ID列型を問い合せるには、3つの方法があります。

- MGD_ID列型を問い合せます。アイテム参照が030241であるすべてのアイテムを検索します。

SELECT location, wi.code.get_component('itemref') as itemref,
wi.code.get_component('serial') as serial
FROM warehouse_info wi WHERE wi.code.get_component('itemref') = '030241';

LOCATION       |ITEMREF   |SERIAL
---------------|----------|----------
SHELF_123      |030241    |1041970

- MGD_ID ADTのメンバー関数を使用して問い合せます。表内のすべてのRFIDタグの純粋な識別表現を選択します。

SELECT wi.code.format(null,'PURE_IDENTITY')
as PURE_IDENTITY FROM warehouse_info wi;

PURE_IDENTITY
-------------------------------------------------------------------------------
urn:epc:id:sgtin:0037000.030241.1041970
urn:epc:id:gid:0037000.053021.1012353
urn:epc:id:sgtin:0037000.020140.10174832

詳細は、「MGD_IDオブジェクトとget_component関数の使用」を参照してください。メンバー関数のリストは表17-3を参照してください。

MGD_ID列型のメンバー関数を使用したファンクション索引の構築

get_componentメンバー関数またはそのバリエーションの簡易関数を使用するファンクション索引を作成し、RFIDタグの特定のコンポーネントの問合せのパフォーマンスを改善できます。次に例を示します。

CREATE INDEX warehouseinfo_idx2
on warehouse_info(code.get_component('itemref'));

また、get_componentメンバー関数またはそのバリエーションの簡易関数を使用するビットマップ・ファンクション索引を作成し、RFIDタグの特定のコンポーネントの問合せのパフォーマンスも改善できます。次に例を示します。

CREATE BITMAP INDEX warehouseinfo_idx3
on warehouse_info(code.get_component('serial'));

MGD_ID ADT関数の使用

MGD_ID ADTには、次のADTで動作するメンバー・サブプログラムが含まれます。詳細は、表17-2のMGD_ID_COMPONENT、MGD_ID_COMPONENT_VARRAYおよびMGD_ID ADTの参照情報を参照してください。MGD_ID ADTの定義およびそのメンバー・サブプログラムについては、mgdtyp.sqlファイルを参照してください。

内容は次のとおりです。

- MGD_IDオブジェクトとget_component関数の使用

- 標準的な表現からのタグ・データの解析

- フィールドからのタグ表現の再構成

- タグ表現間の翻訳

MGD_IDオブジェクトとget_component関数の使用

get_component関数の定義は、次のとおりです。

MEMBER FUNCTION get_component(component_name IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC,

識別コードの各コンポーネントには名前が付けられています。この名前は、コード・タイプを登録する際に定義されます。識別コード・タイプの作成方法の詳細は、「識別コードのカテゴリの定義と既存のカテゴリへのコード体系の追加」を参照してください。

get_component関数は、コンポーネントの名前であるcomponent_nameをパラメータとして取り、識別コードを解析するためにメタデータ表内に登録されたメタデータを使用し、component_nameの名前とコンポーネントを戻します。

get_component関数はSQL問合せで使用できます。たとえば、itemrefという名前のコンポーネントのコーディング済アイテムの現在の場所の検索、つまり、03024のアイテムを参照するすべてのアイテムを検索するとします。コード・タグが「itemref」を1つのコンポーネントとしてエンコーディングしているため、次のSQL問合せを使用できます。

SELECT location,
w.code.get_component('itemref') as itemref,
w.code.get_component('serial')  as serial
FROM   warehouse_info w
WHERE  w.code.get_component('itemref')  = '030241';

LOCATION       |ITEMREF   |SERIAL
---------------|----------|----------
SHELF_123      |030241    |1041970

他のメンバー関数のリストは、表17-3を参照してください。

標準的な表現からのタグ・データの解析

RFIDリーダーは、タグに格納されているビット列を読み取ります。タグ・データと、リーダーID、タイムスタンプなどのその他の情報は、まずエッジ・サーバーで処理および正規化され、事前にフィルタリングされます。その後、多くのアプリケーション・シナリオでは、情報は永続的に格納され後で取得される必要があります。表17-1で示したように、Oracle DatabaseではEPC標準で定義されたコード表現体系が事前に登録されているため、様々なEPCタグのコード構造表現を理解します。これにより、Oracle DatabaseはすべてのEPCコード体系を理解し、様々なタグ表現をフィールドに解析できます。ユーザーは、他のエンコーディング・テクノロジを使用した識別コードの独自のコーディング構造を登録することもできます。このように、システムは拡張可能です。

「識別の概念」で示したとおり、それぞれのEPCGlobalタグ・スキーム(GID-96、SGTIN-64、SGTIN-96など)には様々な表現があります。最も頻繁に使用されるのは、BINARY、TAG_URI、およびPURE_IDENTITYです。

これらの表現にはタグに関するすべての情報が含まれているものがありますが(BINARYおよびTAG_URI)、他の表現には一部の情報しか含まれていません(PURE_IDENTITY)。そのため、タグをTAG_URIからPURE_IDENTITY表現へ翻訳することはできますが、フィルタ値などの詳細情報がないかぎり、逆への翻訳(PURE_IDENTITYからTAG_URIへ)は実行できません。

MGD_IDコンストラクタの1つは、カテゴリ名(EPCなど)、カテゴリ・バージョン、タグ識別子(EPCの場合、以前記述した表現に含まれる識別子である必要があります)、およびタグ表現の解析に必要な追加のパラメータ・リストの4つのフィールドを使用します。たとえば、次のコードはBINARY表現からMGD_IDオブジェクトを作成します。

SELECT MGD_ID
('EPC',
null,
'1001100000000000001000001110110001000010000011111110011000110010',
null
)
AS NEW_RFID_CODE FROM DUAL;

NEW_RFID_CODE(CATEGORY_ID, COMPONENTS(NAME, VALUE))
--------------------------------------------------------------------------------
MGD_ID ('1',
MGD_ID_COMPONENT_VARRAY(MGD_ID_COMPONENT('filter', '3'),
MGD_ID_COMPONENT('schemes', 'SGTIN-64'),
MGD_ID_COMPONENT('companyprefixlength', '7'),
MGD_ID_COMPONENT('companyprefix', '0037000'),
MGD_ID_COMPONENT('companyprefixindex', '1'),
MGD_ID_COMPONENT('serial', '1041970'),
MGD_ID_COMPONENT('itemref', '030241')
)
)

たとえば、次のようにフィルタ値を追加し、タグのTAG_URI表現からコールが実行された場合、同一のオブジェクトが作成されます。

SELECT MGD_ID ('EPC',
null,
'urn:epc:tag:sgtin-64:3.0037000.030241.1041970',
null
)
as NEW_RFID_CODE FROM DUAL;

NEW_RFID_CODE(CATEGORY_ID, COMPONENTS(NAME, VALUE))
--------------------------------------------------------------------------------
MGD_ID ('1',
MGD_ID_COMPONENT_VARRAY (
( MGD_ID_COMPONENT('filter', '3'),
MGD_ID_COMPONENT('schemes', 'SGTIN-64'),
MGD_ID_COMPONENT('companyprefixlength', '7'),
MGD_ID_COMPONENT('companyprefix', '0037000'),
MGD_ID_COMPONENT('serial', '1041970'),
MGD_ID_COMPONENT('itemref', '030241')
)
)

フィールドからのタグ表現の再構成

識別コード・パッケージのその他の便利な機能として、タグ・データを事前定義済の表現にエンコーディングできます。たとえば、倉庫からある在庫を小売業者に送る前に、どの在庫を小売業者に送るかを記述した請求書を送る必要があるとします。請求書は、倉庫から送る純粋な識別URIのリストとなります。WAREHOUSE_INFO表のすべての在庫を送る場合、次の例では必要なURIを構成します。

SELECT wi.code.format (null,'PURE_IDENTITY')
as PURE_IDENTITY FROM warehouse_info wi;

PURE_IDENTITY
--------------------------------------------------------------------------------
urn:epc:id:sgtin:0037000.030241.1041970
urn:epc:id:gid:0037000.053021.1012353
urn:epc:id:sgtin:0037000.020140.10174832

タグ表現間の翻訳

識別コード・パッケージは、タグ表現をMGD_IDオブジェクトにデコードし、これらのオブジェクトをタグ表現にエンコードできます。MGD_ID.translate関数を使用して、この2つの手順を1つにまとめることができます。静的な翻訳により、RFIDタグを1つの表現から別の表現に変換できます。次に例を示します。

SELECT MGD_ID.translate ('EPC',
null,
'urn:epc:id:sgtin:0037000.030241.1041970',
'filter=3;scheme=SGTIN-64',
'BINARY'
)
as BINARY FROM DUAL;

BINARY
--------------------------------------------------------------------------------
1001100000000000001000001110110001000010000011111110011000110010

この例では、バイナリ表現には純粋な識別表現より多くの情報が含まれます。特に、バイナリ表現にはフィルタ値も含まれます。この場合、SGTIN-64とSGTIN-96の区別にスキーム値も指定する必要があります。そのため、翻訳コールを正常に実行するためには、ファンクション・コールにおいて欠落したフィルタのパラメータ情報を提供し、スキーム名を指定する必要があります。

識別コードのカテゴリの定義と既存のカテゴリへのコード体系の追加

内容は次のとおりです。

- 識別コードのカテゴリの作成

- 新規作成したカテゴリへの2つのメタデータ・スキームの追加

識別コードのカテゴリの作成

EPCglobal TDT標準は強力で拡張性も高いため、Oracle Database RFID標準メタデータはTDT仕様と密接に関連しています。そのため、識別コード・パッケージは拡張可能であり、汎用的なメタデータを使用して独自のカテゴリとタグ構造を作成できます。識別コードのカテゴリを作成するには、DBMS_MGD_ID_UTIL.create_category関数を使用します。

たとえば、CONTRACTOR_TAGとEMPLOYEE_TAGの2つの型のタグがあるMGD_SAMPLE_CATEGORYというカテゴリを作成するとします。このカテゴリと2つのメタデータ・スキームを使用する会社では、正社員と契約社員に異なるアクセス権限を付与する必要がある場合があります。そのため、セキュリティ・ソフトウェアはRFIDリーダーにおいて2つの権限の違いを迅速に識別できる必要があります。次のスクリプトは「MGD_SAMPLE_CATEGORY」というカテゴリをカテゴリ・バージョン1.0で作成します。組織名はOracle、URIはhttp://www.oracle.com/mgd/sampleとなります。例は、「新規作成したカテゴリへの2つのメタデータ・スキームの追加」を参照してください。

新規作成したカテゴリへの2つのメタデータ・スキームの追加

続いて、次のようなCONTRACTOR_TAGメタデータ・スキームを作成します。

<?xml version="1.0" encoding="UTF-8"?>
<TagDataTranslation version="0.04" date="2005-04-18T16:05:00Z"
xmlns:xsi="http://www.w3.org/2001/XMLSchema"
xmlns="oracle.mgd.idcode">
<scheme name="CONTRACTOR_TAG" optionKey="1" xmlns="">
<level type="URI" prefixMatch="mycompany.contractor.">
<option optionKey="1" pattern="mycompany.contractor.([0-9]*).([0-9]*)"
grammar="''mycompany.contractor.'' contractorID ''.'' divisionID">
<field seq="1" characterSet="[0-9]*" name="contractorID"/>
<field seq="2" characterSet="[0-9]*" name="divisionID"/>
</option>
</level>
<level type="BINARY" prefixMatch="11">
<option optionKey="1" pattern="11([01]{7})([01]{6})"
grammar="''11'' contractorID divisionID ">
<field seq="1" characterSet="[01]*" name="contractorID"/>
<field seq="2" characterSet="[01]*" name="divisionID"/>
</option>
</level>
</scheme>
</TagDataTranslation>

CONTRACTOR_TAGスキームには、2つのエンコーディング・レベル、つまり2つのタグ表現方法が含まれます。最初のレベルはURI、2つ目のレベルはBINARYです。URI表現は、接頭辞「mycompany.contractor.」で始まり、ピリオドで区切られた2つの数値フィールドが続きます。2つのフィールドの名前はcontractorIDとdivisionIDです。オプション・タグのパターン・フィールドはタグURI表現の解析構造を定義します。grammarフィールドはURI表現の再構成方法を定義します。BINARY表現も同じ方法で理解できます。この表現は接頭辞「01」で始まり、同じ2つのフィールドcontractorIDとdivisionIDが続きます。ここでは、それぞれバイナリ形式となります。このXMLメタデータ構造を指定すると、contractorタグはURI表現およびBINARY表現からデコードされ、結果のフィールドをこれらの表現のいずれかに再度エンコードできます。

EMPLOYEE_TAGスキームも同様に定義され、次のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<TagDataTranslation version="0.04" date="2005-04-18T16:05:00Z"
xmlns:xsi="http://www.w3.org/2001/XMLSchema"
xmlns="oracle.mgd.idcode">
<scheme name="EMPLOYEE_TAG" optionKey="1" xmlns="">
<level type="URI" prefixMatch="mycompany.employee.">
<option optionKey="1" pattern="mycompany.employee.([0-9]*).([0-9]*)"
grammar="''mycompany.employee.'' employeeID ''.'' divisionID">
<field seq="1" characterSet="[0-9]*" name="employeeID"/>
<field seq="2" characterSet="[0-9]*" name="divisionID"/>
</option>
</level>
<level type="BINARY" prefixMatch="01">
<option optionKey="1" pattern="01([01]{7})([01]{6})"
grammar="''01'' employeeID divisionID ">
<field seq="1" characterSet="[01]*" name="employeeID"/>
<field seq="2" characterSet="[01]*" name="divisionID"/>
</option>
</level>
</scheme>
</TagDataTranslation>;

前に作成したカテゴリIDにこれらのスキームを追加するには、DBMS_MGD_ID_UTIL.add_scheme関数を使用します。

次のスクリプトは、MGD_SAMPLE_CATEGORYカテゴリの作成、contractorスキームとemployeeスキームのMGD_SAMPLE_CATEGORYカテゴリへの追加、MGD_SAMPLE_CATEGORYスキームの検証、contractorスキームとemployeeスキームのタグ翻訳のテストを実行します。その後、contractorスキームを削除し、contractorスキームのタグ翻訳をテストします。削除したcontractorスキームについては、予期した例外が戻されることを確認します。employeeスキームの翻訳をテストし、予期した値が返されることを確認してからMGD_SAMPLE_CATEGORYカテゴリを削除します。

--contents of add_scheme2.sql
SET LINESIZE 160
CALL DBMS_MGD_ID_UTL.set_proxy('example.com', '80');
---------------------------------------------------------------------
---CREATE CATEGORY, ADD_SCHEME, REMOVE_SCHEME, REMOVE_CATEGORY-------
---------------------------------------------------------------------
DECLARE
amt          NUMBER;
buf          VARCHAR2(32767);
pos          NUMBER;
tdt_xml      CLOB;
validate_tdtxml VARCHAR2(1042);
category_id  VARCHAR2(256);
BEGIN
-- remove the testing category if it exists
DBMS_MGD_ID_UTL.remove_category('MGD_SAMPLE_CATEGORY', '1.0');
-- create the testing category 'MGD_SAMPLE_CATEGORY', version 1.0
category_id := DBMS_MGD_ID_UTL.CREATE_CATEGORY('MGD_SAMPLE_CATEGORY', '1.0', 'Oracle',
'http://www.oracle.com/mgd/sample');
-- add contractor scheme to the category
DBMS_LOB.CREATETEMPORARY(tdt_xml, true);
DBMS_LOB.OPEN(tdt_xml, DBMS_LOB.LOB_READWRITE);

buf := '<?xml version="1.0" encoding="UTF-8"?>
<TagDataTranslation version="0.04" date="2005-04-18T16:05:00Z"
xmlns:xsi="http://www.w3.org/2001/XMLSchema"
xmlns="oracle.mgd.idcode">
<scheme name="CONTRACTOR_TAG" optionKey="1" xmlns="">
<level type="URI" prefixMatch="mycompany.contractor.">
<option optionKey="1" pattern="mycompany.contractor.([0-9]*).([0-9]*)"
grammar="''mycompany.contractor.'' contractorID ''.'' divisionID">
<field seq="1" characterSet="[0-9]*" name="contractorID"/>
<field seq="2" characterSet="[0-9]*" name="divisionID"/>
</option>
</level>
<level type="BINARY" prefixMatch="11">
<option optionKey="1" pattern="11([01]{7})([01]{6})"
grammar="''11'' contractorID divisionID ">
<field seq="1" characterSet="[01]*" name="contractorID"/>
<field seq="2" characterSet="[01]*" name="divisionID"/>
</option>
</level>
</scheme>
</TagDataTranslation>';

amt := length(buf);
pos := 1;
DBMS_LOB.WRITE(tdt_xml, amt, pos, buf);
DBMS_LOB.CLOSE(tdt_xml);

DBMS_MGD_ID_UTL.ADD_SCHEME(category_id, tdt_xml);

-- add employee scheme to the category
DBMS_LOB.CREATETEMPORARY(tdt_xml, true);
DBMS_LOB.OPEN(tdt_xml, DBMS_LOB.LOB_READWRITE);

buf := '<?xml version="1.0" encoding="UTF-8"?>
<TagDataTranslation version="0.04" date="2005-04-18T16:05:00Z"
xmlns:xsi="http://www.w3.org/2001/XMLSchema"
xmlns="oracle.mgd.idcode">
<scheme name="EMPLOYEE_TAG" optionKey="1" xmlns="">
<level type="URI" prefixMatch="mycompany.employee.">
<option optionKey="1" pattern="mycompany.employee.([0-9]*).([0-9]*)"
grammar="''mycompany.employee.'' employeeID ''.'' divisionID">
<field seq="1" characterSet="[0-9]*" name="employeeID"/>
<field seq="2" characterSet="[0-9]*" name="divisionID"/>
</option>
</level>
<level type="BINARY" prefixMatch="01">
<option optionKey="1" pattern="01([01]{7})([01]{6})"
grammar="''01'' employeeID divisionID ">
<field seq="1" characterSet="[01]*" name="employeeID"/>
<field seq="2" characterSet="[01]*" name="divisionID"/>
</option>
</level>
</scheme>
</TagDataTranslation>';

amt := length(buf);
pos := 1;
DBMS_LOB.WRITE(tdt_xml, amt, pos, buf);
DBMS_LOB.CLOSE(tdt_xml);
DBMS_MGD_ID_UTL.ADD_SCHEME(category_id, tdt_xml);

-- validate the scheme
dbms_output.put_line('Validate the MGD_SAMPLE_CATEGORY Scheme');
validate_tdtxml := DBMS_MGD_ID_UTL.validate_scheme(tdt_xml);
dbms_output.put_line(validate_tdtxml);
dbms_output.put_line('Length of scheme xml is: '||DBMS_LOB.GETLENGTH(tdt_xml));

-- test tag translation of contractor scheme
dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'mycompany.contractor.123.45',
NULL, 'BINARY'));

dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'111111011101101',
NULL, 'URI'));

-- test tag translation of employee scheme
dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'mycompany.employee.123.45',
NULL, 'BINARY'));

dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'011111011101101',
NULL, 'URI'));

DBMS_MGD_ID_UTL.REMOVE_SCHEME(category_id, 'CONTRACTOR_TAG');

-- Test tag translation of contractor scheme. Doesn't work any more.
BEGIN
dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'mycompany.contractor.123.45',
NULL, 'BINARY'));

dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'111111011101101',
NULL, 'URI'));
EXCEPTION
WHEN others THEN
dbms_output.put_line('Contractor tag translation failed: '||SQLERRM);
END;

-- Test tag translation of employee scheme. Still works.
BEGIN
dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'mycompany.employee.123.45',
NULL, 'BINARY'));
dbms_output.put_line(
mgd_id.translate('MGD_SAMPLE_CATEGORY', NULL,
'011111011101101',
NULL, 'URI'));
EXCEPTION
WHEN others THEN
dbms_output.put_line('Employee tag translation failed: '||SQLERRM);
END;

-- remove the testing category, which also removes all the associated schemes
DBMS_MGD_ID_UTL.remove_category('MGD_SAMPLE_CATEGORY', '1.0');
END;
/
SHOW ERRORS;
call DBMS_MGD_ID_UTL.remove_proxy();

@add_scheme3.sql
.
.
.
Validate the MGD_SAMPLE_CATEGORY Scheme
EMPLOYEE_TAG;URI,BINARY;divisionID,employeeID
Length of scheme xml is: 933
111111011101101
mycompany.contractor.123.45
011111011101101
mycompany.employee.123.45
Contractor tag translation failed: ORA-55203: Tag data translation level not found
ORA-06512: at "MGDSYS.DBMS_MGD_ID_UTL", line 54
ORA-06512: at "MGDSYS.MGD_ID", line 242
ORA-29532: Java call terminated by uncaught Java
exception: oracle.mgd.idcode.exceptions.TDTLevelNotFound: Matching level not
found for any configured scheme
011111011101101
mycompany.employee.123.45
.
.
.

識別コード・パッケージ・タイプ

表17-2は識別コード・パッケージADTを示します。

表17-2 識別コード・パッケージADT

ADT名

説明

MGD_ID_COMPONENT ADT

コンポーネントを定義する名前/値ペア属性を指定するデータ型です。

MGD_ID_COMPONENT_VARRAY ADT

データ型を指定します。最大128個のコンポーネントのリストを名前/値属性ペアで指定するデータ型で、識別コード・タイプ・オブジェクトを作成するための2つのコンストラクタ関数で使用されます。

MGD_ID ADT

この識別コードとコンポーネントのリストのコード・カテゴリのカテゴリ識別子を指定する識別コード・タイプを表します。

表17-3はMGD_ID ADTのサブプログラムを示します。

MGD_ID ADTで定義されたサブプログラムに渡されるすべての値と名前は、特に記載のないかぎり、大/小文字を区別しません。大/小文字を保持するには、値を二重引用符で囲みます。

表17-3 MGD_ID ADTサブプログラム

サブプログラム

説明

MGD_IDコンストラクタ関数

識別コード・タイプ・オブジェクトMGD_IDを作成し、それ自体を戻します。

FORMATメンバー関数

MGD_IDコンポーネントを指定した場合の識別コードの表現を戻します。

GET_COMPONENTメンバー関数

MGD_IDコンポーネントの値を戻します。

TO_STRINGメンバー関数

category_idパラメータ値とコンポーネントの名前/値属性ペアを連結します。

TRANSLATE静的関数

識別コードの1つのMGD_ID表現を別のMGD_ID表現に翻訳します。

DBMS_MGD_ID_UTLパッケージ

表17-4はDBMS_MGD_ID_UTLパッケージのユーティリティ・プログラムを示します。

MGD_ID ADTで定義されたサブプログラムに渡されるすべての値と名前は、特に記載のないかぎり、大/小文字を区別しません。大/小文字を保持するには、値を二重引用符で囲みます。

表17-4 DBMS_MGD_ID_UTLパッケージ・ユーティリティ・サブプログラム

サブプログラム

説明

ADD_SCHEMEプロシージャ

既存のカテゴリにタグ・データ翻訳スキームを追加します。

CREATE_CATEGORY関数

カテゴリまたはカテゴリのバージョンを作成します。

EPC_TO_ORACLE関数

EPCglobal Tag Data Translation(TDT)XMLをOracle Database Tag Data Translation XMLに変換します。

GET_CATEGORY_ID関数

カテゴリ名とカテゴリ・バージョンを指定した場合、カテゴリIDを戻します。

GET_COMPONENTS関数

指定したスキームのすべての関連するコンポーネント名をセミコロン(;)で区切って戻します。

GET_ENCODINGS関数

指定したスキームのエンコーディング(フォーマット)のリストをセミコロン(;)で区切って戻します。

GET_JAVA_LOGGING_LEVEL関数

現在のJavaのトレース・ロギング・レベルを表す整数を戻します。

GET_PLSQL_LOGGING_LEVEL関数

現在のPL/SQLのトレース・ロギング・レベルを表す整数を戻します。

GET_SCHEME_NAMES関数

指定したカテゴリのスキーム名のリストをセミコロン(;)で区切って戻します。

GET_TDT_XML関数

指定したスキームのOracle Database Tag Data Translation XMLを戻します。

GET_VALIDATOR関数

Oracle Database Tag Data Translationスキーマを戻します。

REFRESH_CATEGORY関数

指定したカテゴリのJavaスタックに関するメタデータ情報をリフレッシュします。

REMOVE_CATEORY関数

関連するすべてのTDT XMLを含むカテゴリを削除します。

REMOVE_PROXYプロシージャ

プロキシ・サーバーのホストとポートの設定を解除します。

REMOVE_SCHEMEプロシージャ

カテゴリのタグ・スキームを削除します。

SET_JAVA_LOGGING_LEVELプロシージャ

Javaのロギング・レベルを設定します。

SET_PLSQL_LOGGING_LEVELプロシージャ

PL/SQLのトレース・ロギング・レベルを設定します。

SET_PROXYプロシージャ

インターネット・アクセス用に、プロキシ・サーバーのホストとポートを設定します。

VALIDATE_SCHEME関数

入力タグ・データ翻訳XMLをOracle Database Tag Data Translationスキーマで検証します。

識別コード・メタデータ表およびビュー

この項では、識別コード・メタデータ表とビュー、および様々なRFIDタグを解釈するために識別コード・パッケージによってメタデータがどのように使用されるかについて説明します。これらのメタ表ビュー、およびトリガーの作成は、識別コード・パッケージのインストール時に自動的に実行されます。

エンコーディング・メタデータ・ビューはエンコーディング・カテゴリとスキームの格納に使用します。アプリケーション開発者は、自身の識別コードのメタ情報をこれらのビューに挿入できます。MGD_ID ADTは、エンコーディングのメタデータがメタ表に格納されているかぎり、そのエンコーディングを解釈するように設計されています。アプリケーション開発者がEPC仕様バージョン1.1で定義されたエンコーディングのみを使用する場合、EPC仕様バージョン1.1で指定された製品コードは事前定義済のため、メタ表について考慮する必要はありません。

エンコーディング・メタデータ・ビューには次の2種類があります。

- user_mgd_id_category - このビューは、セッション・ユーザーが定義したエンコーディング・カテゴリ情報の格納に使用します。

- user_mgd_id_scheme - このビューは、セッション・ユーザーが定義したエンコーディング・タイプ情報の格納に使用します。

さらにユーザーには、システムで事前定義済のエンコーディング・メタデータとユーザー定義のメタデータを問い合せるために、次の読取り専用ビューが定義されています。

- mgd_id_category - このビューは、システムまたはセッション・ユーザーが定義したエンコーディング・カテゴリ情報の問合せに使用します。

- mgd_id_scheme - このビューは、システムまたはセッション・ユーザーが定義したエンコーディング・タイプ情報の問合せに使用します。

前述のビューの基礎となるメタデータ表は、次のとおりです。

- mgd_id_xml_validator

- mgd_id_category_tab

- mgd_id_scheme_tab

識別コード・パッケージのシステム・ユーザー以外は、この表を操作できません。ユーザーは、メタデータ表を直接使用できません。ユーザーは、読取り専用ビューとDBMS_MGD_ID_UTLパッケージに記述されたメタデータ関数を使用する必要があります。

参照:
DBMS_MGD_ID_UTLパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

メタデータ・ビュー定義

表17-5、表17-6、表17-7および表17-8は、mgdview.sqlファイルで定義したとおり、それぞれMGD_ID_CATEGORY、USER_ID_CATEGORY、MGD_ID_SCHMEおよびUSER_MGD_ID_SCHMEのメタデータ・ビュー定義を示します。

表17-5 MGD_ID_CATEGORYメタデータ・ビューの定義と説明

列名

データ型

説明

CATEGORY_ID

NUMBER(4)

カテゴリ識別子

CATEGORY_NAME

VARCHAR2(256)

カテゴリ名

AGENCY

VARCHAR2(256)

カテゴリを定義した組織

VERSION

VARCHAR2(256)

カテゴリ・バージョン

URI

VARCHAR2(256)

カテゴリを示すURI

表17-6 USER_MGD_ID_CATEGORYメタデータ・ビューの定義と説明

列名

データ型

説明

CATEGORY_ID

NUMBER(4)

カテゴリ識別子

CATEGORY_NAME

VARCHAR2(256)

カテゴリ名

AGENCY

VARCHAR2(256)

カテゴリを定義した組織

VERSION

VARCHAR2(256)

カテゴリ・バージョン

URI

VARCHAR2(256)

カテゴリを示すURI

表17-7 MGD_ID_SCHEMEメタデータ・ビューの定義と説明

列名

データ型

説明

CATEGORY_ID

NUMBER(4)

カテゴリ識別子

TYPE_NAME

VARCHAR2(256)

SGTIN-96、GID-96などのコード体系名

TDT_XML

CLOB

このコード体系のタグ・データ翻訳XML

ENCODINGS

VARCHAR2(256)

カンマで区切られたエンコーディング。たとえば、SGTIN-96の場合はLEGACY, TAG_ENCODING, PURE_IDENTITY, BINARY。

COMPONENTS

VARCHAR2(1024)

各レベルから抽出し組み合せた関連コンポーネント名。それぞれカンマで区切られます。たとえば、GID-96の場合はobjectclass, generalmanager, serial。

表17-8 USER_MGD_ID_SCHEMEメタデータ・ビューの定義と説明

列名

データ型

説明

CATEGORY_ID

NUMBER(4)

カテゴリ識別子

TYPE_NAME

VARCHAR2(256)

SGTIN-96、GID-96などのコード体系名

TDT_XML

CLOB

このコード体系のタグ・データ翻訳XML

ENCODINGS

VARCHAR2(256)

カンマで区切られたエンコーディング。たとえば、SGTIN-96の場合はLEGACY, TAG_ENCODING, PURE_IDENTITY, BINARY。

COMPONENTS

VARCHAR2(1024)

各レベルから抽出し組み合せた関連コンポーネント名。それぞれカンマで区切られます。たとえば、GID-96の場合はobjectclass, generalmanager, serial。

電子製品コード(EPC)の概念

内容は次のとおりです。

- RFIDテクノロジとEPCバージョン1.1コード体系

- 製品コードの概念と現在の使用

RFIDテクノロジとEPCバージョン1.1コード体系

Radio Frequency Identification(RFID)テクノロジは、直列処理が不要となり、重要なサプライ・チェーン・トランザクションの自動化が可能であるため、供給業者、卸売業者、製造業者、小売業者の間で進化を続けています。電子製品コード(EPC)とは、RFIDタグやその他の手段によりオブジェクトを識別する世界共通の識別スキームであり、新たな基準として幅広い支持を集めています。在庫管理の改善と、サプライ・チェーンの可視性を高めることで、企業における倉庫と配送のコストが削減できます。

標準化されたEPC識別子は、様々な業界のニーズに応えるよう設計されたメタコード体系です。その結果、EPCはすべてのEPC準拠タグで一意となるような一連のコード体系および手段を表すようになりました。EPCバージョン1.1には、次の固有のコード体系が含まれます。

- 一般ID(GID)

- EAN.UCC Global Trade Item Number(GTIN)のシリアル化バージョン

- EAN.UCC Serial Shipping Container Code(SSCC)

- EAN.UCC Global Location Number(GLN)

- EAN.UCC Global Returnable Asset Identifier(GRAI)

- EAN.UCC Global Individual Asset Identifier(GIAI)

RFIDアプリケーションは、大量のEPCデータをデータベースに格納する必要があります。EPCデータを効率的に使用するには、データベース側でEPCデータの異なるコード体系を認識する必要もあります。

EPCは新たな基準です。そのため、様々な業界で使用されている番号付けのスキームをすべて網羅しておらず、EPCバージョン1.0からEPCバージョン1.1への変更からも明らかであるように、EPC自体が現在も進化しています。

識別コード・パッケージにより、Oracle DatabaseでEPCコード体系を認識できるようになります。これにより、Oracle DatabaseにおいてEPCデータの効率的な記憶域およびコンポーネント・レベルの取得が可能になるのみではなく、EPCデータのエンコーディングとデコーディング、およびビット・エンコーディングとURIエンコーディング間の変換をサポートする機能を持つようになります。

識別コード・パッケージは、開発者がEPC標準に含まれていない自分のコード体系を定義する拡張可能なフレームワークを提供します。この拡張機能により、Oracle Databaseは進化する将来のEPC標準にも対応可能となります。

この章では、EPCを含む様々な製品コードのOracle Databaseでの格納、取得、エンコーディングおよびデコーディングの要件について説明し、識別コード・パッケージ・ソリューションがデータ型、メタデータ表およびPL/SQLパッケージを提供することで、これらの要件をどのように満たしているかについて説明します。

製品コードの概念と現在の使用

この項では、次の製品コードについて説明します。

- 電子製品コード(EPC)

- Global Trade Identification Number(GTIN)およびSerializable Global Trade Identification Number(SGTIN)

- Serial Shipping Container Code(SSCC)

- Global Location Number(GLN)およびSerializable Global Location Number(SGLN)

- Global Returnable Asset Identifier(GRAI)

- Global Individual Asset Identifier(GIAI)

- RFID EPCネットワーク

電子製品コード(EPC)

電子製品コード(tm)(EPC(tm))は、Radio Frequency Identification(RFID)タグおよびその他の手段を使用して物理オブジェクトを世界的に識別するための識別スキームです。標準のEPCデータは、個別のオブジェクトを一意に識別するEPC(またはEPC識別子)およびEPCタグを効果的かつ効率的に読み取る必要がある場合はオプションのフィルタ値で構成されています。この標準のデータに加え、EPCタグの特定のクラスでは、ユーザー定義データも使用できます。

EPC識別子は、既存のコード体系(可能な場合)の対処と、必要に応じたスキームの定義により、様々な業界のニーズをサポートするために設計されたメタコード体系です。これらのコード体系は、特定の業界または業界グループのドメインでオブジェクト識別子を提供していることを示すため、ドメインIDと呼ばれます。これにより、EPCは一連のコード体系(または「ネームスペース」)を表し、すべてのEPC準拠タグで一意の手段となります。

EPCGlobal EPC Data Standards Version 1.1では、EPCの抽象的な内容と、RFIDタグ、インターネットURIおよびその他の表現の形式における具体的な認識を定義します。EPCバージョン1.1では、特定のコード体系には、汎用識別子(GID)、EAN.UCC Global Trade Item Number(GTIN®)のシリアル化バージョン、EAN.UCC Serial Shipping Container Code(SSCC®)、EAN.UCC Global Location Number(GLN®)、EAN.UCC Global Returnable Asset Identifier(GRAI®)、EAN.UCC Global Individual Asset Identifier(GIAI®)が含まれます。

EPCの純粋な識別

EPCの純粋な識別とは、特定の物理エンティティまたは論理エンティティに関連付けられた識別であり、RFタグ、バーコードおよびデータベース・フィールドなどの特定のエンコーディング媒体に依存しません。そのため、純粋な識別は、エンティティを識別するために使用される抽象的な名前または数値です。純粋な識別は、特定のエンティティを一意に識別するために必要な情報のみで構成されます。

EPCエンコーディング

EPCエンコーディングは、純粋なエンコーディングと、フィルタ値などの詳細情報を、特定の構文(通常は特定のサイズの値フィールドで構成される)に変換するものです。指定した純粋な識別には、バーコード・エンコーディング、様々なタグ・エンコーディング、および様々なURIエンコーディングなどの多数のエンコーディングが含まれている可能性があります。エンコーディングには、識別以外の追加データ(一部のエンコーディングで使用されるフィルタ値)などが含まれている場合もあり、保持する追加データはコード体系により指定します。

たとえば、EAN.UCCシステムで定義されたSerial Shipping Container Code(SSCC)形式は純粋な識別の例です。EPC-SSCC 96ビット形式にエンコーディングされたSSCCはエンコーディングの一例です。

EPCタグのビットレベルのエンコーディング

タグのEPCエンコーディングはビット文字列であり、階層化された可変長のヘッダーとそれに続く一連の数値フィールドから構成されます。数値フィールドは、ヘッダー値によってその全体の長さ、構造、機能が完全に決定されます。

EPC識別URI

EPC識別URIは、統一資源識別子(URI)としての純粋な識別の表現です。

EPCタグのURIエンコーディング

EPCタグのURIエンコーディングは、urn:epc:tag:sgtin-64:3.0652642.800031.400など、特定のEPCタグのビットレベル・エンコーディングを表現したものです。

EPCエンコーディング・プロシージャ

EPCエンコーディング・プロシージャは、様々な情報からEPCタグのビットレベル・エンコーディングを生成する場合に使用します。

EPCデコーディング・プロシージャ

EPCデコーディング・プロシージャは、EPCタグのビットレベル・エンコーディングをEAN.UCCコードに変換する場合に使用します。

Global Trade Identification Number(GTIN)およびSerializable Global Trade Identification Number(SGTIN)

Global Trade Identification Number(GTIN)は、EAN.UCCシステム内で、世界規模で取引品目を一意に識別する場合に使用します。Serialized Global Trade Identification Number(SGTIN)はEPC標準バージョン1.1での識別型です。SGTINはGeneral EAN.UCC Specifications(GenSpec5.0)で定義されているEAN.UCC GTINコードに基づいています。GTINは特定の製品やSKUなど、特定のオブジェクトのクラスを識別します。GTINと一意のシリアル番号を組み合せたものはシリアル化GTIN(SGTIN)と呼ばれます。

Serial Shipping Container Code(SSCC)

Serial Shipping Container Code(SSCC)はGeneral EAN.UCC Specifications(GenSpec5.0)で定義されています。EAN.UCCシステム内の物流単位の一意の識別にはSSCCを使用します。SSCCは個別のオブジェクトへの割当てを想定しています。

Global Location Number(GLN)およびSerializable Global Location Number(SGLN)

Global Location Number(GLN)はGeneral EAN.UCC Specifications(GenSpec5.0)で定義されています。GLNは、ドックのドアや倉庫のスロットなどの個別の一意の物理的位置、または倉庫全体などの物理的位置の集合を表現できます。さらに、GLNは業務(発注など)を行う組織のような論理的エンティティも表現できます。GLNと一意のシリアル番号を組み合せたものはシリアル化GLN(SGLN)と呼ばれます。ただし、EAN.UCCコミュニティがGLN拡張の適切な方法を決定するまでは、シリアル番号フィールドは予約済となり使用できません。

Global Returnable Asset Identifier(GRAI)

特定の値の輸送装置または再利用可能なパッケージを、リターナブル資産といいます。Global Returnable Asset Identifier(GRAI)は、リターナブル資産を一意に識別するためにGeneral EAN.UCC Specifications(GenSpec5.0)で定義されています。

Global Individual Asset Identifier(GIAI)

Global Individual Asset Identifier(GIAI)はGeneral EAN.UCC Specifications(GenSpec5.0)で定義されています。GTINとは異なり、GIAIは個別のオブジェクトへの割当てを想定しています。Global Individual Asset Identifier(GIAI)は会社の固定在庫の一部であるエンティティの一意の識別に使用します。GIAIは、組織のすべての固定資産を識別します。

RFID EPCネットワーク

RFID EPCネットワークは資産の識別、追跡、特定に使用します。物理オブジェクトは、一意のRFIDが有効となっているEPCで識別します。

Oracle Database Tag Data Translationスキーマ

Oracle Database Tag Data TranslationスキーマはEPCglobal TDTスキーマに類似していますが、同一なものではありません。Oracle Database TDTの内容は次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="oracle.mgd.idcode"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tdt="oracle.mgd.idcode" elementFormDefault="qualified"
attributeFormDefault="unqualified" version="1.0">

<xsd:simpleType name="InputFormatList">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="BINARY"/>
<xsd:enumeration value="STRING"/>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="LevelTypeList">
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="SchemeNameList">
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="ModeList">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="EXTRACT"/>
<xsd:enumeration value="FORMAT"/>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="CompactionMethodList">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="32-bit"/>
<xsd:enumeration value="16-bit"/>
<xsd:enumeration value="8-bit"/>
<xsd:enumeration value="7-bit"/>
<xsd:enumeration value="6-bit"/>
<xsd:enumeration value="5-bit"/>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="PadDirectionList">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="LEFT"/>
<xsd:enumeration value="RIGHT"/>
</xsd:restriction>
</xsd:simpleType>

<xsd:complexType name="Field">
<xsd:attribute name="seq" type="xsd:integer" use="required"/>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="bitLength" type="xsd:integer"/>
<xsd:attribute name="characterSet" type="xsd:string" use="required"/>
<xsd:attribute name="compaction" type="tdt:CompactionMethodList"/>
<xsd:attribute name="compression" type="xsd:string"/>
<xsd:attribute name="padChar" type="xsd:string"/>
<xsd:attribute name="padDir" type="tdt:PadDirectionList"/>
<xsd:attribute name="decimalMinimum" type="xsd:long"/>
<xsd:attribute name="decimalMaximum" type="xsd:long"/>
<xsd:attribute name="length" type="xsd:integer"/>
</xsd:complexType>

<xsd:complexType name="Option">
<xsd:sequence>
<xsd:element name="field" type="tdt:Field" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="optionKey" type="xsd:string" use="required"/>
<xsd:attribute name="pattern" type="xsd:string"/>
<xsd:attribute name="grammar" type="xsd:string" use="required"/>
</xsd:complexType>

<xsd:complexType name="Rule">
<xsd:attribute name="type" type="tdt:ModeList" use="required"/>
<xsd:attribute name="inputFormat" type="tdt:InputFormatList" use="required"/>
<xsd:attribute name="seq" type="xsd:integer" use="required"/>
<xsd:attribute name="newFieldName" type="xsd:string" use="required"/>
<xsd:attribute name="characterSet" type="xsd:string" use="required"/>
<xsd:attribute name="padChar" type="xsd:string"/>
<xsd:attribute name="padDir" type="tdt:PadDirectionList"/>
<xsd:attribute name="decimalMinimum" type="xsd:long"/>
<xsd:attribute name="decimalMaximum" type="xsd:long"/>
<xsd:attribute name="length" type="xsd:string"/>
<xsd:attribute name="function" type="xsd:string" use="required"/>
<xsd:attribute name="tableURI" type="xsd:string"/>
<xsd:attribute name="tableParams" type="xsd:string"/>
<xsd:attribute name="tableXPath" type="xsd:string"/>
<xsd:attribute name="tableSQL" type="xsd:string"/>
</xsd:complexType>

<xsd:complexType name="Level">
<xsd:sequence>
<xsd:element name="option" type="tdt:Option" minOccurs="1"
maxOccurs="unbounded"/>
<xsd:element name="rule" type="tdt:Rule" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="type" type="tdt:LevelTypeList" use="required"/>
<xsd:attribute name="prefixMatch" type="xsd:string"/>
<xsd:attribute name="requiredParsingParameters" type="xsd:string"/>
<xsd:attribute name="requiredFormattingParameters" type="xsd:string"/>
</xsd:complexType>

<xsd:complexType name="Scheme">
<xsd:sequence>
<xsd:element name="level" type="tdt:Level" minOccurs="4" maxOccurs="5"/>
</xsd:sequence>
<xsd:attribute name="name" type="tdt:SchemeNameList" use="required"/>
<xsd:attribute name="optionKey" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="TagDataTranslation">
<xsd:sequence>
<xsd:element name="scheme" type="tdt:Scheme" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="version" type="xsd:string" use="required"/>
<xsd:attribute name="date" type="xsd:dateTime" use="required"/>
</xsd:complexType>
<xsd:element name="TagDataTranslation" type="tdt:TagDataTranslation"/>
</xsd:schema>

18 スキーマ・オブジェクトの依存性

オブジェクトAの定義がオブジェクトBを参照している場合、AはBに依存します。この章では、スキーマ・オブジェクトの相互間の依存性と、Oracle Databaseがそのような依存性を自動的に追跡し管理する方法について説明します。こうした自動依存性管理により、AによってBの古いバージョンが使用されることがなく、Bの変更後にAを明示的に再コンパイルする必要もほとんどなくなります。

内容は次のとおりです。

- スキーマ・オブジェクトの依存性の概要

- オブジェクトの依存性の問合せ

- オブジェクトのステータス

- 依存オブジェクトの無効化

- 無効化を回避するためのガイドライン

- オブジェクトの再有効化

- スキーマの範囲内での名前解決

- ローカル依存性の管理

- リモート依存性の管理

- リモート・プロシージャ・コール(RPC)の依存性管理

- 共有SQLの依存性管理

スキーマ・オブジェクトの依存性の概要

スキーマ・オブジェクトのタイプによっては、定義の中で他のオブジェクトを参照できるものがあります。たとえば、ビューは表や他のビューを参照する問合せによって定義され、サブプログラムの本体の中には、他のオブジェクトを参照するSQL文を含めることができます。オブジェクトAの定義がオブジェクトBを参照している場合、Aは(Bの)依存オブジェクト、Bは(Aの)参照オブジェクトです。

例18-1は、データベース内の依存オブジェクト・タイプと参照オブジェクト・タイプの表示方法(DBAとしてログインしている場合)を示します。

例18-1 依存オブジェクト・タイプと参照オブジェクト・タイプの表示

依存オブジェクト・タイプの表示:

SELECT DISTINCT TYPE
FROM DBA_DEPENDENCIES
ORDER BY TYPE;

結果:

TYPE
------------------
DIMENSION
EVALUATION CONTXT
FUNCTION
INDEX
INDEXTYPE
JAVA CLASS
JAVA DATA
MATERIALIZED VIEW
OPERATOR
PACKAGE
PACKAGE BODY

TYPE
------------------
PROCEDURE
RULE
RULE SET
SYNONYM
TABLE
TRIGGER
TYPE
TYPE BODY
UNDEFINED
VIEW
XML SCHEMA

22 rows selected.

参照オブジェクト・タイプの表示:

SELECT DISTINCT REFERENCED_TYPE
FROM DBA_DEPENDENCIES
ORDER BY REFERENCED_TYPE;

結果:

REFERENCED_TYPE
------------------
EVALUATION CONTXT
FUNCTION
INDEX
INDEXTYPE
JAVA CLASS
LIBRARY
NON-EXISTENT
OPERATOR
PACKAGE
PROCEDURE
SEQUENCE

REFERENCED_TYPE
------------------
SYNONYM
TABLE
TYPE
VIEW
XML SCHEMA

16 rows selected.

参照オブジェクトの定義を変更した場合、その変更の内容によって、依存オブジェクトがエラーなしに機能し続けることができない場合があります。たとえば、表を削除すると、その表に基づくビューは使用できなくなります。

一部の依存性のみを無効にするスキーマ・オブジェクトの変更例として、例18-2に示す2つのビューについて考えてみます。これらのビューは、HR.EMPLOYEES表に基づいています。

例18-2は、EMPLOYEES表から、表内のすべての列を選択するSIXFIGURESビューと、EMAIL列を含まないCOMMISSIONEDビューの2つを作成します。この例が示すように、EMAIL列を変更すると、SIXFIGURESは無効化されますが、COMMISSIONEDはされません。

例18-2 一部の依存オブジェクトを無効にするスキーマ・オブジェクトの変更

CREATE OR REPLACE VIEW sixfigures AS
SELECT * FROM employees
WHERE salary >= 100000;

CREATE OR REPLACE VIEW commissioned AS
SELECT first_name, last_name, commission_pct
FROM employees
WHERE commission_pct > 0.00;

SQL*Plus書式設定コマンド:

COLUMN object_name FORMAT A16

問合せ:

SELECT object_name, status
FROM user_objects
WHERE object_type = 'VIEW'
ORDER BY object_name;

結果:

OBJECT_NAME      STATUS
---------------- -------
COMMISSIONED     VALID
SIXFIGURES       VALID

EMPLOYEES表のEMAIL列を長くする:

ALTER TABLE employees MODIFY email VARCHAR2(100);

問合せ:

SELECT object_name, status
FROM user_objects
WHERE object_type = 'VIEW'
ORDER BY object_name;

結果:

OBJECT_NAME      STATUS
---------------- -------
COMMISSIONED     VALID
SIXFIGURES       INVALID

ビューは、その問合せ内で参照されているすべてのオブジェクトに依存します。例18-3のビューは、表employeesおよびdepartmentsによって変わります。

例18-3 複数のオブジェクトに依存するビュー

CREATE OR REPLACE VIEW v AS
SELECT last_name, first_name, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id
ORDER BY last_name;

注意:

- CREATE文を実行すると、すべての依存性が自動的に更新されます。

- 動的SQL文では、依存性は作成されません。たとえば次の文を実行しても、tab1に対する依存性は作成されません。

EXECUTE IMMEDIATE 'SELECT * FROM tab1'

オブジェクトの依存性の問合せ

静的データ・ディクショナリ・ビューUSER_DEPENDENCIES、ALL_DEPENDENCIESおよびDBA_DEPENDENCIESには、データベース・オブジェクト間の依存性が表示されます。

utldtree.sql SQLスクリプトを実行すると、オブジェクト依存性ツリーに関する情報が表示されるビューDEPTREEと、DEPTREEをソートした印刷用のビューであるIDEPTREEが作成されます。

参照:
DEPTREE、IDEPTREEおよびutldtree.sqlスクリプトの詳細は、『Oracle Databaseリファレンス』を参照してください。

オブジェクトのステータス

各データベース・オブジェクトには、表18-1に示すステータス値の1つが割り当てられています。

表18-1 データベース・オブジェクトのステータス

ステータス

意味

有効

オブジェクトが、データ・ディクショナリ内の現在の定義を使用して正常にコンパイルされた。

コンパイル・エラー

オブジェクトの最後のコンパイル実行時にエラーが発生した。

無効

参照先のオブジェクトが変更されたため、オブジェクトに無効とマークされている。(無効になるのは依存オブジェクトのみ。)

権限取消し

参照オブジェクトに対するアクセス権限が取り消された。(権限取消しの対象となるのは依存オブジェクトのみ。)

注意:
静的データ・ディクショナリ・ビューUSER_OBJECTS、ALL_OBJECTSおよびDBA_OBJECTSでは、「コンパイル・エラー」、「無効」、「権限取消し」はすべて同じものとみなされ、INVALIDと表示されます。

依存オブジェクトの無効化

オブジェクトAがオブジェクトBに、オブジェクトBがオブジェクトCにそれぞれ依存している場合、A、Bはそれぞれ、B、Cに対する直接依存オブジェクトであり、AはCに対する間接依存オブジェクトです。

直接依存オブジェクトは、それ自体に影響を与える参照オブジェクトへの変更(参照オブジェクトのシグネチャの変更)によってのみ無効になります。

間接依存オブジェクトは、それ自体に影響を与えない参照オブジェクトへの変更によって無効になることがあります。つまり、Cの変更によってBが無効になると、それによってA(およびBの他のすべての直接依存オブジェクトと間接依存オブジェクト)が無効になります。これを連鎖的な無効化と呼びます。

緩やかな無効化では、参照オブジェクトを変更するデータ定義言語(DDL)文によって、そのすべての依存オブジェクトが無効になります。

高度な無効化では、参照オブジェクトを変更するDDL文によって、次の文のいずれかに該当する依存オブジェクトのみが無効になります。

- 依存オブジェクトが、DDL文によって変更された参照オブジェクトの属性に依存している場合。

- 依存オブジェクトのコンパイル済メタデータが、変更された参照オブジェクトに対して正しいものでなくなった場合。

たとえば、ビューvが表tの列c1およびc2を選択している場合、tの列c3のみを変更するDDL文では、vは無効になりません。

DDL文CREATE OR REPLACE objectは、次の条件下では効果がありません。

- objectがPL/SQLオブジェクトで、新しいPL/SQLソース・テキストが既存のPL/SQLソース・テキストと同一であり、objectとともに保存されているPL/SQLコンパイル・パラメータ設定がセッション環境のパラメータ設定と同一である。
PL/SQLのコンパイル・パラメータ設定の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- objectはシノニムで、この文はターゲット・オブジェクトを変更しません。

表18-2の左側の列の操作では高度な無効化が行われますが、右側の列のケースは例外です。右側の列のケース、および表18-2に示されていないすべての操作では、緩やかな無効化が行われます。

表18-2 高度な無効化が発生する操作

操作

例外

ALTER TABLE table ADD column

- 依存オブジェクト(ビューを除く)で、tableにSELECT *が使用された場合。

- 依存オブジェクトで、table%rowtypeが使用された場合。

- 依存オブジェクトで、列リストを指定することなくtableに対してINSERTが実行された場合。

- 依存オブジェクトが、結合が含まれる問合せ内のtableを参照している場合。

- 依存オブジェクトが、PL/SQL変数を参照する問合せ内のtableを参照している場合。

ALTER TABLE table {MODIFY|RENAME|DROP|SET UNUSED} column

ALTER TABLE table DROP CONSTRAINT not_null_constraint

- 依存オブジェクトがcolumnを直接参照している場合。

- 依存オブジェクトで、tableにSELECT *が使用された場合。

- 依存オブジェクトで、table%ROWTYPEが使用された場合。

- 依存オブジェクトで、列リストを指定することなくtableに対してINSERTが実行された場合。

- 依存オブジェクトが、行全体に依存するトリガーである(定義で列を指定していない)場合。

- 依存オブジェクトが、削除された列の右側の列に依存するトリガーである場合。

CREATE OR REPLACE VIEW view

オンライン表再定義(DBMS_REDEFINITION)

新しい定義と以前の定義の列リストが異なり、次の1つ以上に該当する場合。

- 依存オブジェクトが、ビューまたは表の新しい定義の中で修正または削除された列を参照している場合。

- 依存オブジェクトで、view%rowtypeまたはtable%rowtypeが使用されている場合。

- 依存オブジェクトで、列リストを指定することなくビューまたは表に対してINSERTが実行された場合。

- ビューの新しい定義に新しい列が追加され、かつ結合が含まれている問合せ内のビューまたは表を依存オブジェクトが参照している場合。

- ビューの新しい定義に新しい列が追加され、PL/SQLを参照する問合せ内のビューまたは表を依存オブジェクトが参照している場合。

- 依存オブジェクトが、RELIES ON句でビューまたは表を参照している場合。

CREATE OR REPLACE SYNONYM synonym

- 新旧のsynonymのターゲットが異なり、かつ一方が表ではない場合。

- synonymの新旧のターゲットがどちらも表で、かつその2つの表の列リストまたは付与権限が異なる場合。

- synonymの新旧のターゲットがどちらも表で、かつ依存オブジェクトがビューであり、そのビューが参照している列が以前のターゲットの一意索引に関与し、新しいターゲットの一意索引には関与していない場合。

DROP INDEX

- 索引がファンクション索引であり、依存オブジェクトが、行全体に依存するトリガー、またはファンクション索引が作成された後でtableに追加された列に依存するトリガーである場合。

- 索引が一意索引であり、依存オブジェクトがビューであって、かつそのビューが一意索引に関与している列を参照している場合。

CREATE OR REPLACE {PROCEDURE|FUNCTION}

コール・シグネチャが変更された場合。コール・シグネチャとは、パラメータ・リスト(パラメータの順序、名前および型)、戻り型、純粋度脚注1、決定性、並列度、パイプライン処理および(プロシージャまたはファンクションがCまたはJavaで実装されている場合は)実装の各プロパティを指します。

CREATE OR REPLACE PACKAGE

- 依存オブジェクトが、削除または名前変更されたパッケージ・アイテムを参照している場合。

- 依存オブジェクトが参照しているパッケージ・プロシージャまたはパッケージ・ファンクションのコール・シグネチャまたはエントリ・ポイント番号脚注2が変更された場合。
参照されているプロシージャまたはファンクションにオーバーロードの候補が複数ある場合、それらの候補のコール・シグネチャまたはエントリ・ポイント番号が変更されるか、候補が追加または削除されると、依存オブジェクトは無効。

- 依存オブジェクトが参照しているパッケージ・カーソルのコール・シグネチャ、行タイプまたはエントリ・ポイント番号が変更された場合。

- 依存オブジェクトが参照しているパッケージ・タイプまたはパッケージ・サブタイプの定義が変更された場合。

- 依存オブジェクトが参照しているパッケージの変数または定数の名前、データ型、初期値、オフセット番号のいずれかが変更された場合。

- パッケージ純粋度^1が変更された場合。

脚注1 純粋度とは、SQL問合せ内部でPL/SQLファンクションを起動する際に不測の影響(予期せぬデータ変更など)が生じるのを回避するための一連のルールです。パッケージ純粋度とは、パッケージ初期化ブロック内のコードの純粋度を指します。

脚注2 プロシージャやファンクションのエントリ・ポイント番号は、PL/SQLパッケージ・コードにおける位置によって決まります。PL/SQLパッケージの最後に追加されたプロシージャやファンクションには、新しいエントリ・ポイント番号が付与されます。

注意:
表18-2の操作により無効化される依存オブジェクトが、静的データ・ディクショナリ・ビュー*_OBJECTSおよび*_OBJECTS_AEに反映されるのは、(コンパイル時または実行時に)そのオブジェクトの参照が試行された後、または次のいずれかのサブプログラムが起動された後です。

- DBMS_UTILITY.COMPILE_SCHEMA(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)

- 任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)

内容は次のとおりです。

- セッションの状態と参照パッケージ

- セキュリティ認可

セッションの状態と参照パッケージ

パッケージ構成を参照するセッションごとに、各パッケージの独自のインスタンスが存在します。このインスタンスには、パブリック変数とプライベート変数、カーソルおよび定数の永続的な状態が含まれます。その後、セッションのインスタンス化されたパッケージのいずれかが無効になった後、再度有効化されると、そのセッションのパッケージのインスタンス化は、状態も含めてすべて失われる可能性があります。

参照:

- パッケージのインスタンス化の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- パッケージ状態の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

セキュリティ認可

データ操作言語(DML)オブジェクト権限またはシステム権限をユーザーまたはPUBLICに対して付与または取り消すと、Oracle Databaseによって、その所有者のすべての依存オブジェクトが無効化されます。これは、依存オブジェクトの所有者が、すべての参照オブジェクトに関する必要な権限を引き続き持つことを確認するためです。

無効化を回避するためのガイドライン

依存オブジェクトの無効化を回避するには、次のガイドラインに従ってください。

- パッケージの最後へのアイテムの追加

- ビューを介した各表の参照

パッケージの最後へのアイテムの追加

アイテムをパッケージに追加するときは、パッケージの最後に追加します。このようにすると、既存の最上位パッケージ・アイテムのエントリ・ポイント番号が維持され、それらのパッケージ・アイテムが無効になりません。

たとえば、次のパッケージについて考えます。

CREATE OR REPLACE PACKAGE pkg1 IS
FUNCTION get_var RETURN VARCHAR2;
END;
/

次のようにアイテムをpkg1の最後に追加すると、get_varファンクションを参照する依存オブジェクトが無効になりません。

CREATE OR REPLACE PACKAGE pkg1 IS
FUNCTION get_var RETURN VARCHAR2;
PROCEDURE set_var (v VARCHAR2);
END;
/

次のようにアイテムをget_varファンクションとset_varプロシージャの間に挿入すると、set_varファンクションを参照する依存オブジェクトが無効になります。

CREATE OR REPLACE PACKAGE pkg1 IS
FUNCTION get_var RETURN VARCHAR2;
PROCEDURE assert_var (v VARCHAR2);
PROCEDURE set_var (v VARCHAR2);
END;
/

ビューを介した各表の参照

ビューを使用して表を間接的に参照すると、次のことができるようになります。

- 依存ビューまたは依存PL/SQLオブジェクトを無効にせずに、表に列を追加できます。

- 依存オブジェクトを無効にせずに、ビューで参照されていない列を変更または削除できます。

CREATE OR REPLACE VIEW文を使用しても、新しいROWTYPEが古いROWTYPEと一致する場合は、既存のビューまたはその依存オブジェクトが無効になることはありません。

オブジェクトの再有効化

参照されたときに無効になっているオブジェクトは、使用できるように有効化する必要があります。有効化は、オブジェクトが参照されるときに自動的に行われます。ユーザーが明示的な操作を行う必要はありません。

オブジェクトが無効な場合、ステータスはコンパイル・エラー、権限取消し、または無効のいずれかです。これらの用語の定義は、表18-1を参照してください。

内容は次のとおりです。

- コンパイルされたがエラーがあるオブジェクトの再有効化

- 未許可オブジェクトの再有効化

- 無効SQLオブジェクトの再有効化

- 無効PL/SQLオブジェクトの再有効化

コンパイルされたがエラーがあるオブジェクトの再有効化

コンパイラでは、コンパイルされたがエラーのあるオブジェクトの自動的な再有効化は行われません。コンパイラはオブジェクトを再コンパイルします。オブジェクトがエラーなしで再コンパイルされると、再有効化されます。それ以外は無効のままです。

未許可オブジェクトの再有効化

コンパイラは、そのすべての参照オブジェクトに対するアクセス権限が未許可オブジェクトにあるかどうかを調べます。ある場合、未許可オブジェクトはコンパイラによって再コンパイルなしで再有効化されます。ない場合は、コンパイラによって対応するエラー・メッセージが発行されます。

無効SQLオブジェクトの再有効化

SQLコンパイラによって無効なオブジェクトが再コンパイルされます。オブジェクトがエラーなしで再コンパイルされると、再有効化されます。それ以外は無効のままです。

無効PL/SQLオブジェクトの再有効化

無効のPL/SQLプログラム・ユニット(プロシージャ、ファンクションまたはパッケージ)の場合、PL/SQLコンパイラが、参照オブジェクトの変更が無効オブジェクトに影響を与えるものだったかどうかを調べます。影響を与えた場合、SQLコンパイラによって無効なオブジェクトが再コンパイルされます。オブジェクトがエラーなしで再コンパイルされると、再有効化されます。それ以外は無効のままです。影響がなかった場合、無効オブジェクトはコンパイラによって再コンパイルなしで再有効化されます。

スキーマの範囲内での名前解決

SQL文で参照されるオブジェクト名は1つ以上の部分で構成されます。各部分はピリオドで区切られます。たとえば、hr.employees.department_idは3つの部分から構成されています。

Oracle Databaseは次の手順を使用して、オブジェクト名を解決しようとします。

1. オブジェクト名の先頭の要素を修飾します。
オブジェクト名に要素が1つしかない場合は、その要素が最初の要素となります。要素が2つ以上ある場合は、最も左にあるピリオドの左側の要素が先頭の要素です。たとえば、hr.employees.department_idでは、hrが先頭の要素です。

先頭の要素を修飾する手順は次のとおりです。

1. オブジェクト名が、SELECT文のFROM句に含まれる表名であり、2つ以上の構成要素を持つ場合は、手順dに進みます。それ以外の場合は、手順bに進みます。

2. 現在のスキーマ内で、最初の要素と一致する名前を持つオブジェクトが検索されます。

見つかった場合は、手順2に進みます。それ以外の場合は、手順cに進みます。

3. 最初の要素と一致するパブリック・シノニムが検索されます。

見つかった場合は、手順2に進みます。それ以外の場合は、手順dに進みます。

4. 最初の要素と名前が一致するスキーマが検索されます。

該当するスキーマが見つかった場合、オブジェクト名に後続の要素があれば、手順eに進みます。それ以外の場合は、エラーが戻され、オブジェクト名を修飾できません。

5. 手順dで見つかったスキーマ内で、オブジェクト名の2番目の要素と一致する名前を持つ表またはSQLファンクションが検索されます。

見つかった場合は、手順2に進みます。それ以外の場合は、エラーが戻され、オブジェクト名を修飾できません。

注意:
この手順で検出されたSQLファンクションは、手順dで検出されたスキーマによって再定義されています。

2. スキーマ・オブジェクトは修飾されています。オブジェクト名の残りの要素は、このスキーマ・オブジェクトの有効な部分と一致する必要があります。

たとえば、オブジェクト名がhr.employees.department_idである場合、hrがスキーマとして修飾されます。employeesが表として修飾されている場合、department_idはその表の列に対応する必要があります。また、employeesがパッケージとして修飾されている場合、department_idはそのパッケージのパブリック定数、変数、プロシージャまたはファンクションに対応する必要があります。

Oracle Databaseによる参照の解決では、オブジェクトは、他のオブジェクトが存在しないという事実に依存する場合があります。このような状況が発生するのは、依存オブジェクトで使用されている参照の解釈が、別のオブジェクトの存在により多義的になる場合です。

参照:

- SQLとPL/SQLでの名前解決の違いの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- 分散データベース・システムでの名前解決の詳細は、『Oracle Database管理者ガイド』を参照してください。

ローカル依存性の管理

ローカルの依存性管理は、Oracle Databaseが単一データベースのオブジェクト間の依存性を管理するときに行われます。たとえば、プロシージャ内の文が同じデータベースの表を参照することができます。

リモート依存性の管理

リモートの依存性管理は、Oracle Databaseがネットワーク上の分散環境で依存性を管理するときに行われます。たとえば、Oracle Formsトリガーは、データベースのスキーマ・オブジェクトに依存することができます。分散データベースでは、ローカル・ビューはリモート表を参照できます。

Oracle Databaseでは、分散データベースの依存性も管理されます。たとえば、Oracle Formsアプリケーションは、表を参照するトリガーを含むことがあります。データベース・システムは、そのオブジェクト間の依存性を把握する必要があります。Oracle Databaseがリモート依存性を管理する際は、関係するオブジェクトに応じて様々なメカニズムを使用します。

内容は次のとおりです。

- ローカル・データベース・プロシージャとリモート・データベース・プロシージャの間の依存性

- その他のリモート・オブジェクト間の依存性

- アプリケーションの依存性

ローカル・データベース・プロシージャとリモート・データベース・プロシージャの間の依存性

分散データベース・システムのストアド・プロシージャ(ファンクション、パッケージおよびトリガーを含む)間の依存性は、タイムスタンプ・チェックまたはシグネチャ・チェックを使用して管理されます(「タイムスタンプ依存性モード」および「RPCシグネチャ依存性モード」を参照)。

動的初期化パラメータREMOTE_DEPENDENCIES_MODEによって、タイムスタンプとシグネチャのどちらでリモート依存性を管理するかが決まります。

参照:
『Oracle Database PL/SQL言語リファレンス』

その他のリモート・オブジェクト間の依存性

Oracle Databaseでは、ローカル・プロシージャとリモート・プロシージャ間の依存性を除き、リモート・スキーマ・オブジェクト間の依存性は管理されません。

たとえば、リモート表を参照する問合せによってローカル・ビューが作成および定義されるとします。また、ローカル・プロシージャに、同じリモート表を参照するSQL文が含まれるとします。その後、表の定義が変更されます。

したがって、表の変更後にビューとプロシージャが使用され、そのビューとプロシージャがエラーとなった場合でも、ローカル・ビューとプロシージャは無効になりません。この場合、ビューとプロシージャを、エラーが戻されないように手動で変更する必要があります。このような場合は、依存オブジェクトを不必要に再コンパイルするより、依存性を管理しないことをお薦めします。

アプリケーションの依存性

データベース・アプリケーションのコードは、接続先データベースのオブジェクトを参照できます。たとえば、Oracle Call Interface(OCI)およびプリコンパイラ・アプリケーションは無名PL/SQLブロックを発行できます。Oracle Formsアプリケーションのトリガーは、スキーマ・オブジェクトを参照できます。

これらのアプリケーションは、参照しているスキーマ・オブジェクトに依存しています。依存性管理の方法は開発環境によって異なります。Oracle Databaseでは、アプリケーションの依存性が自動的に追跡されることはありません。

参照:
データベース・アプリケーション内のリモート依存性管理の詳細は、アプリケーション開発ツールおよびオペレーティング・システムのマニュアルを参照してください。

リモート・プロシージャ・コール(RPC)の依存性管理

リモート・プロシージャ・コール(RPC)の依存性管理は、分散データベース・システムでローカル・ストアド・プロシージャがリモート・プロシージャをコールするときに行われます。動的初期化パラメータREMOTE_DEPENDENCIES_MODEは、依存性モードを制御します。選択肢は、タイムスタンプ依存性モード、またはRPCシグネチャ依存性モードです。

内容は次のとおりです。

- タイムスタンプ依存性モード

- RPCシグネチャ依存性モード

- 依存性モードの制御

タイムスタンプ依存性モード

プロシージャのコンパイル時に、タイムスタンプがデータ・ディクショナリに記録されます。タイムスタンプは、プロシージャが作成、変更または置換された時刻を示します。

コンパイル済のプロシージャには、このプロシージャがコールする各リモート・プロシージャの情報(リモート・プロシージャのスキーマ、パッケージ名、プロシージャ名、タイムスタンプなど)が含まれます。

タイムスタンプ依存性モードでは、ローカル・リモート・プロシージャがリモート・プロシージャをコールすると、Oracle Databaseは、リモート・プロシージャに対するローカル・プロシージャのタイムスタンプと、リモート・プロシージャの現在のタイムスタンプを比較します。2つのタイムスタンプが一致した場合、ローカル・プロシージャとリモート・プロシージャの両方が実行されます。どちらも再コンパイルされません。

2つのタイムスタンプが一致しない場合は、ローカル・プロシージャが無効になり、コール元の環境にエラーが返されます。新しいタイムスタンプのリモート・プロシージャに依存する他のすべてのローカル・プロシージャも無効になります。

タイムスタンプは、ローカル・プロシージャ本体の文によってリモート・プロシージャが実行されるときに比較されます。したがって、ローカル・プロシージャ内の無効なプロシージャ・コールよりも前にある文は、正常に実行されることがあります。無効なコールの後の分は実行されません。ローカル・プロシージャは再コンパイルが必要です。

無効なコールの前にDML文がある場合、この文と無効なコールが同じPL/SQLブロックにある場合のみ、この文がロールバックされます。たとえば、次のコードではUPDATE文がロールバックされます。

BEGIN

UPDATE table SET ...
invalid_proc;
COMMIT;

END;

しかし、次のコードではUPDATE文はロールバックされません。

UPDATE table SET ...
EXECUTE invalid_proc;
COMMIT;

タイムスタンプ依存性モードには次のデメリットがあります。

- ネットワーク上での依存オブジェクトに対して、パフォーマンスに関係なく、不要な再コンパイルが行われることがよくあります。

- クライアント側アプリケーションでPL/SQLが使用されていると、このモードでは、クライアント側でアプリケーションの実行が妨げられる状況になる場合があります。
このようなアプリケーションの例はOracle Formsです。インストール中、クライアント・サイトでOracle Formsが使用するクライアント側PL/SQLプロシージャを再コンパイルする必要があります。また、クライアント側プロシージャがサーバー・プロシージャに依存しているときに、サーバー・プロシージャが変更または自動再コンパイルされた場合は、クライアント側PL/SQLプロシージャを再コンパイルする必要があります。ただし、クライアントではPL/SQLコンパイラは使用できません。したがって、クライアント・アプリケーション開発者は、新しいバージョンのアプリケーションをすべての顧客に再配布する必要があります。

RPCシグネチャ依存性モード

Oracle Databaseは、リモート依存性を処理するために、RPCシグネチャを提供します。ローカル環境では常に再コンパイルが可能であるため、RPCシグネチャはローカル依存性に影響を与えません。

RPCシグネチャは、各コンパイル済ストアド・プログラム・ユニットと関連付けられています。これは、次の特性を基準にユニットを識別しています。

- 名前

- パラメータ数

- 各パラメータのデータ型クラス

- 各パラメータのモード

- ファンクションの戻り値のデータ型クラス

RPCシグネチャは、先行する特性の少なくとも1つが変更された場合のみ変更されます。

注意:
RPCシグネチャには、DETERMINISTIC、PARALLEL_ENABLE、または純粋度の情報は含まれません。リモート・システムのあるファンクションについてこれらの設定が変更された場合、これらに基づく最適化は自動的に再検討されません。したがって、SQL文でリモート・ファンクションをコールしたり、ファンクションに基づいたインデックスで使用したりすると、問合せの結果が正しくならないことがあります。

コンパイル済のプログラム・ユニットには、このプログラムがコールする各リモート・プロシージャのRPCシグネチャ(および、リモート・プロシージャのスキーマ、パッケージ名、プロシージャ名、タイムスタンプ)が含まれます。

RPCシグネチャ依存性モードでは、ローカル・プログラム・ユニットがリモート・プログラム・ユニットでサブプログラムをコールすると、データベースはタイムスタンプの不一致を無視し、リモート・サブプログラムに対するローカル・ユニットのRPCシグネチャと、リモート・サブプログラムの現在のRPCシグネチャを比較します。RPCシグネチャが一致する場合、コールは正常に行われます。一致しない場合、データベースからローカル・ユニットにエラーが返され、このユニットが無効化されます。

たとえば、プロシージャget_emp_nameが、Bostonにあるサーバー(BOSTON_SERVER)に格納されているとします。

CREATE OR REPLACE PROCEDURE get_emp_name (
emp_number  IN  NUMBER,
hiredate    OUT VARCHAR2,
emp_name    OUT VARCHAR2) AS
BEGIN
SELECT last_name, TO_CHAR(hire_date, 'DD-MON-YY')
INTO emp_name, hiredate
FROM employees
WHERE employee_id = emp_number;
END;
/

get_emp_nameがBOSTON_SERVERでコンパイルされたときに、Oracle Databaseにより、RPCシグネチャとタイムスタンプの両方が記録されます。

たとえば、print_nameをコールするPL/SQLプロシージャget_emp_nameがCaliforniaにあるサーバーにあるとしましょう。

CREATE OR REPLACE PROCEDURE print_ename (emp_number IN NUMBER) AS
hiredate  VARCHAR2(12);
ename     VARCHAR2(10);
BEGIN
get_emp_name@BOSTON_SERVER(emp_number, hiredate, ename);
dbms_output.put_line(ename);
dbms_output.put_line(hiredate);
END;
/

print_nameがCaliforniaサーバーでコンパイルされると、このデータベースはBostonサーバーに接続し、get_emp_nameのRPCシグネチャをCaliforniaサーバーに送信してから、get_emp_nameのRPCシグネチャをコンパイル済のprint_enameに記録します。

実行時、print_nameがget_emp_nameをコールすると、データベースは、コンパイル済のprint_enameに記録されたget_emp_nameのRPCシグネチャをBostonサーバーに送信します。記録されたRPCシグネチャが、Bostonサーバーのget_emp_nameの現在のRPCシグネチャと一致した場合、コールは正常に行われます。それ以外の場合、データベースはprint_nameにエラーを返し、その後、これが無効化されます。

内容は次のとおりです。

- パラメータの名前とデフォルト値の変更

- パラメータ・モードINの指定の変更

- サブプログラム本体の変更

- パラメータのデータ型クラスの変更

- パッケージ・タイプの変更

パラメータの名前とデフォルト値の変更

サブプログラム・パラメータの名前またはデフォルト値を変更しても、サブプログラムのRPCシグネチャは変更されません。たとえば、次の2つの例でプロシージャP1のRPCシグネチャは同じです。

PROCEDURE P1 (Param1 IN NUMBER := 100);
PROCEDURE P1 (Param2 IN NUMBER := 200);

ただし、コール側で新しいデフォルト値を取得できるようにする必要があるアプリケーションの場合、コールされたプロシージャを再コンパイルする必要があります。

パラメータ・モードINの指定の変更

サブプログラム・パラメータ・モードINはデフォルトなので、暗黙的または明示的に指定できます。指定を暗黙的から明示的、または明示的から暗黙的に変更しても、サブプログラムのRPCシグネチャは変更されません。たとえば、次の2つの例でプロシージャP1のRPCシグネチャは同じです。

PROCEDURE P1 (Param1 NUMBER);    -- implicit specification
PROCEDURE P1 (Param1 IN NUMBER);  -- explicit specification

サブプログラム本体の変更

サブプログラムの本体を変更しても、サブプログラムのRPCシグネチャは変更されません。

例18-4では、プロシージャget_hire_dateの本体のみ変更されます。したがって、get_hire_dateのRPCシグネチャは変更されません。

例18-4 プロシージャget_hire_dateの本体の変更

CREATE OR REPLACE PROCEDURE get_hire_date (
emp_number  IN  NUMBER,
hiredate    OUT VARCHAR2,
emp_name    OUT VARCHAR2) AS
BEGIN
SELECT last_name, TO_CHAR(hire_date, 'DD-MON-YY')
INTO emp_name, hiredate
FROM employees
WHERE employee_id = emp_number;
END;
/

CREATE OR REPLACE PROCEDURE get_hire_date (
emp_number  IN  NUMBER,
hiredate    OUT VARCHAR2,
emp_name    OUT VARCHAR2) AS
BEGIN
-- Change date format model
SELECT last_name, TO_CHAR(hire_date, 'DD/MON/YYYY')
INTO emp_name, hiredate
FROM employees
WHERE employee_id = emp_number;
END;
/

パラメータのデータ型クラスの変更

パラメータのデータ型を同じクラスの別のデータ型に変更しても、RPCシグネチャは変更されませんが、別のクラスのデータ型に変更すると、シグネチャも変更されます。

表18-3に、データ型クラスと、クラスを構成するデータ型を示します。NCHARなど、表18-3に含まれないデータ型はデータ型クラスには属していません。これらの型を変更すると、必ずRPCシグネチャも変更されます。

表18-3 データ型クラス

データ型クラス

クラスのデータ型

Character

CHAR
CHARACTER

VARCHAR

VARCHAR
VARCHAR2
STRING
LONG
ROWID

Raw

RAW
LONG RAW

Integer

BINARY_INTEGER
PLS_INTEGER
SIMPLE_INTEGER
BOOLEAN
NATURAL
NATURALN
POSITIVE
POSITIVEN

Number

NUMBER
INT
INTEGER
SMALLINT
DEC
DECIMAL
REAL
FLOAT
NUMERIC
DOUBLE PRECISION

Datetime

DATE
TIMESTAMP
TIMESTAMP WITH TIME ZONE
TIMESTAMP WITH LOCAL TIME ZONE
INTERVAL YEAR TO MONTH
INTERVAL DAY TO SECOND

例18-5はパラメータhiredateのデータ型をVARCHAR2からDATEに変更します。VARCHAR2とDATEは同じデータ型クラスではないので、プロシージャget_hire_dateのRPCシグネチャが変更されます。

例18-5 get_hire_dateパラメータのデータ型クラスの変更

CREATE OR REPLACE PROCEDURE get_hire_date (
emp_number  IN  NUMBER,
hiredate    OUT DATE,
emp_name    OUT VARCHAR2) AS
BEGIN
SELECT last_name, TO_CHAR(hire_date, 'DD/MON/YYYY')
INTO emp_name, hiredate
FROM employees
WHERE employee_id = emp_number;
END;
/

パッケージ・タイプの変更

パッケージ・タイプの名前、または内部コンポーネントの名前を変更しても、パッケージのRPCシグネチャは変更されません。

例18-6では、パッケージemp_packageの内部にレコード型emp_data_typeが定義されます。次に、レコード・フィールドの名前が変更されます。レコード型は変更されません。最後に、レコード型の名前が変更されます。特性は変更されません。パッケージのRPCシグネチャは変更されません。

例18-6 パッケージ・レコード型のフィールド名の変更

CREATE OR REPLACE PACKAGE emp_package AS
TYPE emp_data_type IS RECORD (
emp_number  NUMBER,
hiredate    VARCHAR2(12),
emp_name    VARCHAR2(10)
);
PROCEDURE get_emp_data (
emp_data  IN OUT emp_data_type
);
END;
/

CREATE OR REPLACE PACKAGE emp_package AS
TYPE emp_data_type IS RECORD (
emp_num   NUMBER,
hire_dat  VARCHAR2(12),
empname   VARCHAR2(10)
);
PROCEDURE get_emp_data (
emp_data  IN OUT emp_data_type
);
END;
/

CREATE OR REPLACE PACKAGE emp_package AS
TYPE emp_data_record_type IS RECORD (
emp_num   NUMBER,
hire_dat  VARCHAR2(12),
empname   VARCHAR2(10)
);
PROCEDURE get_emp_data (
emp_data  IN OUT emp_data_record_type
);
END;
/

依存性モードの制御

動的初期化パラメータREMOTE_DEPENDENCIES_MODEは、依存性モードを制御します。初期化パラメータ・ファイルに次のように指定されているとします。この場合は、依存性を解決するためにタイムスタンプのみが使用されます(明示的かつ動的にオーバーライドされない場合)。

REMOTE_DEPENDENCIES_MODE = TIMESTAMP

初期化パラメータ・ファイルでパラメータが次のように指定されている場合は、依存性を解決するためにRPCシグネチャのみが使用されます(明示的かつ動的にオーバーライドされない場合)。

REMOTE_DEPENDENCIES_MODE = SIGNATURE

DDL文を使用して動的にモードを変更することができます。たとえば、次の例では現行セッションの依存性モードが変更されます。

ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = {SIGNATURE | TIMESTAMP}

次の例は、起動後にシステム全体の依存性モードを変更します。

ALTER SYSTEM SET REMOTE_DEPENDENCIES_MODE = {SIGNATURE | TIMESTAMP}

init.oraパラメータ・ファイルに、あるいはALTER SESSIONまたはALTER SYSTEM文を使用して、REMOTE_DEPENDENCIES_MODEパラメータが指定されない場合、TIMESTAMPがデフォルト値になります。したがって、REMOTE_DEPENDENCIES_MODEパラメータを明示的に使用するか適切なDDL文を使用しないかぎり、サーバーはタイムスタンプ依存性モードを使用して実行します。

REMOTE_DEPENDENCIES_MODE=SIGNATUREを使用すると、次のようになります。

- リモート・プロシージャのパラメータの初期値を変更しても、そのリモート・プロシージャをコールするローカル・プロシージャは無効になりません。リモート・プロシージャへのコールでパラメータが指定されない場合は、初期値が使用されます。この場合、無効化と再コンパイルが自動的には行われないため、古い初期値が使用されます。新しい初期値を確認するには、手動でコール側プロシージャを再コンパイルします。

- オーバーロードされたプロシージャ(既存プロシージャと同名のプロシージャ)をパッケージへ追加しても、リモート・プロシージャをコールするローカル・プロシージャは無効にされません。このオーバーロードの結果として、ローカル・プロシージャからの既存のコールがタイムスタンプ・モードで再バインドされた場合、ローカル・プロシージャは無効にされないため、RPCシグネチャ・モードでは、この再バインドは行われません。再バインドを成功させるには、ローカル・プロシージャを手動で再コンパイルする必要があります。

- 新しい型と以前の型が同じになるように既存のパッケージ・プロシージャのパラメータの型が変更された場合でも、ローカルのコール側プロシージャは自動的に無効化または再コンパイルされません。新しい型のセマンティクスを取得するには、コール側プロシージャを手動で再コンパイルする必要があります。

内容は次のとおりです。

- 依存性の解決

- 依存性管理の提案

依存性の解決

REMOTE_DEPENDENCIES_MODE = TIMESTAMP(デフォルト値)の場合、プログラム・ユニット間の依存性は、実行時にタイムスタンプを比較することで処理されます。コールされたリモート・プロシージャのタイムスタンプが、コールしたプロシージャのタイムスタンプと一致しない場合、コール側の(依存)ユニットは無効になり、再コンパイルする必要が生じます。この場合、ローカルPL/SQLコンパイラがない場合は、コール側のアプリケーションを処理できません。

タイムスタンプ依存性モードでは、RPCシグネチャは比較されません。ローカルPL/SQLコンパイラがある場合は、コール側プロシージャが実行されると自動的に再コンパイルされます。

REMOTE_DEPENDENCIES_MODE = SIGNATUREの場合、コール側のユニットの記録済タイムスタンプは、まず最初にコールされたリモート・ユニット内の現在のタイムスタンプと比較されます。タイムスタンプが一致すると、コールが処理されます。タイムスタンプが一致しない場合は、コールされたリモート・サブプログラムのRPCシグネチャは、コール側サブプログラムに記録されたままの状態で、コールされたサブプログラムの現在のRPCシグネチャと比較されます。(「パラメータのデータ型クラスの変更」で説明する基準を使用して)シグネチャが一致しない場合、エラーがコール元セッションに返されます。

依存性管理の提案

REMOTE_DEPENDENCIES_MODEパラメータを設定する際には、次のガイドラインに従います。

- サーバー側PL/SQLユーザーは、パラメータをTIMESTAMPに設定して(つまりデフォルトのままにして)タイムスタンプ依存性モードを使用できます。

- サーバー側PL/SQLユーザーが、分散システムを使用しており、不要な再コンパイルを回避したい場合には、RPCシグネチャ依存性モードを使用できます。

- クライアント側PL/SQLユーザーは、パラメータをSIGNATUREに設定する必要があります。こうすると、次のようになります。

- クライアント・サイトにアプリケーションをインストールするときに、プロシージャを再コンパイルする必要がありません。

- サーバーをアップグレードしてもタイムスタンプの不一致が発生しません。

- サーバー側でRPCシグネチャ・モードを使用するときは、プロシージャをパッケージ仕様部のプロシージャ(またはファンクション)宣言の最後に追加します。宣言リストの中間にプロシージャを追加すると、依存プロシージャの不必要な無効化と再コンパイルを引き起こすことがあります。

共有SQLの依存性管理

スキーマ・オブジェクト相互間の依存性管理に加えて、Oracle Databaseでは共有プール内の各共有SQL領域の依存性も管理します。表またはビュー、シノニム、順序を生成、変更または削除したり、プロシージャまたはパッケージ仕様部を再コンパイルすると、それらに依存する共有SQL領域もすべて無効になります。共有SQL領域が無効になった後で、その領域に対応するカーソルを実行すると、Oracle DatabaseによってSQL文が再解析されて、共有SQL領域が再生成されます。

19 エディションベースの再定義

エディションベースの再定義を使用すると、アプリケーションの使用中にそのデータベース・コンポーネントをアップグレードでき、停止時間を最小化あるいは排除することができます。

使用中にアプリケーションをアップグレードするには、アプリケーションを構成するデータベース・オブジェクトをコピーし、コピーしたオブジェクトを分離した状態で再定義します。変更内容はアプリケーションのユーザーには影響しません。ユーザーは変更されていないアプリケーションの実行を継続します。変更内容が正しいことを確認したら、アップグレードしたアプリケーションをすべてのユーザーが使用できるようにします。

エディションベースの再定義では、1つ以上のコンポーネント機能を使用します。使用する機能と停止時間は次の要素によって異なります。

- 再定義するデータベース・オブジェクトの種類

- データベース・オブジェクトの再定義中に、ユーザーがそのデータベース・オブジェクトをどの程度使用できるか

- 以前のアプリケーションを使用しているユーザーがいるときに、アップグレードしたアプリケーションを他のユーザーが使用できるようにするかどうか

データベース・オブジェクトをコピーし、コピーしたデータベース・オブジェクトを分離した状態で再定義するには、常にエディション機能を使用します。この章で説明するオンラインでのアプリケーション・アップグレード手順がエディションベースの再定義と呼ばれるのはこのためです。

再定義するすべてのオブジェクトのオブジェクト・タイプがエディション対応(定義は「エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ」を参照)の場合、使用する機能はエディションのみです。

表はエディション対応タイプではありません。1つ以上の表の構造を変更する場合は、エディショニング・ビュー機能も使用します。

表の構造を変更している間、他のユーザーがその表のデータを変更する必要がある場合は、forward crosseditionトリガーも使用します。アップグレード前のアプリケーションとアップグレード後のアプリケーションが同時に通常使用(ホット・ロールオーバー)されている場合、reverse crosseditionトリガーも使用します。crosseditionトリガーはアプリケーションの永続的な要素ではありません。全ユーザーがアップグレード後のアプリケーションを使用するようになったら削除します。

内容は次のとおりです。

- エディション

- エディショニング・ビュー

- crosseditionトリガー

- エディション、エディショニング・ビュー、crosseditionトリガーの情報の表示

- アプリケーションをアップグレードするためのエディションベースの再定義の使用

エディション

エディションはスキーマ・オブジェクトではなく、所有者もありません。エディションは1つのネームスペースに作成されます。複数のエディションがデータベースに共存することができます。

データベースには少なくとも1つのエディションが必要です。新規作成またはアップグレードされたOracle Databaseはすべて、ora$baseという名前の1つのエディションから開始されます。

内容は次のとおりです。

- エディション・オブジェクトと非エディション・オブジェクト

- エディションの作成

- 継承オブジェクトと実オブジェクト

- 一部のユーザーに対してエディションを使用可能にする

- すべてのユーザーに対してエディションを使用可能にする

- 現行エディションとセッション・エディション

- エディションのリタイア

- エディションの削除

エディション・オブジェクトと非エディション・オブジェクト

エディション・オブジェクトは、エディション対応タイプとエディションが有効化された所有者の両方を持つスキーマ・オブジェクトです。(エディション対応タイプは持っているが、エディションが有効化された所有者を持たないスキーマ・オブジェクトは潜在的エディションです。)この場合、そのエディションに対してはこのコピーのみが表示可能です。

非エディション・オブジェクトは、非エディション・タイプのスキーマ・オブジェクトです。エディションは、非エディション・オブジェクトの独自のコピーを持つことはできません。非エディション・オブジェクトは、すべてのエディションで同一です。また、どのエディションでも表示できます。

エディション・オブジェクトは、そのOBJECT_NAME、OWNER、およびEDITION_NAMEにより一意に識別されます。非エディション・オブジェクトは、そのOBJECT_NAMEおよびOWNERにより(EDITION_NAMEはNULL)一意に識別されます(厳密に言えば、オブジェクトを一意に識別するにはオブジェクトのNAMESPACEも必要ですが、オブジェクトを参照する文では暗黙的または明示的にNAMESPACEが指定されるので、これは無視しても構いません)。

オブジェクトのOBJECT_NAME、OWNER、およびEDITION_NAMEは、静的ディクショナリ・ビュー*_OBJECTSおよび*_OBJECTS_AEに表示できます(表19-1を参照)。

オブジェクトのEDITION_NAMEを知らなくても、このオブジェクトを参照できます(知っていても、指定できません)。参照のコンテキストで、エディションを暗黙的に指定します。コンテキストがデータ定義言語(DDL)文である場合、エディションは、このコマンドを発行したセッションの現行エディションです(現行エディションの詳細は、「現行エディションとセッション・エディション」を参照)。コンテキストがソース・コードである場合、エディションはオブジェクトが実オブジェクトであるものです(「継承オブジェクトと実オブジェクト」を参照)。

内容は次のとおりです。

- エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ

- エディション・オブジェクトの規則

- ユーザーに対するエディションの有効化

エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ

次のスキーマ・オブジェクト・タイプはエディション対応です。

- SYNONYM

- VIEW

- すべてのPL/SQLオブジェクト型:

- FUNCTION

- LIBRARY

- PACKAGEおよびPACKAGE BODY

- PROCEDURE

- TRIGGER

- TYPEおよびTYPE BODY

その他のスキーマ・オブジェクト・タイプはすべて非エディション対応です。表は非エディション対応タイプの一例です。

エディション対応タイプのスキーマ・オブジェクトは、その所有者に対してエディションが有効化されている場合はエディション化されます。それ以外の場合は、潜在的エディション・オブジェクトです。

非エディション対応タイプのスキーマ・オブジェクトは、その所有者に対してエディションが有効化されていても、常にエディション化できません。表は非エディション・オブジェクトの一例です。

注意:
この規則には1つ例外があります。SYNONYMはエディション対応タイプですが、パブリック・シノニムは非エディション・オブジェクトです。

エディション・オブジェクトの規則

- 非エディション・オブジェクトは、エディション・オブジェクトに依存できません。
次に例を示します。

- パブリック・シノニムは、エディション・オブジェクトを参照できません。

- ファンクション索引は、エディション・ファンクションに依存できません。

- マテリアライズド・ビューは、エディション・ビューに依存できません。

- 表は、エディションが有効化されているユーザーを所有者とするユーザー定義のデータ型(コレクションまたは抽象データ型(ADT))の列を持つことはできません。

- 非エディション・サブプログラムは、エディションが有効化されているユーザーを所有者とするサブプログラムを静的に参照することはできません。

この規則の理由については、「参照されているオブジェクトの実オブジェクト化」を参照してください。

- ADTをエディション化し、同時に進化させることはできません。
型進化の詳細は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。

- エディション・オブジェクトを、FOREIGN KEY制約の始点、または終点にすることはできません。
この規則が影響するエディション・オブジェクトは、エディション化されたビューのみです。エディション化されたビューとは、通常のビュー、またはエディショニング・ビューのどちらかです。

ユーザーに対するエディションの有効化

ユーザーに対してエディションを有効化するには、CREATE USER、またはALTER USER文のENABLE EDITIONS句を使用します。

静的データ・ディクショナリ・ビューDBA_USERSまたはUSER_USERSのEDITIONS_ENABLED列に、エディションが有効化されているユーザーが示されます。

エディションの有効化は遡及的で、これを元に戻すことはできません。ユーザーに対してエディションが有効化されている場合、このユーザーが所有している、または将来所有するエディション対応タイプのオブジェクトはすべて、エディション・オブジェクトです。次のようにして、FORCEを指定しないかぎり、エディション化されていない依存オブジェクトを持ち、潜在的エディション・オブジェクトを所有するユーザーに対してエディションを有効化することはできません。

ALTER USER user_name ENABLE EDITIONS FORCE;

FORCEは、次の状況で便利です。ユーザーAとBに対してエディションを有効化する必要がある場合。ユーザーAが潜在的エディション・オブジェクトa1とa2の所有者である場合。ユーザーBが潜在的エディション・オブジェクトb1とb2の所有者である場合。オブジェクトa1がオブジェクトb1に依存している場合。オブジェクトb2がオブジェクトa2に依存している場合。ユーザーAとBに対してエディションを有効化させるには、次のようにします。

1. FORCEを使用して、ユーザーAについてエディションを有効化します。

ALTER USER A ENABLE EDITIONS FORCE;

これで、a1とa2はエディション・オブジェクトになり、b2(a2に依存するもの)は無効になりました。

2. ユーザーBのエディションを有効化します。

ALTER USER B ENABLE EDITIONS;

3. COMPILEで、適切なALTER文を使用して、b2を再コンパイルします。PL/SQLオブジェクトについては、REUSE SETTINGSも指定してください。
たとえば、b2がプロシージャの場合、次の文を使用します。

ALTER PROCEDURE b2 COMPILE REUSE SETTINGS

PL/SQLオブジェクトのためのALTER文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

SQLオブジェクトのためのALTER文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

FORCEは、次の状況では必要ありません。潜在的エディション・オブジェクトc1を所有しているユーザーCに対してエディションを有効化する必要がある場合。オブジェクトc1が、ユーザーDにより所有されていて、潜在的エディション依存オブジェクトd1を持っている場合。ユーザーDが、所有者がCである依存オブジェクトを持つ、潜在的エディション・オブジェクトを所有していない場合。最初にd1をエディション・オブジェクトにして、Dに対してエディションを有効化した場合、非エディション・オブジェクトはエディション・オブジェクトに依存できないという規則に違反せずに、Cに対してエディションを有効化することができます。

1つ以上の進化したADTを所有するユーザーに対してエディションを有効化することはできません。有効化しようとすると、エラーORA-38820が発生します。ADTが表への依存性を持っていない場合、ALTER TYPE RESET文を使用して、バージョンを1にリセットすることにより、それ以上、表が進化するとみなされないようにすることができます(ADTのバージョンを1にリセットすると、これに依存するものは無効化されます。)

参照:

- CREATE USERおよびALTER USER文の構文は、『Oracle Database SQL言語リファレンス』を参照してください。

- 静的データ・ディクショナリ・ビュー*_USERSの詳細は、『Oracle Databaseリファレンス』を参照してください。

エディションの作成

エディションを作成するには、SQL文CREATE EDITIONを使用します。

エディションは既存のエディションの子として作成する必要があります。CREATE EDITION文によって作成される最初のエディションの親はora$baseです。次の文によって、ora$baseの子としてエディションe2が作成されます。

CREATE EDITION e2

(例19-1などでこの文が使用されています。)

Oracle Database 11gリリース2では、エディションの子は最大で1つです。

エディションの子孫は、エディションの子、子の子、その子などを指します。エディションの祖先は、エディションの親、親の親、その親などを指します。ルート・エディションには親はありません。また、リーフ・エディションには子はありません。

参照:
使用するための権限も含む、CREATE EDITION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

継承オブジェクトと実オブジェクト

各データベース・セッションで一度に使用されるエディションは1つのみです。作成時に子エディションは、親エディションで表示可能なデータベースのすべてのエディション・オブジェクトを親エディションから継承します。各継承オブジェクトは子エディションで表示可能です。

継承オブジェクトは、変更時にコピー、すなわち実オブジェクト化されます。つまり、子エディションのユーザーがDDL文(DROP以外)で継承オブジェクトを参照すると、継承オブジェクトはコピーされ、DDL文はコピー(実オブジェクト)のみに作用します。親エディション内の未変更のオブジェクトは、子エディションでは表示可能ではなくなります。

注意:
DDL文CREATE OR REPLACE objectに効果がない場合、objectは実オブジェクト化されません(詳細は、「依存オブジェクトの無効化」を参照)。DDL文ALTER object COMPILEは、常にobjectを実オブジェクト化します。

例19-1は、エディションora$baseでプロシージャhelloを作成してから、ora$baseの子としてエディションe2を作成します。e2がhelloを起動するときは、継承プロシージャを起動します。このとき、e2はhelloを変更して、実オブジェクト化します。エディションora$baseのプロシージャhelloは変更されず、e2には表示されなくなります。ここで、e2がhelloを起動するときは、実プロシージャを起動します。

例19-1 継承オブジェクトと実オブジェクト

1. 親エディションでプロシージャを作成します。

CREATE OR REPLACE PROCEDURE hello IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello, edition 1.');
END hello;
/

2. 親エディションでプロシージャを起動します。

BEGIN hello(); END;
/

結果:

Hello, edition 1.

PL/SQL procedure successfully completed.

3. 子エディションを作成します。

CREATE EDITION e2;

4. 子エディションを使用します。

ALTER SESSION SET EDITION = e2;

ALTER SESSION SET EDITIONの詳細は、「セッション・エディションの変更」を参照してください。

5. 子エディションで、次のプロシージャを起動します。

BEGIN hello(); END;
/

子エディションは、親エディションからプロシージャを継承します。子エディションにより、継承したプロシージャが起動されます。結果:

Hello, edition 1.

PL/SQL procedure successfully completed.

6. 子エディションでプロシージャを変更します。

CREATE OR REPLACE PROCEDURE hello IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello, edition 2.');
END hello;
/

子は、プロシージャの独自のコピーのみ変更します。子のコピーは実オブジェクトです。

7. プロシージャを起動します。

BEGIN hello(); END;
/

子は独自のコピー、実プロシージャを起動します。

Hello, edition 2.

PL/SQL procedure successfully completed.

8. 親に戻ります。

ALTER SESSION SET EDITION = ora$base;

9. プロシージャを起動し、これが変更されていないことを確認します。

BEGIN hello(); END;
/

結果:

Hello, edition 1.

PL/SQL procedure successfully completed.

内容は次のとおりです。

- 継承オブジェクトの削除

- 参照されているオブジェクトの実オブジェクト化

継承オブジェクトの削除

子エディションのユーザーが継承オブジェクトを削除すると、そのオブジェクトは子エディションでは表示されなくなりますが、親エディションでは引き続き表示可能です。

例19-2は、エディションora$baseでプロシージャgoodbyeを作成してから、ora$baseの子としてエディションe2を作成します。e2でgoodbyeが削除されると、e2はgoodbyeを起動できなくなりますが、ora$baseでは起動できます(使用するための権限も含む、DROP PROCEDURE文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください)。

例19-2 継承オブジェクトの削除

1. エディションora$baseでプロシージャを作成します。

CREATE OR REPLACE PROCEDURE goodbye IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Good-bye!');
END goodbye;
/

2. プロシージャを起動します。

BEGIN goodbye; END;
/

結果:

Good-bye!

PL/SQL procedure successfully completed.

3. ora$baseの子としてエディションe2を作成します。

CREATE EDITION e2;

4. エディションe2を使用します。

ALTER SESSION SET EDITION = e2;

ALTER SESSION SET EDITIONはトップレベルのSQL文である必要があります。詳細は、「セッション・エディションの変更」を参照してください。

5. e2で、次のプロシージャを起動します。

BEGIN goodbye; END;
/

e2により、継承されたプロシージャが起動されます。

Good-bye!

PL/SQL procedure successfully completed.

6. e2で、次のプロシージャを削除します。

DROP PROCEDURE goodbye;

7. e2で、削除したプロシージャの起動を試行します。

BEGIN goodbye; END;
/

結果:

BEGIN goodbye; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'GOODBYE' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

8. 親に戻ります。

ALTER SESSION SET EDITION = ora$base;

9. 親で、次のプロシージャを起動します。

BEGIN goodbye; END;
/

結果:

Good-bye!

PL/SQL procedure successfully completed.

e2でプロシージャgoodbyeが削除されたため、次のようになります。

- 子孫では、プロシージャgoodbyeが継承されません。

- goodbyeというオブジェクトはe2で表示可能でないため、e2では、任意のエディション対応タイプのオブジェクトをgoodbyeという名前を付けて作成できます。e2でこのようなオブジェクトが作成された場合、e2の子孫はこのオブジェクトを継承します。

例19-3では、e2にgoodbyeという名前のファンクションが作成され、その後、e2の子としてe3という名前のエディションが作成されます。e3でプロシージャgoodbye(e2で削除)を起動しようとすると、エラーが発生しますが、e3でファンクションgoodbye(e2で作成)は正常に起動されます。

例19-3 削除済継承オブジェクトの名前を使用したオブジェクトの作成

1. e2に戻ります。

ALTER SESSION SET EDITION = e2;

ALTER SESSION SET EDITIONの詳細は、「セッション・エディションの変更」を参照してください。

2. e2で、goodbyeという名前のファンクションを作成します。

CREATE OR REPLACE FUNCTION goodbye
RETURN BOOLEAN
IS
BEGIN
RETURN(TRUE);
END goodbye;
/

3. エディションe3を作成します。

CREATE EDITION e3 AS CHILD OF e2;

4. エディションe3を使用します。

ALTER SESSION SET EDITION = e3;

5. e3で、プロシージャgoodbyeの起動を試行します。

BEGIN
goodbye;
END;
/

結果:

goodbye;
*
ERROR at line 2:
ORA-06550: line 2, column 3:
PLS-00221: 'GOODBYE' is not a procedure or is undefined
ORA-06550: line 2, column 3:
PL/SQL: Statement ignored

6. e3で、ファンクションgoodbyeを起動します。

BEGIN
IF goodbye THEN
DBMS_OUTPUT.PUT_LINE('Good-bye!');
END IF;
END;
/

結果:

Good-bye!

PL/SQL procedure successfully completed.

参照されているオブジェクトの実オブジェクト化

あるエディションで参照オブジェクトが実オブジェクト化されると、そのエディションにあるそのオブジェクトのすべての直接依存オブジェクトと間接依存オブジェクトが実オブジェクト化されて無効な状態になります。したがって、エディション・オブジェクトは、実オブジェクト化できない依存オブジェクトを持つことはできません。言い換えれば、非エディション・オブジェクトは、エディション・オブジェクトに依存できません(例については、「エディション・オブジェクトの規則」を参照)。

無効なオブジェクトが参照されている場合、データベースは自動的にこれを検証しますが、そのためには名前解決が必要です。データベースはまず、現行エディションでこのオブジェクト名を探し、次に親エディションの検索に進みます。

参照:
無効化、再有効化、名前解決を含む、スキーマ・オブジェクト間の依存性の詳細は、第18章「スキーマ・オブジェクトの依存性」を参照してください。

一部のユーザーに対してエディションを使用可能にする

エディションの作成者には、エディションに対するUSE権限WITH GRANT OPTIONが自動的に付与されます。他のユーザーにエディションのUSE権限を付与するには、SQL文GRANT USE ON EDITIONを使用します。GRANT文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

すべてのユーザーに対してエディションを使用可能にする

すべてのユーザーがエディションを使用できるようにするには、次のいずれかの手順を実行します。

- エディションのUSE権限をPUBLICに付与します。

GRANT USE ON EDITION edition_name TO PUBLIC

GRANT文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- このエディションを、データベースのデフォルト・エディションにします。

ALTER DATABASE DEFAULT EDITION = edition_name

これには、edition_nameのUSE特権がPUBLICに付与されるという副作用もあります。

ALTER DATABASE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

現行エディションとセッション・エディション

各データベース・セッションで一度に使用されるエディションは1つのみです。データベース・セッションがある時点で使用するエディションは、現行エディションと呼ばれます。データベース・セッションが開始すると、現行エディションがセッション・エディションになります。これは、データベース・セッションが開始するときのエディションです。セッション・エディションを変更すると、現行エディションも同様に変更されます。ただし、現行エディションとセッション・エディションが異なる状況もあります。

内容は次のとおりです。

- 最初のセッション・エディション

- セッション・エディションの変更

- 現行エディション名とセッション・エディション名の表示

- 現行エディションがセッション・エディションと異なる状況

最初のセッション・エディション

データベースに接続するときに、最初のセッション・エディションを指定できます。USE権限を持っている任意のエディションを最初のセッション・エディションにすることができます。使用できるエディションの名前を表示するには、次の問合せを使用します。

SELECT EDITION_NAME FROM ALL_EDITIONS;

接続時に最初のセッション・エディションをどのように指定するかは、データベースの接続方法によって異なります。インタフェースのドキュメントを参照してください。

参照:

- デフォルト・エディションの設定の詳細は、『Oracle Database管理者ガイド』を参照してください。

- SQL*Plusを使用するデータベースへの接続の詳細は、『SQL*Plusユーザーズ・ガイドおよびリファレンス』を参照してください。

- Oracle Call Interface(OCI)を使用するデータベースへの接続の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

- JDBCを使用するデータベースへの接続の詳細は、『Oracle Database JDBC開発者ガイド』を参照してください。

Oracle Database 11gリリース2 (11.2.0.2)では、接続時にセッション・エディションを指定しない場合、次のようになります。

- データベース・サービスを使用してデータベースに接続し、そのサービスで最初のセッション・エディションが指定された場合、そのサービスの最初のセッション・エディションが最初のセッション・エディションになります。

- そうでない場合、データベースのデフォルト・エディションが最初のセッション・エディションになります。

リリース11.2.0.2では、データベース・サービスの作成または変更時に、その最初のセッション・エディションを指定できます。

データベース・サービスを作成または変更にするには、srvctl add serviceまたはsrvctl modify serviceコマンドを使用することをお薦めします。サービスのデフォルトの最初のセッション・エディションを指定するには、-tオプションを使用します。

また、DBMS_SERVICE.CREATE_SERVICEまたはDBMS_SERVICE.MODIFY_SERVICEプロシージャを使用してデータベース・サービスを作成または変更して、EDITION属性を使用してデフォルトの最初のセッション・エディションを指定できます。

注意:
Oracle Database 11gリリース2では、DBMS_SERVICE.CREATE_SERVICEおよびDBMS_SERVICE.MODIFY_SERVICEプロシージャは、Oracle ClusterwareおよびOracle Restartにより管理されるデータベースで非推奨です。

参照:

- srvctl add serviceコマンドの-tオプションの詳細は、『Oracle Database管理者ガイド』を参照してください。

- srvctl modify serviceコマンドの-tオプションの詳細は、『Oracle Database 管理者ガイド』を参照してください。

- DBMS_SERVICE.CREATE_SERVICEプロシージャのEDITION属性の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- DBMS_SERVICE.MODIFY_SERVICEプロシージャのEDITION属性の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

セッション・エディションの変更

データベースに接続した後で、SQL文ALTER SESSION SET EDITIONを使用してセッション・エディションを変更することができます。セッション・エディションは、USE権限のある任意のエディションに変更することができます。セッション・エディションを変更すると、現行エディションも同じセッション・エディションに変更されます。

例19-1および例19-2に含まれる次の文は、まずセッション・エディション(現行エディション)をe2に変更し、その後ora$baseに変更します。

ALTER SESSION SET EDITION = e2
...
ALTER SESSION SET EDITION = ora$base

注意:
ALTER SESSION SET EDITIONはトップレベルのSQL文である必要があります。たとえば、ログオン・トリガーでエディションの変更を遅らせるには、DBMS_SESSION.SET_EDITION_DEFERREDプロシージャを使用します。

参照:

- ALTER SESSION SET EDITION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- DBMS_SESSION.SET_EDITION_DEFERREDプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

現行エディション名とセッション・エディション名の表示

次の文によって、現行エディションの名前が返されます。

SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') FROM DUAL;

次の文によって、セッション・エディションの名前が返されます。

SELECT SYS_CONTEXT('USERENV', 'SESSION_EDITION_NAME') FROM DUAL;

参照:
SYS_CONTEXT関数の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

現行エディションがセッション・エディションと異なる状況

次のような場合に、現行エディションがセッション・エディションと異なることがあります。

- crosseditionトリガーが起動される場合。
詳細は、「crosseditionトリガーとエディションの相互作用」を参照してください。

- 例19-4のように、DBMS_SQL.PARSEプロシージャをコールして、文を実行するエディションを指定することで、文を実行する場合。
文が実行している間、指定されたエディションが現行エディションになりますが、セッション・エディションは変更されません。DBMS_SQL.PARSEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例19-4では、セッション・エディションと現行エディションの名前を返すファンクションが作成されます。その後、子エディションが作成され、子エディションによってそのファンクションが2回起動されます。1回目はセッション・エディションと現行エディションは同じです。2回目は異なります。別のエディションがパラメータとしてDBMS_SQL.PARSEプロシージャに渡されるためです。

例19-4 セッション・エディションと異なる現行エディション

1. セッション・エディションと現行エディションの名前を返すファンクションを作成します。

CREATE OR REPLACE FUNCTION session_and_current_editions
RETURN VARCHAR2
IS
BEGIN
RETURN
'Session: '|| SYS_CONTEXT('USERENV', 'SESSION_EDITION_NAME') ||
' / ' ||
'Current: '|| SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME');
END session_and_current_editions;
/

2. 子エディションを作成します。

CREATE EDITION e2 AS CHILD OF ora$base;

3. 子エディションを使用します。

ALTER SESSION SET EDITION = e2;

4. ファンクションを起動します。

BEGIN
DBMS_OUTPUT.PUT_LINE (session_and_current_editions());
END;
/

結果:

Session: E2 / Current: E2

PL/SQL procedure successfully completed.

5. ファンクションをもう一度起動します。

DECLARE
c     NUMBER := DBMS_SQL.OPEN_CURSOR();
v     VARCHAR2(200);
dummy NUMBER;
stmt  CONSTANT VARCHAR2(32767)
:= 'SELECT session_and_current_editions() FROM DUAL';
BEGIN
DBMS_SQL.PARSE (c => c,
statement => stmt,
language_flag => DBMS_SQL.NATIVE,
edition => 'ora$base');

DBMS_SQL.DEFINE_COLUMN (c, 1, v, 200);
dummy := DBMS_SQL.EXECUTE_AND_FETCH (c, true);
DBMS_SQL.COLUMN_VALUE (c, 1, v);
DBMS_SQL.CLOSE_CURSOR(c);
DBMS_OUTPUT.PUT_LINE (v);
END;
/

結果:

Session: E2 / Current: ORA$BASE

PL/SQL procedure successfully completed.

エディションのリタイア

新しいエディション(アップグレードしたアプリケーション)をすべてのユーザーが使用できるようにしたら、SYS以外のユーザーがリタイアしたエディションを使用できないようにするために、古いエディション(元のアプリケーション)をリタイアさせます。

注意:
古いエディションがデータベースのデフォルト・エディションである場合は、この古いエディションをリタイアさせる前に、別のエディションをデフォルトにします。

ALTER DATABASE DEFAULT EDITION = edition_name

ALTER DATABASE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディションをリタイアさせるには、このエディションに対するUSE権限を、すべての権限受領者から取り消します。権限受領者のリストを表示するには、次の問合せを使用します。ここで、eには削除するエディションの名前が入ります。

SELECT GRANTEE, PRIVILEGE
FROM DBA_TAB_PRIVS
WHERE TABLE_NAME = :e
/

REVOKE文の詳細は『Oracle Database SQL言語リファレンス』を参照してください。

エディションの削除

注意:
エディションにcrosseditionトリガーが含まれている場合は、エディションを削除する前に、「crosseditionトリガーの削除」を参照してください。

エディションを削除するには、DROP EDITION文を使用します。詳細は、『Oracle Database SQL言語リファレンス』を参照してください。エディションに実オブジェクトがある場合は、実オブジェクトを削除するCASCADE句を指定する必要があります。

DROP EDITION edition CASCADE文が正常終了前に(たとえば、停電などの理由で)中断された場合、静的データ・ディクショナリ・ビュー*_EDITIONSには、editionに対するUSABLEの値がNOであることが表示されます。このように使用できないeditionに対して実行できる唯一の操作は、DROP EDITION CASCADEです。

エディションは次の場合に削除します。

- アプリケーション・アップグレードをロールバックする必要がある場合。

- (オプション)エディションをリタイアさせた場合。

エディションを削除できるのは、次のすべての条件に該当する場合のみです。

- エディションがルート・エディション、またはリーフ・エディションである場合。

- エディションがルートの場合、その子孫により継承されているオブジェクトを持っていない場合。(つまり、ルート・エディションから継承された各オブジェクトは、実オブジェクト化されたか、削除された場合)。

- エディションが使用されていない場合(つまり、セッションの現行エディションまたはセッション・エディションではない場合)。

- このエディションが、データベースのデフォルト・エディションではない場合。

子エディションで継承オブジェクトを明示的に実オブジェクト化するには、次のようにします。

1. 子エディションをセッション・エディションにします。
手順は、「セッション・エディションの変更」を参照してください。

2. COMPILEで、適切なALTER文を使用して、このオブジェクトを再コンパイルします。PL/SQLオブジェクトについては、REUSE SETTINGSも指定してください。
たとえば、次の文ではプロシージャp1が実オブジェクト化されます。

ALTER PROCEDURE p1 COMPILE REUSE SETTINGS

PL/SQLオブジェクトのためのALTER文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

SQLオブジェクトのためのALTER文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

参照:

- ALTER LIBRARY文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- ALTER VIEW文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- ALTER FUNCTION文の詳細は、Oracle Database PL/SQLリファレンスを参照

- ALTER PACKAGE文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- ALTER PROCEDURE文の詳細は、Oracle Database PL/SQL言語リファレンスを参照

- ALTER TRIGGER文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

- ALTER TYPE文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

エディショニング・ビュー

エディショニング・ビューを作成する前に、エディショニング・ビューの所有者に対してエディションを有効化しておく必要があります。

エディショニング・ビュー以外のビューで定義できるトリガーのタイプは、INSTEAD OFトリガーのみです。エディショニング・ビューでは、表で定義できるトリガー・タイプすべてを定義できます(ただし、crosseditionトリガー(一時トリガー)とINSTEAD OF トリガーは例外です)。このため、またエディショニング・ビューはエディション化が可能であることによって、エディショニング・ビューを使用することで、実表がエディション化されたかのように扱うことができます。ただし、アップグレードされたアプリケーションにより、新しい索引または制約が必要とされる場合、エディショニング・ビューに索引または制約を追加することはできません。これらは実表に追加する必要があります。

エディショニング・ビューは1つの実表の列のサブセットを選択し、オプションとしてそれらの列に別名を提供します。別名を提供するとき、エディショニング・ビューは物理列名(実表で使用される)を論理列名(アプリケーションで使用される)にマップします。エディショニング・ビューは、表のAPIに似ています。

直接ではなく、エディショニング・ビュー経由で表にアクセスすることに対するパフォーマンス・ペナルティはありません。つまり、SQL SELECT、INSERT、UPDATE、DELETE、またはMERGE文で1つ以上のエディショニング・ビューが1回以上使用されているときに、必要に応じて、エディショニング・ビューの名前を実表の名前で置き換え、列名を調整した場合でも、パフォーマンスは変わりません。

静的データ・ディクショナリ・ビュー*_EDITIONING_VIEWSは、セッション・エディションで表示可能なデータベース内のすべてのエディショニング・ビュー(実エディショニング・ビューまたは継承エディショニング・ビュー)を示します。*_EDITIONING_VIEWS_AEは、すべてのエディションにおけるデータベース内のすべてのエディショニング・ビューのすべての実オブジェクトを示します。

内容は次のとおりです。

- エディショニング・ビューの作成

- パーティション拡張エディショニング・ビュー名

- エディショニング・ビューの書込み可能性の変更

- エディショニング・ビューの置換

- 実表の削除または名前変更

- 実表への索引と制約の追加

- SQLオプティマイザ索引ヒント

参照:
静的データ・ディクショナリ・ビュー*_EDITIONING_VIEWSおよび*_EDITIONING_VIEWS_AEの詳細は、『Oracle Databaseリファレンス』を参照してください。

エディショニング・ビューの作成

エディショニング・ビューを作成するには、SQL文CREATE VIEWをキーワードEDITIONINGとともに使用します。エディショニング・ビューを読取り専用にするには、WITH READ ONLYを指定します。読取り/書込みにするにはWITH READ ONLYを省略します。

エディショニング・ビューが読取り専用の場合、未変更アプリケーションのユーザーが実表のデータを見ることはできますが、変更することはできません。この実表は準可用性を備えています。準可用性を利用できるのは、ユーザーが読むだけで変更しない、オンライン・ディクショナリなどのアプリケーションです。実表にcrosseditionトリガーを定義しない場合は、エディショニング・ビューを読取り専用にします。

エディショニング・ビューが読取り/書込みの場合、未変更アプリケーションのユーザーが、実表のデータを見ることも変更することもできます。この実表は最大可用性を備えています。最大可用性が必要となるのは、ユーザーが注文を発行するオンライン・ストアなどのアプリケーションです。実表にcrosseditionトリガーを定義する場合は、エディショニング・ビューを読取り/書込みにします。

エディショニング・ビューは、実表からの列のサブセットの選択と列の別名提供の他にも機能を実行する必要があるため、エディショニング・ビューを作成するCREATE VIEW文には制限があります。制限に違反すると、FORCEを指定していてもビューの作成が失敗します。

参照:
制限を含む、CREATE VIEW文を使用したエディショニング・ビューの作成の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

パーティション拡張エディショニング・ビュー名

パーティション表に定義されているエディショニング・ビューには、パーティション拡張名を付けることができます。この名前は、実表のパーティションおよびサブパーティションを示すパーティション名とサブパーティション名を含みます。

パーティション拡張表名に対応するデータ操作言語(DML)は、パーティション拡張エディショニング・ビュー名にも対応します。次の文が対応しています。

- DELETE

- INSERT

- SELECT

- UPDATE

参照:
パーティション表の参照の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディショニング・ビューの書込み可能性の変更

既存のエディショニング・ビューを読取り専用から読取り/書込みに変更するには、SQL文ALTER VIEW READ WRITEを使用します。既存のエディショニング・ビューを読取り/書込みから読取り専用に変更するには、SQL文ALTER VIEW READ ONLYを使用します。

参照:
ALTER VIEW文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディショニング・ビューの置換

エディショニング・ビューを置換するには、SQL文CREATE VIEWをOR REPLACE句およびキーワードEDITIONINGとともに使用します。

エディショニング・ビューを置換できるのは別のエディショニング・ビューのみです。置換対象のエディショニング・ビューに定義されているトリガーはすべて保持されます。

実表の削除または名前変更

エディショニング・ビューの定義が基づいている実表を削除したり名前を変更したりしても、エディショニング・ビューは削除されませんが、エディショニング・ビューとその依存オブジェクトが無効になります。ただし、エディショニング・ビューに定義されているトリガーはすべて保持されます。

実表への索引と制約の追加

アップグレードされたアプリケーションにより、新しい索引または制約が必要とされる場合は、これらを実表に追加する必要があります。これらをエディショニング・ビューに追加することはできません。

新しい索引が古いエディション(元のアプリケーション)に悪い影響を与える場合は、これらを非表示にします。新しい索引の使用が必要なcrosseditionトリガーで、これらをINDEXヒントに指定します。

すべてのユーザーがアップグレードされたアプリケーションのみを使用している場合は、次のようにします。

- 新しい索引を使用しているのがcrosseditionトリガーのみである場合は、これらの索引を削除します。

- アップグレードされたアプリケーションが新しい索引で便利である場合は、これらを表示します。

参照:

- どのような場合に索引を使用するかについては、「索引の管理のガイドライン」を参照してください。

- INDEXヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- 「SQLオプティマイザ索引ヒント」

SQLオプティマイザ索引ヒント

SQLオプティマイザ索引ヒントは、索引を構成する列の論理名を使用して指定されます。論理列名を使用してエディショニング・ビューに指定されたSQLオプティマイザ索引ヒントは、実表の対応する物理列の索引にマップする必要があります。

参照:
ヒントの使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

crosseditionトリガー

crosseditionトリガーと非crosseditionトリガーの最も大きな違いは、エディションとの相互作用の方法です。crosseditionトリガーは、それが実であるエディションにのみ表示されます。子孫エディションでは表示されません。forward crosseditionトリガーは、データを古いエディションが使用していた列から、新しいエディションが使用している列に移動します。reverse crosseditionトリガーは逆方向へデータを移動します。

この他の重要な違いは次のとおりです。

- crosseditionトリガーは、他の表に定義されたトリガーに対して並べ替えることができますが、非crosseditionトリガーは同じ表に定義されたトリガーに対してのみ並べ替えることができます。

- crosseditionトリガーは一時的に使用します。構成を変更した表をすべてのユーザーが使用できるようにした後で削除します。

内容は次のとおりです。

- forward crosseditionトリガー

- reverse crosseditionトリガー

- crosseditionトリガーとエディションの相互作用

- crosseditionトリガーの作成

- アップグレード前の表現をアップグレード後の表現に変換

- crosseditionトリガーの削除

参照:
トリガーの詳細は、Oracle Database PL/SQL言語リファレンスを参照

forward crosseditionトリガー

アップグレード後のエディションでDML変更を表に行うと、新しい列または新しい表のみに書き込まれ、アップグレード前(祖先)エディションのユーザーが読取りまたは書込みを行う可能性がある列に対しては行われません。ただし、祖先エディションのユーザーが表データを変更する場合、表示しているエディショニング・ビューがそれらの変更内容を正確に反映する必要があります。これは、forward crosseditionトリガーを使用することで実現します。

forward crosseditionトリガーはトランスフォームを定義します。これは、古い行を1つ以上の新しい行に変換するための規則です。古い行は、アップグレード前の表現に含まれるデータ行です。新しい行は、アップグレード後の表現に含まれるデータ行です。トリガーの名前はトリガー自体、およびこのトリガーにより定義された変換を表します。

reverse crosseditionトリガー

アップグレード前のエディションとアップグレード後のエディションが同時に通常使用(ホット・ロールオーバー)されている場合、reverse crosseditionトリガーを使用して、アップグレード後エディションのユーザーが表データを変更するときに、変更内容がアップグレード前エディションに正確に反映されるようにします。

crosseditionトリガーとエディションの相互作用

crosseditionトリガーと非crosseditionトリガーの最も大きな違いは、エディションとの相互作用の方法です。

ここでは、現行エディションは、トリガーを起動するDML文が実行されるエディションを指します。現行エディションはセッション・エディションと異なることがあります(詳細は、「現行エディションがセッション・エディションと異なる状況」を参照)。

- 表示可能なトリガー

- 起動できるトリガーの種類

- 起動順序

- crosseditionトリガーの実行

表示可能なトリガー

エディションは、非crosseditionトリガーを他のエディション・オブジェクトと同じように継承します(「継承オブジェクトと実オブジェクト」を参照)。

エディションはcrosseditionトリガーは継承しません。crosseditionトリガーは、別のエディションで実行されるDML文に対応して起動されることもありますが、名前が表示されるのは作成されたエディションのみです。したがって、エディションでは、祖先エディションで作成されたcrosseditionトリガーの名前を再利用できます。crosseditionトリガーの名前を再利用しても、古いトリガーの起動条件は変更されません。

静的データ・ディクショナリ・ビューに示されるcrosseditionトリガーは、現行エディションの実オブジェクトです。

起動できるトリガーの種類

起動できるトリガーの種類は、トリガーするDML文のカテゴリによって異なります。このカテゴリは次のとおりです。

- 「forward crosseditionトリガーSQL」

- 「reverse crosseditionトリガーSQL」

- 「アプリケーションSQL」

注意:
SQL INSERT文にAPPENDヒントを指定してもcrosseditionトリガーの起動を防ぐことはできません。APPENDヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

forward crosseditionトリガーSQL

forward crosseditionトリガーSQLは、次のいずれかの方法で実行されるSQLです。

- forward crosseditionトリガー本体から直接起動
forward croseditionトリガーのローカル・サブプログラムが起動された場合のみ、このカテゴリには、起動されたサブプログラムのSQLが含まれます。

- apply_crossedition_triggerパラメータに対してNULL以外の値を指定してDBMS_SQL.PARSEプロシージャを起動
apply_crossedition_triggerパラメータに対して唯一有効なNULL以外の値は、forward crosseditionトリガーの非修飾名です。DBMS_SQL.PARSEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

forward crosseditionトリガーが別のコンパイル・ユニットに含まれるサブプログラムを起動する場合、このトリガーがapply_crossedition_triggerパラメータにNULL以外の値が指定されたDBMS_SQL.PARSEプロシージャにより起動された場合のみ、このサブプログラムのSQLがforward crosseditionトリガーSQLになります。

forward crosseditionトリガーSQLは、次の条件をすべて満たすトリガーのみ起動できます。

- forward crosseditionトリガーである。

- 現行エディションまたは現行エディションの子孫で作成された。

- 実行中のforward crosseditionトリガーに明示的に後続する。

reverse crosseditionトリガーSQL

reverse crosseditionトリガーSQLは、reverse crosseditionトリガー本体から直接実行されるSQLです。reverse croseditionトリガーのローカル・サブプログラムが起動された場合のみ、このカテゴリには、起動されたサブプログラムのSQLが含まれます。

reverse crosseditionトリガーSQLは、次の条件をすべて満たすトリガーのみ起動できます。

- reverse crosseditionトリガーである。

- 現行エディションまたは現行エディションの先祖で作成された。

- 実行中のreverse crosseditionトリガーよりも前に明示的に実行される。

アプリケーションSQL

アプリケーションSQLは、crosseditionトリガーSQLを除くすべてのSQLで、次のDML文が含まれます。

- DBMS_SQLパッケージを使用してコーディングされた動的SQL DML文(これらの文の詳細は『Oracle Database PL/SQL言語リファレンス』を参照)。

- Javaストアド・プロシージャおよび外部プロシージャによって実行されるDML文(これらのプロシージャがCALLトリガーで起動された場合も含む)

アプリケーションSQLは、次の規則に従って、noncrosseditionトリガーとcrosseditionトリガーの両方を起動します。

トリガーの種類

トリガーの起動条件

noncrossedition

トリガーが現行エディションで表示可能かつ有効である。

forward crossedition

トリガーが現行エディションの子孫で作成された。

reverse crossedition

トリガーが現行エディションまたは現行エディションの祖先で作成された。

起動順序

特定のDML文に対応してトリガーを起動するためのトリガーの条件は次のとおりです。

- トリガーの種類が適切である(「起動できるトリガーの種類」参照)

- 選択の条件を満たしている(たとえば、DML文の種類やWHEN句)

- 有効化されている

これらの条件を満たすトリガーの場合、起動順序は次により決定されます。

- FOLLOWS句およびPRECEDES句

- トリガーの種類とエディション

参照:
トリガーの起動順序に関する概要は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

FOLLOWS句およびPRECEDES句

トリガーAとBが同じタイミング・ポイントで起動されるとき、次のいずれかに該当するとAはBよりも先に起動します。

- Aが明示的にBに先行する場合。

- Bが明示的にAに続く場合。

この規則は次のような条件とは無関係です。

- トリガーが有効か無効か。

- UPDATE OF句に指定された列が変更されるかどうか。

- WHEN句が満たされるかどうか。

- 2つのトリガーが同じ種類のDML文(INSERT、UPDATEまたはDELETE)に関連付けられているかどうか。

- トリガーのタイミング・ポイントが重なっているかどうか。

明示的な先行または後続の関係がないトリガーの起動順序は予測できません。

トリガーの種類とエディション

トリガーを起動するDML文に関連付けられた各タイミング・ポイントでは、条件に合うトリガーが次の順序で起動されます。1から3ではFOLLOWSの関係が適用され、4と5ではPRECEDESの関係が適用されます。

1. 非crosseditionトリガー

2. 現行エディションで作成されたforward crosseditionトリガー

3. 現行エディションの子孫で作成されたforward crosseditionトリガー(子孫の作成順(子、孫、その子など))

4. 現行エディションで作成されたreverse crosseditionトリガー

5. 現行エディションの祖先で作成されたreverse crosseditionトリガー(祖先の作成と逆順(親、その親、さらにその親など))

crosseditionトリガーの実行

crosseditionトリガーは、自らが作成されたエディションを使用して実行します。crosseditionトリガーがコールするすべてのコード(パッケージ参照、PL/SQLサブプログラム・コールおよびSQL文を含む)も、crosseditionトリガーが作成されたエディションで実行します。

PL/SQLパッケージが複数のエディションで実パッケージである場合、単一セッション内であっても、パッケージの変数やその他の状態は各エディションのみで公開されます。各crosseditionトリガーおよびそれらのトリガーがコールするコードは、crosseditionトリガーが作成されたエディションを使用して実行するため、同一セッションがパッケージの複数のバージョンを同じ名前でインスタンス化することがあります。

crosseditionトリガーの作成

crosseditionトリガーを作成するには、エディションが有効化されたユーザーである必要があります(ユーザーに対してエディションを有効にする方法の詳細は「ユーザーに対するエディションの有効化」を参照)。

次の規則に注意しながらSQL文CREATE TRIGGERを使用して、crosseditionトリガーを作成します。

- crosseditionトリガーは、ビューではなく表に定義する必要があります。

- crosseditionトリガーはDMLトリガー(単純トリガーまたは複合トリガー)であることが必要です。
crosseditionトリガー本体のDML文は、静的SQL文(『Oracle Database PL/SQL言語リファレンス』を参照)、またはネイティブ動的SQL文(『Oracle Database PL/SQL言語リファレンス』を参照)のどちらかです。

- crosseditionトリガーは、REVERSEを指定しないかぎりforwardになります。(FORWARDの指定はオプションです。)

- FOLLOWS句を使用できるのは、forward crosseditionトリガーまたは非crosseditionトリガーを作成する場合のみです。(FOLLOWS句は、作成中のトリガーが、指定したトリガーの起動後に起動することを指定します。)

- PRECEDES句を使用できるのは、reverse crosseditionトリガーを作成する場合のみです。(PRECEDES句は、作成中のトリガーが、指定したトリガーの起動前に起動することを指定します。)

- FOLLOWS句またはPRECEDES句に指定するトリガーは存在している必要がありますが、有効になっていなくても、正常にコンパイルされていなくてもかまいません。

- 非crosseditionトリガーと同じく、crosseditionトリガーは、DISABLEを指定しないかぎり作成された時点で有効になっています。(ENABLEの指定はオプションです。)

ヒント:
crosseditionトリガーは無効な状態で作成して、正常にコンパイルされたことを確認した後で有効にします。有効な状態で作成してからコンパイルが失敗すると、既存のアプリケーションのユーザーの操作が影響を受けます。

- crosseditionトリガー本体の操作は多重呼出し不変(操作を複数回実行するのは冗長であり、結果は変わらない)である必要があります。

参照:
crosseditionトリガーを作成するCREATE TRIGGER文の使用方法の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

forward crosseditionトリガー本体のコーディング

forward crosseditionトリガーの本体の操作は、予測が不可能であるため、多重呼出し不変である必要があります。

- 古い行に対して本体が最初に実行されるコンテキスト。
可能性は次のとおりです。

- 祖先エディションのユーザーが、トリガー(予期せぬ変更)を起動するDML文を実行するとき

- 定義をトリガーする変換を適用するとき
変換の適用に関する詳細は、「アップグレード前の表現をアップグレード後の表現に変換」を参照してください。

- 本体が古い行それぞれについて何回実行されるか。

内容は次のとおりです。

- データ変換における衝突の処理

- 他の表への変更の処理

データ変換における衝突の処理

forward crosseditionトリガーが(表の新しい列ではなく)新しい表を移入する場合、その本体は必ずデータ変換の衝突に対応します。

たとえば、新しい表のある列にUNIQUE制約が含まれるとします。予期せぬ変更によりforward crosseditionトリガーが起動され、これにより新しい表に1行挿入されます。その後、別の予期せぬ変更により、forward crosseditionトリガーが起動されるか、またはユーザーがトリガーにより定義された変換を適用します。このトリガーは新しい表への行の挿入を試行しますが、これはUNIQUE制約に違反しています。

衝突処理方法がトリガーの実行理由に応じて変わる場合、その理由はファンクションAPPLYING_CROSSEDITION_TRIGGERにより判断できます。このファンクションがトリガーの本体から直接呼び出されたときに、予期せぬ変更によりトリガーが実行されていた場合はBOOLEAN値のTRUEが返されます。また、変換が適用されたためにトリガーが実行されていた場合はFALSEが返されます。(APPLYING_CROSSEDITION_TRIGGERは、パッケージDBMS_STANDARDで定義されています。これにはパラメータはありません。)これにはパラメータはありません。)

衝突を無視し、既存の行と衝突しない行を挿入するには、INSERT文にIGNORE_ROW_ON_DUPKEY_INDEXヒントを入れます。

このような衝突を無視したくはないが、これらに対応するために、衝突がどこで発生しているかを知る必要があるという場合は、INSERTまたはUPDATE文にCHANGE_DUPKEY_ERROR_INDEXヒントを入れ、索引または列のセットを指定します。その後、索引、または列のセットに一意キーの違反が発生した場合、ORA-00001のかわりにORA-38911が報告されます。ORA-38911に対する例外ハンドラを書くことができます。

注意:
ヒントの構文もありますが、IGNORE_ROW_ON_DUPKEY_INDEXおよびCHANGE_DUPKEY_ERROR_INDEXは必須です。これらはオプティマイザにより必ず使用されます。

例19-5はAPPLYING_CROSSEDITION_TRIGGERファンクション、およびIGNORE_ROW_ON_DUPKEY_INDEXヒントとCHANGE_DUPKEY_ERROR_INDEXヒントを使用して、データ変換の衝突に対応するcrosseditionトリガーを作成します。このトリガーはtable1の古い行をtable2の新しい行に変換します。この表を次のように作成されます。

CREATE TABLE table1 (key NUMBER, value VARCHAR2(20));

CREATE TABLE table2 (key NUMBER, value VARCHAR2(20), last_updated TIMESTAMP);
CREATE UNIQUE INDEX i2 on table2(key);

例19-5 データ変換の衝突に対応するcrosseditionトリガー

CREATE OR REPLACE TRIGGER trigger1
BEFORE INSERT OR UPDATE ON table1
FOR EACH ROW
CROSSEDITION
DECLARE
row_already_present  EXCEPTION;
PRAGMA EXCEPTION_INIT(row_already_present, -38911);
BEGIN
IF APPLYING_CROSSEDITION_TRIGGER THEN
/* Trigger is running because of serendipitous change.
Insert new row into table2 unless it is already there. */
INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(table2(key)) */
INTO table2
VALUES(:new.key, :new.value, to_date('1900-01-01', 'YYYY-MM-DD'));
ELSE
/* Trigger is running because you are applying transform.
If tranform has not yet inserted new row in table2, insert new row;
otherwise, update new row. */
BEGIN
INSERT /*+ CHANGE_DUPKEY_ERROR_INDEX(table2(key)) */
INTO table2
VALUES(:new.key, :new.value, SYSTIMESTAMP);
EXCEPTION WHEN row_already_present THEN
UPDATE table2
SET value = :new.value, last_updated = SYSTIMESTAMP
WHERE key = :new.key;
END;
END IF;
END;
/

参照:

- IGNORE_ROW_ON_DUPKEY_INDEXの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- CHANGE_DUPKEY_ERROR_INDEXの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

- ヒントの概要は、『Oracle Database SQL言語リファレンス』を参照してください。

他の表への変更の処理

トリガーが定義された表以外の表を変更する明示的なSQL文がforward croseditionトリガーの本体に含まれ、それらの表の行にトリガーが定義された表の行との1対1の対応がない場合、次の状況を正しく処理するためのロック・メカニズムを本体コードに実装する必要があります。

- 祖先エディションの複数のユーザーが、トリガーの定義されている表に対するDML文を同時に発行する状況。

- 祖先エディションのユーザーのうち、少なくとも1人が、トリガーの定義されている表に対するDML文を発行する状況。

アップグレード前の表現をアップグレード後の表現に変換

アップグレードしているアプリケーションを構成するデータベース・オブジェクトを(新しいエディションで)再定義した後、アプリケーション・データを(古いエディションで)アップグレード前の表現から(新しいエディションで)アップグレード後の表現に変換する必要があります。この変換の規則はトランスフォームと呼ばれ、これらはforward crosseditionトリガーにより定義されます。(forward crosseditionトリガーについては、「forward crosseditionトリガー」を参照してください。)

古い行の一部は、予期せぬ変更、つまり、forward crosseditionトリガーが起動したアップグレード前のアプリケーションのユーザーが行った変更により、新しい行にトランスフォームされている可能性があります。しかし、予期せぬ変更によりトランスフォームされなかった行はすべてアップグレード前の表現のままです。古い行がすべて新しい行に確実にトランスフォームされるようにするには、アプリケーション・データに格納されている表で定義したトランスフォームを適用する必要があります。

トランスフォームを適用する方法には次の2通りがあります。

- トランスフォームを定義しているトリガーを、表のすべての行に対して一度に1行ずつ起動します。

- トリガーを起動するかわりに、トリガーで行われる内容をより速く処理するSQL文を実行し、そのトリガーに続くトリガーがあれば起動します。
表全体を置換した場合、または新しい表を作成した場合は2番目の方法をお薦めします。

トランスフォームを適用する方法がどちらであっても、DBMS_SQL.PARSEプロシージャ、またはDBMS_PARALLEL_EXECUTEパッケージのサブプログラムを起動します。大量のデータがある場合は2番目の方法をお薦めします。このサブプログラムを使用すると、大容量の表のデータを並列で増分的に更新することができます。これは次の2つの手順で行われます。

1. 表の行をグループ化して小さなチャンクに分けます。

2. 必要なUPDATE文を並列でチャンクに適用し、1チャンクの処理が終了するたびにコミットします。

この利点は次のとおりです。

- 表全体のロックではなく、相対的に短い時間で一度に1セットの行のみをロックする。

- 操作全体が完了する前に問題が発生してもそれまでに処理した内容が失われない。

DBMS_SQL.PARSEプロシージャとDBMS_PARALLEL_EXECUTEサブプログラムの両方で、apply_crossedition_trigger、fire_apply_triggerおよびsql_stmtの実際のパラメータ値は次に示すように同じです。

- apply_crossedition_triggerには、適用されるトランスフォームを定義するforward crosseditionトリガーの名前を指定します。

- 表のすべての行に対して一度に1行ずつトリガーを起動するには、次のようにします。

- fire_apply_triggerの値にTRUEを指定します。

- sql_stmtには、起動するforward crosseditionトリガーの選択以外に重要な影響を及ぼさないSQL文を指定します。たとえば、一部の列を各行の既存の値に設定するUPDATE文を指定します。

- トリガーで行われる内容を処理するSQL文を実行し、そのトリガーに続くトリガーがあれば起動します。

- fire_apply_triggerの値にFALSEを指定します。

- sql_stmtには、forward crosseditionトリガーの処理内容をより速く行うSQL文を指定します。たとえば、1つ以上のPL/SQLサブプログラムをコールするPL/SQL無名ブロックを指定します。

参照:

- DBMS_SQL.PARSEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

- DBMS_PARALLEL_EXECUTEパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

更新内容の消失の防止

トランスフォームの適用中に更新内容が消失するのを防ぐには、次の手順を使用します。

1. crosseditionトリガーを有効化します。

2. 影響を受ける表への保留中の変更がコミットまたはロールバックされるまで待機します。
プロシージャDBMS_UTILITY.WAIT_ON_PENDING_DMLを使用します。このプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

3. トランスフォームを適用します。

注意:
このシナリオでは、forward crosseditionトリガーが変更するのはそれが定義された表のみですが、リスクを説明するには十分です。crosseditionトリガーがまだ有効になっていないときに、セッション1がUPDATE文を表に対して発行し、次にセッション2がcrosseditionトリガーを有効にし、すぐにトランスフォームを適用するとします。
セッション1とセッション2の両方が同じ行(行n)を変更しようとすると競合状態が発生する可能性があります。どちらのセッションが先に行nに到達するかは運次第です。最初に到達したセッションがその変更をコミットしてロックを解放するまで、2番目に行nに到達したセッションは待機する必要があるとしても、両方の更新は成功します。

問題は、セッション2が競合に勝った場合に起こります。そのSQL文はトリガーが有効になった後にコンパイルされたため、その文を実装するプログラムはトリガー・アクションも実装します。そのため、目的のアップグレード後の列の値は列nに設定されます。ここでセッション1が行nに到達しました。このSQL文はトリガーが有効になる前にコンパイルされたため、この文を実装するプログラムはトリガー・アクションを実装しません。そのため、セッション2がアップグレード後の列に設定した値は変更されず、セッション1が行nを更新する前のソース列の値を反映します。つまり、セッション1の更新の目的の副作用が消失します。

crosseditionトリガーの削除

crosseditionトリガーを削除するには、DROP TRIGGER文を使用します。詳細は『Oracle Database PL/SQL言語リファレンス』を参照してください。また、DROP EDITION文でCASCADE句を使用して、これらが実であるエディションを削除することにより、crosseditionトリガーを削除できます。エディションの削除の詳細は、「エディションの削除」を参照してください。

crosseditionトリガーは次の場合に削除します。

- アプリケーション・アップグレードをロールバックしている(アップグレード後のエディションを削除している)場合。
アップグレード後のエディションを削除する前に、新しい列の制約をすべて無効化、または削除する必要があります。

- アプリケーションのアップグレードが完了し、すべてのユーザーがアップグレード後のエディションを使用できるようにしている場合。
すべてのセッションでアップグレード後のエディションが使用されている場合は、forward crosseditionトリガーを削除できます。ただし、reverse crosseditionトリガーを削除する前に、古い列の制約をすべて無効化、または削除する必要があります。

制約を無効化または削除するには、ALTER TABLE文にDISABLE CONSTRAINTまたはDROP CONSTRAINT句を付けて使用します。ALTER TABLE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディション、エディショニング・ビュー、crosseditionトリガーの情報の表示

表19-1および表19-2に、静的データ・ディクショナリ・ビューを示します。各ビューには、それぞれエディションとエディショニング・ビューの情報が表示されます。各表のビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

トリガーの情報を表示する静的データ・ディクショナリ・ビューは、『Oracle Databaseリファレンス』を参照してください。静的データ・ディクショナリ・ビューに示されるcrosseditionトリガーは、セッション・エディションの実オブジェクトです。

実行される一連のcrosseditionトリガーが異なる場合、子カーソルを共有することはできません。動的パフォーマンス・ビューV$SQL_SHARED_CURSORおよびGV$SQL_SHARED_CURSORには、これに該当するかどうかを示すCROSSEDITION_TRIGGER_MISMATCH列があります。V$SQL_SHARED_CURSORの詳細は、『Oracle Databaseリファレンス』を参照してください。

表19-1 エディション情報を含む*_ディクショナリ・ビュー

ビュー

説明

*_EDITIONS

データベースのすべてのエディションを示します。

*_EDITION_COMMENTS

データベースのすべてのエディションに関連付けられたコメントを示します。

*_OBJECTS

セッション・エディションで表示可能なデータベースのすべてのオブジェクト(実オブジェクトまたは継承オブジェクト)を示します。

*_OBJECTS_AE

すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。

*_ERRORS

セッション・エディションのデータベース内のすべてのエラーを示します。

*_ERRORS_AE

すべてのエディションのデータベース内のすべてのエラーを示します。

*_USERS

データベースのすべてのユーザーを示します。エディションが有効になっているユーザーを表示するときに役立ちます。

*_SERVICES

データベースのすべてのサービスを示します。

Oracle Database 11gリリース2 (11.2.0.2)では、EDITIONS列にデフォルトの最初のセッション・エディションが表示されます。

注意:
*_OBJECTSおよび*_OBJECTS_AEに含まれる依存オブジェクトが、表18-2の操作によって無効化されるのは、次のいずれかの後のみです。

- オブジェクトの参照(コンパイル中または実行中)

- DBMS_UTILITY.COMPILE_SCHEMAの起動(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)

- 任意のUTL_RECOMPサブプログラムの起動(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)

表19-2 エディショニング・ビュー情報を含む*_ディクショナリ・ビュー

ビュー

説明

*_VIEWS

エディショニング・ビューを含む、セッション・エディションで表示可能なデータベースのすべてのビュー(実ビューまたは継承ビュー)を示します。

*_EDITIONING_VIEWS

セッション・エディションで表示可能なデータベースのすべてのエディショニング・ビュー(実エディショニング・ビューまたは継承エディショニング・ビュー)を示します。エディショニング・ビューと実表の関係を表示するときに役立ちます。*_OBJECTS_AEと結合すると、さらに情報を得ることができます。

*_EDITIONING_VIEWS_AE

すべてのエディションにおけるデータベース内のすべてのエディショニング・ビューのすべての実オブジェクトを示します。

*_EDITIONING_VIEW_COLS

セッション・エディションで表示可能なデータベースのすべてのエディショニング・ビュー(実エディショニング・ビューまたは継承エディショニング・ビュー)の列を示します。エディショニング・ビューの列とマッピング先の表の列との関係を表示するときに役立ちます。*_OBJECTS_AEまたは*_TAB_COL(あるいは両方)と結合すると、さらに情報を得ることができます。

*_EDITIONING_VIEW_COLS_AE

すべてのエディションのデータベースにあるすべてのエディショニング・ビューの列を示します。

*_EDITIONING_VIEWSの各行は、*_VIEWSの1つの行と厳密に一致します。EDITIONING_VIEW = 'Y'の*_VIEWSの各行は、*_EDITIONING_VIEWSの1つの行と厳密に一致します。したがって、次の例のWHERE句は冗長です。

SELECT ...
FROM DBA_EDITIONING_VIEWS INNER JOIN DBA_VIEWS
USING (OWNER, VIEW_NAME)
WHERE EDITIONING_VIEW = 'Y'
AND ...

*_EDITIONING_VIEWSの行と一致する*_VIEWSの行は、定義によりEDITIONING_VIEW = 'Y'を満たします。反対に、EDITIONING_VIEW = 'N'の*_VIEWSの行に対応する行は*_ EDITIONING_VIEWSにはありません。

アプリケーションをアップグレードするためのエディションベースの再定義の使用

エディションベースの再定義を使用して、アプリケーションをオンラインでアップグレードするには、まず、アプリケーションを準備する必要があります。

1. 該当するユーザーに対してエディションを有効化します。
手順は、「ユーザーに対するエディションの有効化」を参照してください。

この手順を行う理由は、この次の手順で作成するエディショニング・ビューを所有できるのは、エディションが有効化されているユーザーのみであるためです。

2. エディショニング・ビューを使用するようにアプリケーションを準備します。
手順については、「アプリケーションでのエディショニング・ビューの使用準備」を参照してください。

エディショニング・ビューを表示し、エディションベースの再定義を使用して、アプリケーションをオンラインで必要な回数、アップグレードすることができます。アップグレードのたびに、次のようにしてください。

- 再定義するオブジェクトのタイプがすべてエディション対応である場合(表はエディション対応ではありません)は、「エディションのみを使用するエディションベースの再定義の手順」を使用します。

- 1つ以上の表の構造を変更するとき、その間に他のユーザーがそれらの表のデータを変更できなくてもよい場合は、「エディショニング・ビューを使用するエディションベースの再定義の手順」を使用します。

- 1つ以上の表の構造を変更するとき、その間に他のユーザーがそれらの表のデータを変更できるようにする必要がある場合は、「crosseditionトリガーを使用するエディションベースの再定義の手順」を使用します。

内容は次のとおりです。

- アプリケーションでのエディショニング・ビューの使用準備

- エディションのみを使用するエディションベースの再定義の手順

- エディショニング・ビューを使用するエディションベースの再定義の手順

- crosseditionトリガーを使用するエディションベースの再定義の手順

- アプリケーション・アップグレードのロールバック

- 使用されていない表の列が占める領域の再利用

- 例: アプリケーションをアップグレードするためのエディションベースの再定義の使用

アプリケーションでのエディショニング・ビューの使用準備

1つ以上の表を使用するアプリケーションでは、エディショニング・ビューで各表がカバーされる必要があります。エディショニング・ビューは、次のすべての記述が正しい場合にのみ、表をカバーします。

- アプリケーション内の通常オブジェクトはすべて、エディショニング・ビューを通じてのみ、表を参照できます。(通常オブジェクトは、エディショニング・ビューまたはcrosseditionトリガー以外のすべてのオブジェクトです。エディショニング・ビューとcrosseditionトリガーは表を参照する必要があります。)

- アプリケーション・ユーザーは、表ではなく、エディショニング・ビューに対してのみオブジェクト権限を付与されます。

- 仮想プライベート・データベース(VPD)ポリシーは、表ではなく、エディショニング・ビューにのみアタッチされます。(日常的な監査、およびファイングレイン監査(FGA)ポリシーは、表にのみアタッチされます。)

エディショニング・ビューが実オブジェクト化された場合、VPDポリシーのコピーは実オブジェクト化されたエディショニング・ビューにアタッチされます。(ポリシーは名前と、アタッチ先オブジェクトにより一意に識別されます。)ポリシー・ファンクションも実オブジェクト化されている場合、このポリシーのコピーは実オブジェクト化されたポリシー・ファンクションを使用します。それ以外の場合は元のポリシー・ファンクションを使用します。

VPDポリシーを示す静的なデータ・ディクショナリ・ビュー*_POLICIESは、エディションに応じて、異なる結果を表示することができます。

参照:

- VPDポリシーに関する情報を示す静的データ・ディクショナリ・ビューを含め、VPDに関する詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

- *_POLICIESの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

既存のアプリケーションがエディショニング・ビューを使用していない場合は、使用する各表に対して次の手順を実行して、エディショニング・ビューを使用できるようにアプリケーションを準備します。

1. 表に新しい名前を付けます(現在の表名をエディショニング・ビューに付けるためです)。
新しい名前は、元の名前に関連したものとし、変更履歴を示すようにしてください。たとえば、元の表名がDataの場合、新しい表名をData_1とすることができます。

2. (オプション)表の各列に新しい名前を付けます。

このときも、新しい名前は、元の名前に関連したものとし、変更履歴を示すようにしてください。たとえば、NameおよびNumberをName_1およびNumber_1のように変更できます。

名前を変更した列に依存するトリガーはここで無効になります。詳細は、表18-2でALTER TABLE table RENAME columnの項目を参照してください。

3. エディショニング・ビューを作成し、表の元の名前を付けます。
手順は、「エディショニング・ビューの作成」を参照してください。

エディショニング・ビューには表の元の名前が付けられるため、その表名を参照しているオブジェクトがエディショニング・ビューを参照するようになります。

4. トリガーが表に定義されている場合は、トリガーを削除してから、作成時に使用したコードを再実行します。
こうすることで、表に定義されていたトリガーが、エディショニング・ビューに対して定義されます。

5. VPDポリシーが表にアタッチされている場合は、このポリシーとポリシー・ファンクションを削除してから、作成時に使用したコードを再実行します。
これにより、表にアタッチされていたVPDポリシーが、エディショニング・ビューにアタッチされます。

6. すべてのアプリケーション・ユーザーから、表に対するすべてのオブジェクト権限を取り消します。

表に対し、どのアプリケーション・ユーザーがどのオブジェクト権限を持っているかを確認するには、次の問合せを使用します。

SELECT GRANTEE, PRIVILEGE
FROM DBA_TAB_PRIVS
WHERE TABLE_NAME='table_name';

7. 手順6で取り消された権限すべてについて、エディショニング・ビューで同じ権限を付与します。

8. 表を参照するプライベート・シノニムを所有するユーザーに対してエディションを有効化し(手順については、「ユーザーに対するエディションの有効化」を参照)、これらのユーザーに、シノニムを再作成する必要があることを通知します。

注意:
この結果、表を参照するパブリック・シノニムはORA-00980で失敗するようになります。エディショニング・ビューでこれらを再作成することはできません(理由については、「参照されているオブジェクトの実オブジェクト化」を参照)。

エディションのみを使用するエディションベースの再定義の手順

次の手順は、再定義するすべてのオブジェクトのオブジェクト・タイプがエディション対応(定義は「エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ」を参照)である場合のみ使用します。表はエディション対応タイプではありません。

1. 新しいエディションを作成します。

手順は、「エディションの作成」を参照してください。

2. 新しいエディションをセッション・エディションにします。
手順は、「セッション・エディションの変更」を参照してください。

3. アプリケーションのエディション・オブジェクトに必要な変更を行います。

4. すべてのオブジェクトが有効であることを確認します。
静的データ・ディクショナリ*_OBJECTS_AEを問い合せます。これは、すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。無効オブジェクトが残っている場合は、任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を使用して再コンパイルします。

5. 変更内容が意図したように機能していることを確認します。
機能している場合は、手順6に進みます。

そうでない場合は、さらに変更を続ける(手順3に戻る)か、またはアプリケーション・アップグレードをロールバックします(手順については、「アプリケーション・アップグレードのロールバック」を参照)。

6. 新しいエディション(アップグレードされたアプリケーション)をすべてのユーザーに対して使用可能にします。

手順は、「すべてのユーザーに対してエディションを使用可能にする」を参照してください。

7. 古いエディション(元のアプリケーション)をリタイアさせ、SYS以外のすべてのユーザーがアップグレードされたアプリケーションのみを使用するようにします。

手順は、「エディションのリタイア」を参照してください。

例19-6は、ここで説明した手順を使用して、非常に単純なPL/SQLプロシージャを変更する方法を示します。

例19-6 非常に単純なプロシージャのエディションベースの再定義

1. この例で使用するPL/SQLプロシージャを作成します。

CREATE OR REPLACE PROCEDURE hello IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello, edition 1.');
END hello;
/

2. PL/SQLプロシージャを起動します。

BEGIN hello(); END;
/

結果:

Hello, edition 1.

PL/SQL procedure successfully completed.

3. プロシージャをエディションベースで再定義します。

1. 新しいエディションを作成します。

CREATE EDITION e2 AS CHILD OF ora$base;

結果:

Edition created.

2. 新しいエディションをセッション・エディションにします。

ALTER SESSION SET EDITION = e2;

結果:

Session altered.

3. プロシージャを変更します。

CREATE OR REPLACE PROCEDURE hello IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello, edition 2.');
END hello;
/

結果:

Procedure created.

4. 変更内容が意図したように機能していることを確認します。

BEGIN hello(); END;
/

結果:

Hello, edition 2.
PL/SQL procedure successfully completed.

5. すべてのユーザーが新しいエディションを使用できるようにします(システム権限が必要です)。

ALTER DATABASE DEFAULT EDITION = e2;

6. 古いエディションをリタイアさせます(システム権限が必要です)。
権限受領者のリストを表示します。

SELECT GRANTEE, PRIVILEGE
FROM DBA_TAB_PRIVS
WHERE TABLE_NAME = UPPER('ora$base')
/

結果:

GRANTEE                        PRIVILEGE
------------------------------ ---------
PUBLIC                         USE

1 row selected.

すべての権限受領者について、古いエディションの使用を取り消します。

REVOKE USE ON EDITION ora$base FROM PUBLIC;

エディショニング・ビューを使用するエディションベースの再定義の手順

1つ以上の表の構造を変更するとき、その間に他のユーザーがそれらの表のデータを変更できなくてもよい場合のみ、次の手順を使用します。

1. 新しいエディションを作成します。

手順は、「エディションの作成」を参照してください。

2. 新しいエディションをセッション・エディションにします。
手順は、「セッション・エディションの変更」を参照してください。

3. 新しいエディションで、エディショニング・ビューが読取り専用の場合は、読取り/書込みに変更します。
手順は、「エディショニング・ビューの書込み可能性の変更」を参照してください。

4. 新しいエディションを除くすべてのエディションで、エディショニング・ビューを読取り専用にします。

5. アプリケーションのオブジェクトに必要な変更を行います。

6. すべてのオブジェクトが有効であることを確認します。
静的データ・ディクショナリ*_OBJECTS_AEを問い合せます。これは、すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。無効オブジェクトが残っている場合は、任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を使用して再コンパイルします。

7. 変更内容が意図したように機能していることを確認します。
機能している場合は、手順8に進みます。

そうでない場合は、さらに変更を続ける(手順5に戻る)か、またはアプリケーション・アップグレードをロールバックします(手順については、「アプリケーション・アップグレードのロールバック」を参照)。

8. アップグレードされたアプリケーションをすべてのユーザーに対して使用可能にします。

手順は、「すべてのユーザーに対してエディションを使用可能にする」を参照してください。

9. 古いエディション(元のアプリケーション)をリタイアさせ、SYS以外のすべてのユーザーがアップグレードされたアプリケーションのみを使用するようにします。

手順は、「エディションのリタイア」を参照してください。

crosseditionトリガーを使用するエディションベースの再定義の手順

1つ以上の表の構造を変更するとき、その間に他のユーザーがそれらの表のデータを変更する必要がある場合のみ、次の手順を使用します。

1. 新しいエディションを作成します。

手順は、「エディションの作成」を参照してください。

2. 新しいエディションをセッション・エディションにします。

手順は、「セッション・エディションの変更」を参照してください。

3. アプリケーションのオブジェクトに永続的な変更を行います。

たとえば、表に新しい列を追加し、新しい永続サブプログラムを作成します。

ここで、変更したオブジェクトに依存するオブジェクトが無効になることがあります。詳細は、表18-2を参照してください。

4. すべてのオブジェクトが有効であることを確認します。
静的データ・ディクショナリ*_OBJECTS_AEを問い合せます。これは、すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。無効オブジェクトが残っている場合は、任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を使用して再コンパイルします。

5. 一時オブジェクト、すなわちcrosseditionトリガー(無効状態)とトリガーで必要なサブプログラムを作成します。

手順は、「crosseditionトリガーの作成」を参照してください。

reverse crosseditionトリガーが必要になるのは、手順10(オプション)を実行する場合のみです。

6. crosseditionトリガーが正常にコンパイルされたら、crosseditionトリガーを有効にします。

ALTER TRIGGER文にENABLEオプションを付けて使用します。この文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

7. 保留中の変更がコミットまたはロールバックされるまで待機します。
プロシージャDBMS_UTILITY.WAIT_ON_PENDING_DMLを使用します。このプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

8. トランスフォームを適用します。

手順については、「アップグレード前の表現をアップグレード後の表現に変換」を参照してください。

注意:
この手順が既存の行を処理した後で、祖先エディションのユーザーが同じ行のデータを更新、挿入または削除するかどうかを予測することはできません。

9. 変更内容が意図したように機能していることを確認します。

機能している場合は、手順10に進みます。

そうでない場合は、さらに変更を続ける(手順3に戻る)か、またはアプリケーション・アップグレードをロールバックします(手順については、「アプリケーション・アップグレードのロールバック」を参照)。

10. (オプション)セッション・エディションのUSE権限を、アップグレードしたアプリケーションの初期のユーザーに付与します。

手順は、「一部のユーザーに対してエディションを使用可能にする」を参照してください。

11. アップグレードされたアプリケーションをすべてのユーザーに対して使用可能にします。

手順は、「すべてのユーザーに対してエディションを使用可能にする」を参照してください。

12. 制約を無効化、または削除してから、croseditionトリガーを削除します。

手順は、「crosseditionトリガーの削除」を参照してください。

13. 古いエディション(元のアプリケーション)をリタイアさせ、SYS以外のすべてのユーザーがアップグレードされたアプリケーションのみを使用するようにします。

手順は、「エディションのリタイア」を参照してください。

アプリケーション・アップグレードのロールバック

アプリケーション・アップグレードをロールバックするには、次のようにします。

1. セッション・エディションを、アップグレード用に作成した新しいエディション以外のものに変更します。
手順は、「セッション・エディションの変更」を参照してください。

2. アップグレード用に作成した新しいエディションを削除します。
手順は、「エディションの削除」を参照してください。

3. アップグレード中に、新しい表の列を作成した場合、これらの列が占めていた領域を再利用します(手順については、「使用されていない表の列が占める領域の再利用」を参照)。

使用されていない表の列が占める領域の再利用

新しい表の列を作成したアップグレードをロールバックする場合

未使用の列が占めている領域を再利用するには、次のようにします。

1. 未使用の列の値をNULLに設定します。
この操作を行っている間に、他のユーザーをロックアウトしてしまわないようにするには、DBMS_PARALLEL_EXECUTEプロシージャを使用します(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)。

2. 未使用の列をUNUSEDに設定します。
ALTER TABLE文(『Oracle Database SQL言語リファレンス』を参照)をSET UNUSED句(『Oracle Database SQL言語リファレンス』を参照)とともに使用します。

3. 表を縮小します。
ALTER TABLE文(『Oracle Database SQL言語リファレンス』を参照)をSHRINK SPACE句(『Oracle Database SQL言語リファレンス』を参照)とともに使用します。

例: アプリケーションをアップグレードするためのエディションベースの再定義の使用

この例は、エディション、エディショニング・ビュー、forward crosseditionトリガーおよびreverse crosseditionトリガーを使用します。

内容は次のとおりです。

- 既存のアプリケーション

- アプリケーションでのエディショニング・ビューの使用準備

- アプリケーションをアップグレードするためのエディションベースの再定義の使用

注意:
アプリケーションのアップグレードにエディションベースの再定義を使用する前に、このアプリケーションで使用されるスキーマすべてについてエディションを有効化する必要があります。手順は、「ユーザーに対するエディションの有効化」を参照してください。

既存のアプリケーション

既存のアプリケーション(アップグレード対象のアプリケーション)は、トリガーが定義された1つの表で構成されています。このアプリケーションは例19-7に従って作成されたものです。

例19-7 既存のアプリケーションの作成

1. 表を作成します。

CREATE TABLE Contacts(
ID            NUMBER(6,0) CONSTRAINT Contacts_PK PRIMARY KEY,
Name          VARCHAR2(47),
Phone_Number  VARCHAR2(20)
);

2. 表にデータを移入します(例は示されていません)。

3. 表にトリガーを作成する準備をします。

ALTER TABLE Contacts ENABLE VALIDATE CONSTRAINT Contacts_PK;

DECLARE Max_ID INTEGER;
BEGIN
SELECT MAX(ID) INTO Max_ID FROM Contacts;
EXECUTE IMMEDIATE '
CREATE SEQUENCE Contacts_Seq
START WITH '||To_Char(Max_ID + 1);
END;
/

4. トリガーを作成します。

CREATE TRIGGER Contacts_BI
BEFORE INSERT ON Contacts FOR EACH ROW
BEGIN
:NEW.ID := Contacts_Seq.NEXTVAL;
END;
/

例19-8は、データ移入後の表Contactsを示しています。

例19-8 既存の表のデータの表示

問合せ:

SELECT * FROM Contacts
ORDER BY Name;

結果:

ID NAME                                            PHONE_NUMBER
---------- ----------------------------------------------- --------------------
174 Abel, Ellen                                     011.44.1644.429267
166 Ande, Sundar                                    011.44.1346.629268
130 Atkinson, Mozhe                                 650.124.6234
105 Austin, David                                   590.423.4569
204 Baer, Hermann                                   515.123.8888
116 Baida, Shelli                                   515.127.4563
167 Banda, Amit                                     011.44.1346.729268
172 Bates, Elizabeth                                011.44.1343.529268
192 Bell, Sarah                                     650.501.1876
151 Bernstein, David                                011.44.1344.345268
129 Bissot, Laura                                   650.124.5234
169 Bloom, Harrison                                 011.44.1343.829268
185 Bull, Alexis                                    650.509.2876
187 Cabrio, Anthony                                 650.509.4876
148 Cambrault, Gerald                               011.44.1344.619268
154 Cambrault, Nanette                              011.44.1344.987668
110 Chen, John                                      515.124.4269
...
120 Weiss, Matthew                                  650.123.1234
200 Whalen, Jennifer                                515.123.4444
149 Zlotkey, Eleni                                  011.44.1344.429018

107 rows selected.

Contactsを再定義する必要があるとします。Name列をFirst_Name列とLast_Name列で置換し、Country_Code列を追加します。また、この構造変更を行う際に、他のユーザーがContactsのデータを変更できることが必要です。

エディションベースの再定義のすべての機能が必要になります。つまり、エディション(常に必要)、エディショニング・ビュー(表を再定義するため)、およびcrosseditionトリガー(表の再定義中に他のユーザーが表のデータを変更する必要があるため)です。

アプリケーションでのエディショニング・ビューの使用準備

例19-8は、新しいエディションでエディショニング・ビューを作成する方法を示します。Contacts表を再定義している間、エディショニング・ビューを使用して他のユーザーがその表にアクセスします。

例19-9 既存の表のエディショニング・ビューの作成

1. 表に新しい名前を付けます(現在の表名をエディショニング・ビューに付けるためです)。

ALTER TABLE Contacts RENAME TO Contacts_Table;

2. (オプション)表の列に新しい名前を付けます。

ALTER TABLE Contacts_Table
RENAME COLUMN Name TO Name_1;

ALTER TABLE Contacts_Table
RENAME COLUMN Phone_Number TO Phone_Number_1;

3. エディショニング・ビューを作成します。

CREATE OR REPLACE EDITIONING VIEW Contacts AS
SELECT
ID                 ID,
Name_1             Name,
Phone_Number_1     Phone_Number
FROM Contacts_Table;

4. トリガーContacts_BIを表からエディショニング・ビューに移動します。

DROP TRIGGER Contacts_BI;

CREATE TRIGGER Contacts_BI
BEFORE INSERT ON Contacts FOR EACH ROW
BEGIN
:NEW.ID := Contacts_Seq.NEXTVAL;
END;
/

アプリケーションをアップグレードするためのエディションベースの再定義の使用

例19-10では、既存のアプリケーションをアップグレードするエディションを作成し、新しいエディションをセッション・エディションにして、新しいエディションが実際にセッション・エディションであることをチェックする方法を示します。

例19-10 アプリケーションをアップグレードするエディションの作成

1. 新しいエディションを作成します。

CREATE EDITION Post_Upgrade AS CHILD OF Ora$Base;

2. 新しいエディションをセッション・エディションにします。

ALTER SESSION SET EDITION = Post_Upgrade;

3. セッション・エディションをチェックします。

SELECT
SYS_CONTEXT('Userenv', 'Current_Edition_Name') "Current_Edition"
FROM DUAL;

結果:

Current_Edition
-----------------------------------------------------------------------------
POST_UPGRADE

1 row selected.

例19-11は、Post_Upgradeエディションで、物理表に新しい列を追加し、列の追加により無効化されたトリガーを再コンパイルする方法を示します。エディショニング・ビューContactsが表の列を適切な論理名で選択するように、このエディショニング・ビューを置換する方法を示します。

例19-11 表の変更とエディショニング・ビューの置換

1. 物理表に新しい列を追加します。

ALTER TABLE Contacts_Table ADD (
First_Name_2     varchar2(20),
Last_Name_2      varchar2(25),
Country_Code_2   varchar2(20),
Phone_Number_2   varchar2(20)
);

(これは非ブロック化DDLです。)

2. 無効化されたトリガーを再コンパイルします。

ALTER TRIGGER Contacts_BI COMPILE REUSE SETTINGS;

3. エディショニング・ビューを置換して、このエディショニング・ビューが置換列を適切な論理名で選択するようにします。

CREATE OR REPLACE EDITIONING VIEW Contacts AS
SELECT
ID                 ID,
First_Name_2       First_Name,
Last_Name_2        Last_Name,
Country_Code_2     Country_Code,
Phone_Number_2     Phone_Number
FROM Contacts_Table;

例19-12は、Post_Upgradeエディションで、forward crosseditionトリガーにより使用されるプロシージャを2つ作成し、無効な状態のforward crosseditionトリガーとreverse crosseditionトリガーの両方を作成してから、これらを有効化する方法を示します。

例19-12 crosseditionトリガーの作成と有効化

1. forward crosseditionトリガーにより使用される1つ目のプロシージャを作成します。

CREATE OR REPLACE PROCEDURE Set_First_And_Last_Name (
Name        IN  VARCHAR2,
First_Name  OUT VARCHAR2,
Last_Name   OUT VARCHAR2)
IS
Comma_Pos NUMBER := INSTR(Name, ',');
BEGIN
IF Comma_Pos IS NULL OR Comma_Pos < 2 THEN
RAISE Program_Error;
END IF;

Last_Name := SUBSTR(Name, 1, Comma_Pos-1);
Last_Name := RTRIM(Ltrim(Last_Name));

First_Name := SUBSTR(Name, Comma_Pos+1);
First_Name := RTRIM(LTRIM(First_Name));
END Set_First_And_Last_Name;
/

2. forward crosseditionトリガーにより使用される2つ目のプロシージャを作成します。

CREATE OR REPLACE PROCEDURE Set_Country_Code_And_Phone_No (
Phone_Number     IN  VARCHAR2,
Country_Code     OUT VARCHAR2,
Phone_Number_V2  OUT VARCHAR2)
IS
Char_To_Number_Error EXCEPTION;
PRAGMA EXCEPTION_INIT(Char_To_Number_Error, -06502);
Bad_Phone_Number EXCEPTION;
Nmbr VARCHAR2(30) := REPLACE(Phone_Number, '.', '-');

FUNCTION Is_US_Number(Nmbr IN VARCHAR2)
RETURN BOOLEAN
IS
Len NUMBER := LENGTH(Nmbr);
Dash_Pos NUMBER := INSTR(Nmbr, '-');
n PLS_INTEGER;
BEGIN
IF Len IS NULL OR Len <> 12 THEN
RETURN FALSE;
END IF;
IF Dash_Pos IS NULL OR Dash_Pos <> 4 THEN
RETURN FALSE;
END IF;
BEGIN
n := TO_NUMBER(SUBSTR(Nmbr, 1, 3));
EXCEPTION WHEN Char_To_Number_Error THEN
RETURN FALSE;
END;

Dash_Pos := INSTR(Nmbr, '-', 5);

IF Dash_Pos IS NULL OR Dash_Pos <> 8 THEN
RETURN FALSE;
END IF;

BEGIN
n := TO_NUMBER(SUBSTR(Nmbr, 5, 3));
EXCEPTION WHEN Char_To_Number_Error THEN
RETURN FALSE;
END;

BEGIN
n := TO_NUMBER(SUBSTR(Nmbr, 9));
EXCEPTION WHEN Char_To_Number_Error THEN
RETURN FALSE;
END;

RETURN TRUE;
END Is_US_Number;

BEGIN
IF Nmbr LIKE '011-%' THEN
DECLARE
Dash_Pos NUMBER := INSTR(Nmbr, '-', 5);
BEGIN
Country_Code := '+'|| TO_NUMBER(SUBSTR(Nmbr, 5, Dash_Pos-5));
Phone_Number_V2 := SUBSTR(Nmbr, Dash_Pos+1);
EXCEPTION WHEN Char_To_Number_Error THEN
raise Bad_Phone_Number;
END;
ELSIF Is_US_Number(Nmbr) THEN
Country_Code := '+1';
Phone_Number_V2 := Nmbr;
ELSE
RAISE Bad_Phone_Number;
END IF;
EXCEPTION WHEN Bad_Phone_Number THEN
Country_Code := '+0';
Phone_Number_V2 := '000-000-0000';
END Set_Country_Code_And_Phone_No;
/

3. 無効な状態のforward crosseditionトリガーを作成します。

CREATE OR REPLACE TRIGGER Contacts_Fwd_Xed
BEFORE INSERT OR UPDATE ON Contacts_Table
FOR EACH ROW
FORWARD CROSSEDITION
DISABLE
BEGIN
Set_First_And_Last_Name(
:NEW.Name_1,
:NEW.First_Name_2,
:NEW.Last_Name_2
);
Set_Country_Code_And_Phone_No(
:NEW.Phone_Number_1,
:NEW.Country_Code_2,
:NEW.Phone_Number_2
);
END Contacts_Fwd_Xed;
/

4. forward crosseditionトリガーを有効化します。

ALTER TRIGGER Contacts_Fwd_Xed ENABLE;

5. 無効な状態のreverse crosseditionトリガーを作成します。

CREATE OR REPLACE TRIGGER Contacts_Rvrs_Xed
BEFORE INSERT OR UPDATE ON Contacts_Table
FOR EACH ROW
REVERSE CROSSEDITION
DISABLE
BEGIN
:NEW.Name_1 := :NEW.Last_Name_2||', '||:NEW.First_Name_2;
:NEW.Phone_Number_1 :=
CASE :New.Country_Code_2
WHEN '+1' THEN
REPLACE(:NEW.Phone_Number_2, '-', '.')
ELSE
'011.'||LTRIM(:NEW.Country_Code_2, '+')||'.'||
REPLACE(:NEW.Phone_Number_2, '-', '.')
END;
END Contacts_Rvrs_Xed;
/

6. reverse crosseditionトリガーを有効化します。

ALTER TRIGGER Contacts_Rvrs_Xed ENABLE;

7. 保留中の変更がコミットまたはロールバックされるまで待機します。

DECLARE
scn              NUMBER  := NULL;
timeout CONSTANT INTEGER := NULL;
BEGIN
IF NOT DBMS_UTILITY.WAIT_ON_PENDING_DML(Tables  => 'Contacts_Table',
timeout => timeout,
scn     => scn)
THEN
RAISE_APPLICATION_ERROR(-20000,
'Wait_On_Pending_DML() timed out. CETs were enabled before SCN: '||SCN);
END IF;
END;
/

DBMS_UTILITY.WAIT_ON_PENDING_DMLプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例19-13は、Post_Upgradeエディションで、トランスフォームを適用する方法を示します。

例19-13 トランスフォームの適用

DECLARE
c NUMBER := DBMS_SQL.OPEN_CURSOR();
x NUMBER;
BEGIN
DBMS_SQL.PARSE(
c                          => c,
Language_Flag              => DBMS_SQL.NATIVE,
Statement                  => 'UPDATE Contacts_Table SET ID = ID',
Apply_Crossedition_Trigger => 'Contacts_Fwd_Xed'
);
x := DBMS_SQL.EXECUTE(c);
DBMS_SQL.CLOSE_CURSOR(c);
COMMIT;
END;
/

例19-14は、Post_Upgradeエディションで、変更が意図したとおりに機能しているかどうかをチェックする方法を示します。例19-14と例19-8を比較してください。

例19-14 変更された表のデータ表示

1. 列が読みやすくなるように書式設定します。

COLUMN ID FORMAT 999
COLUMN Last_Name FORMAT A15
COLUMN First_Name FORMAT A15
COLUMN Country_Code FORMAT A12
COLUMN Phone_Number FORMAT A12

2. 問合せ:

SELECT * FROM Contacts
ORDER BY Last_Name;

結果:

ID FIRST_NAME      LAST_NAME       COUNTRY_CODE PHONE_NUMBER
---- --------------- --------------- ------------ ------------
174 Ellen           Abel            +44          1644-429267
166 Sundar          Ande            +44          1346-629268
130 Mozhe           Atkinson        +1           650-124-6234
105 David           Austin          +1           590-423-4569
204 Hermann         Baer            +1           515-123-8888
116 Shelli          Baida           +1           515-127-4563
167 Amit            Banda           +44          1346-729268
172 Elizabeth       Bates           +44          1343-529268
192 Sarah           Bell            +1           650-501-1876
151 David           Bernstein       +44          1344-345268
129 Laura           Bissot          +1           650-124-5234
169 Harrison        Bloom           +44          1343-829268
185 Alexis          Bull            +1           650-509-2876
187 Anthony         Cabrio          +1           650-509-4876
154 Nanette         Cambrault       +44          1344-987668
148 Gerald          Cambrault       +44          1344-619268
110 John            Chen            +1           515-124-4269
...
120 Matthew         Weiss           +1           650-123-1234
200 Jennifer        Whalen          +1           515-123-4444
149 Eleni           Zlotkey         +44          1344-429018

107 rows selected.

変更が意図どおりに機能した場合は、「crosseditionトリガーを使用するエディションベースの再定義の手順」の手順10から13を実行することができます。

A マルチスレッドextprocエージェント

この付録では、マルチスレッドextprocエージェントの概要、分散データベース・システム全体の効率の向上に対する効果および管理方法について説明します。

内容は次のとおりです。

- マルチスレッドextprocエージェントを使用する理由

- マルチスレッドextprocエージェントのアーキテクチャ

- マルチスレッドextprocエージェントの管理

マルチスレッドextprocエージェントを使用する理由

この項では、マルチスレッドextprocエージェントが外部プロシージャの効率の向上にどのように役立つかについて説明します。

内容は次のとおりです。

- 専用エージェント・アーキテクチャの課題

- マルチスレッド化のメリット

専用エージェント・アーキテクチャの課題

デフォルトでは、extprocエージェントはユーザー・セッションごとに起動され、extprocエージェント・プロセスはユーザー・セッションの終了時にのみ終了します。

このアーキテクチャでは、過度にシステム・リソースが消費される場合があります。たとえば、数千のユーザー・セッションによってextprocエージェント・プロセスが同時に起動されるとします。extprocエージェント・プロセスは各セッションに対して起動されるので、数千のextprocエージェント・プロセスが同時に実行されます。extprocエージェント・プロセスは、各extprocエージェント・プロセスが特定の時点でアクティブであるかどうかにかかわらず、すべて実行されます。このため、extprocエージェント・プロセスとオープン接続により、過度にシステム・リソースが消費される場合があります。この問題は、セッションのOracle Databaseへの接続時に、サーバーを共有サーバー・モードで起動することで対処します。共有サーバー・モードでは、データベース接続を少ない数のサーバー・プロセスで共有できます。

マルチスレッド化のメリット

Oracle Database共有サーバー・アーキテクチャは、数千のユーザー・セッションがオープンしている場合でも、特定の時点でアクティブになる接続の割合が小さいことを前提にしています。共有サーバー・モードでは、共有サーバー・プロセスのプールが存在します。ユーザー・セッションは、リクエストされたタスクをキューに置くディスパッチャ・プロセスに接続します。このタスクは、使用可能な最初の共有サーバー・プロセスによって取得されます。共有サーバー・プロセスの数は、通常、ユーザー・セッションの数より少なくなります。

マルチスレッドextprocエージェントは、これに類似した機能を外部プロシージャへの接続に提供します。マルチスレッドextprocエージェントのアーキテクチャでは、共有エージェント・スレッドのプールを使用します。ユーザー・セッションによってリクエストされたタスクは、キューに置かれ、使用可能な最初のマルチスレッドextprocエージェント・スレッドによって取得されます。特定の時点でアクティブなユーザー接続の割合は小さいため、マルチスレッドextprocアーキテクチャでは、システム・リソースをより効率的に使用できます。

マルチスレッドextprocエージェントのアーキテクチャ

マルチスレッドextprocエージェントは、外部プロシージャへの接続を試行する前に、システム識別子(SID)ごとに起動する必要があります。この構成は、エージェント制御ユーティリティagtctlを使用して行います。このユーティリティは、エージェントの構成および停止にも使用されます。

システム上で実行されている各Oracle Netリスナーは、一連のSIDの着信接続リクエストをリスニングします。着信したOracle Net接続文字列内のSIDがリスナーのリスニング対象のSIDである場合は、そのリスナーが接続を処理します。さらに、マルチスレッドextprocエージェントがそのSIDに対して起動されている場合、リスナーはリクエストをそのextprocエージェントに渡します。

マルチスレッドextprocエージェントのアーキテクチャでは、着信した各接続リクエストは次の種類のスレッドにより処理されます。

- 単一の監視スレッド。監視スレッドは次の処理を行います。

- リスナーとの通信の管理

- プロセスの負荷の監視

- 必要に応じたスレッドの起動および停止

- 複数のディスパッチャ・スレッド。ディスパッチャ・スレッドは次の処理を行います。

- Oracle Databaseとの通信の処理

- タスク・スレッドへのタスク・リクエストの受渡し

- 複数のタスク・スレッド。タスク・スレッドは、Oracle Databaseプロセスからのリクエストを処理します。

図A-1に、マルチスレッドextprocエージェントのアーキテクチャを示します。ユーザー・セッション1および2から、いくつかのDLL内にあるファンクションへのコールアウトの要求が発行されます。これらの要求は、異機種間サービスを介してマルチスレッドのextprocエージェントに送られます。エージェントのディスパッチャ・スレッドがこれらの要求を処理し、タスク・スレッドに渡します。タスク・スレッドが実際に要求を処理し、DLLをそれぞれロードし、そこに含まれているファンクションをコールします。

- ユーザー・セッションからの要求はすべて、同じディスパッチャ・スレッドによって処理されます。たとえば、ユーザー・セッション1との通信はディスパッチャ1が処理し、ユーザー・セッション2との通信はディスパッチャ2が処理します。これは、セッションの存続期間を通じて同じです。

- 個々の要求については、異なるタスク・スレッドで処理できます。たとえば、タスク・スレッド1はユーザー・セッション1からの要求を処理し、その後、ユーザー・セッション2からの要求を処理することができます。

参照:
外部プロシージャ用のプロセスの管理方法の詳細は、『Oracle Database管理者ガイド』を参照してください。

図A-1 マルチスレッドextprocエージェントのアーキテクチャ

この3種類のスレッドは、それぞれOracle Databaseマルチスレッド・サーバーのPMON、ディスパッチャおよび共有サーバー・プロセスにほぼ対応しています。

注意:
あるユーザー・セッションからのリクエストはすべて、同じディスパッチャ・スレッドによって処理されますが、異なるタスク・スレッドで処理できます。また、複数のタスク・スレッドで外部プロシージャに対して同じ接続を使用できます。

次の各項では、各種スレッドについてより詳細に説明します。

- 監視スレッド

- ディスパッチャ・スレッド

- タスク・スレッド

参照:
エージェント制御ユーティリティagtctlを使用してマルチスレッドexprocエージェントを起動および停止する方法の詳細は、「マルチスレッドextprocエージェントの管理」を参照してください。

監視スレッド

エージェント制御ユーティリティagtctlは、あるSIDに対してマルチスレッドextprocエージェントを起動する際、監視スレッドを作成します。監視スレッドは次の機能を実行します。

- ディスパッチャ・スレッドおよびタスク・スレッドを作成します。

- ディスパッチャ・スレッドを、このextprocエージェントへの接続を処理している全リスナーに登録します。このSIDに対するディスパッチャが実行中の場合、リスナーは着信接続要求の取得時にプロセスを起動しません。かわりに、リスナーはこの同じディスパッチャに接続を渡します。

- 他のスレッドを監視し、ディスパッチャ・スレッドに関する負荷情報をこのextprocエージェントへの接続を処理しているすべてのリスナー・プロセスに送信します。これにより、リスナーは着信要求接続を負荷が最小のディスパッチャに渡すことができます。

- 作成した各スレッドの監視を続行します。

ディスパッチャ・スレッド

ディスパッチャ・スレッドは次の機能を実行します。

- 着信接続リクエストおよびタスク・リクエストをOracle Databaseサーバーから受け入れます。

- 着信リクエストをキューに入れ、タスク・スレッドがこれを取得できるようにします。

- リクエストの結果を、そのリクエストの発行元のサーバーに戻します。

注意:
ユーザー・セッションがディスパッチャとの接続を確立した後は、そのユーザー・セッションからのすべてのリクエストはユーザー・セッションが終了するまで同じディスパッチャに送信されます。

タスク・スレッド

タスク・スレッドは次の機能を実行します。

- リクエストをキューから取得します。

- 必要な操作を実行します。

- 結果をキューに入れ、ディスパッチャがそれを取得できるようにします。

マルチスレッドextprocエージェントの管理

マルチスレッドextprocエージェントは、外部プロシージャへの接続を試行する前に、システム識別子(SID)ごとに起動する必要があります。

マルチスレッドextprocエージェントは、agtctlというエージェント制御ユーティリティによって起動、停止および構成されます。このエージェントの機能は、lsnrctlと同様です。ただし、lsnrctlが構成ファイル(listener.ora)を読み取るのに対して、agtctlは構成情報をコマンドラインから取得して制御ファイルに書き込みます。

agtctlを起動する前にOracle Listenerが実行していることを確認します。次に、例A-1のようにagtctlコマンドを使用して、agtctl構成パラメータを設定し(デフォルト値を使用しない場合)、agtctlを起動します。

例A-1 構成パラメータの設定とagtctlの起動

agtctl set max_dispatchers  2 ep_agt1
agtctl set tcp_dispatchers  1   ep_agt1
agtctl set max_task_threads 2  ep_agt1
agtctl set max_sessions     5 ep_agt1
agtctl unset listener_address ep_agt1
agtctl set listener_address "(address=(protocol=ipc)(key=extproc))" ep_agt1
agtctl startup extproc ep_agt1

agtctlコマンドは、単一行コマンド・モードでもシェル・モードでも使用できます。

内容は次のとおりです。

- エージェント制御ユーティリティ(agtctl)のコマンド

- 単一行コマンド・モードでのagtctlの使用

- シェル・モード・コマンドの使用

- マルチスレッドextprocエージェント制御用の構成パラメータ

エージェント制御ユーティリティ(agtctl)のコマンド

agtctlの起動と停止、およびその制御ファイルの作成と管理は、表A-1に示すコマンドを使用して実行できます。

表A-1 エージェント制御ユーティリティ(agtctl)のコマンド

コマンド

説明

startup

マルチスレッドextprocエージェントの起動

shutdown

マルチスレッドextprocエージェントの停止

set

マルチスレッドextprocエージェントの構成パラメータの設定

unset

パラメータのデフォルト値へのリセット

show

構成パラメータの値の表示

delete

制御ファイルからの特定のSIDのエントリの削除

exit

シェル・モードの終了

help

使用可能なコマンドの表示

前述のコマンドを発行するには、次の2つの方法があります。

- コマンドをUNIXまたはDOSシェルから発行できます。このモードは単一行コマンド・モードと呼ばれます。

- agtctlと入力すると、AGTCTL>プロンプトが表示されます。その後は、agtctlシェル内からコマンドを入力できます。このモードはシェル・モードと呼ばれます。

agtctlコマンドの構文とパラメータは、発行時のモードに応じて異なります。

注意:

- すべてのコマンドで大/小文字が区別されます。

- agtctlユーティリティは、2つの環境変数AGTCTL_ADMINまたはTNS_ADMINのいずれかで指定されるディレクトリに制御ファイルを配置します。これらの2つの環境変数のうち少なくとも一方が設定され、エージェントがアクセスするディレクトリを指していることを確認してください。

- マルチスレッドextprocエージェントで環境変数の設定が必要な場合、または専用モードで動作するエージェントのlistener.oraエントリの構成時にENVSパラメータを使用した場合は、agtctlユーティリティを実行するUNIXまたはDOSシェル内で必須のすべての環境変数を設定する必要があります。

単一行コマンド・モードでのagtctlの使用

この項では、agtctlコマンドの使用について説明します。これらのコマンドは単一行コマンド・モードで表示されます。

マルチスレッドextprocエージェントの構成パラメータの設定

マルチスレッドextprocエージェントを起動する前に、その構成パラメータを設定します。構成パラメータが特に設定されていない場合は、デフォルト値が使用されます。構成パラメータとそのデフォルト値については、表A-2を参照してください。

setコマンドを使用して、マルチスレッドextprocエージェントの構成パラメータを設定します。

構文

agtctl set parameter parameter_value agent_sid

parameterは、設定するパラメータです。

parameter_valueは、パラメータに割り当てられる値です。

agent_sidは、このエージェントで処理するSIDです。この指定は、単一行コマンド・モードでは必須です。

例

agtctl set max_dispatchers 5 salesDB

マルチスレッドextprocエージェントの起動

startupコマンドを使用して、マルチスレッドextprocエージェントを起動します。

構文

agtctl startup extproc agent_sid

agent_sidは、このマルチスレッドextprocエージェントで処理するSIDです。この指定は、単一行コマンド・モードでは必須です。

例

agtctl startup extproc salesDB

マルチスレッドextprocエージェントの停止

shutdownコマンドを使用して、マルチスレッドextprocエージェントを停止します。次の3つの停止形式があります。

- 通常(デフォルト)
agtctlは、マルチスレッドextprocエージェントにエージェント自体を正常終了するように要求します。すべてのセッションは、実行中の操作を完了してから停止します。

- 即時
agtctlは、マルチスレッドextprocエージェントに即時に終了するように指示します。エージェントは、現行のセッションの状態に関係なく即時に終了します。

- 中断
マルチスレッドextprocエージェントと対話をせずに、agtctlはシステム・コールを発行してエージェントを停止します。

構文

agtctl shutdown [immediate|abort] agent_sid

agent_sidは、このマルチスレッドextprocエージェントで処理するSIDです。この指定は、単一行コマンド・モードでは必須です。

例

agtctl shutdown immediate salesDB

構成パラメータの値の確認

構成パラメータの値を確認するには、showコマンドを使用します。

構文

agtctl show parameter agent_sid

parameterは、確認するパラメータです。

agent_sidは、このマルチスレッドextprocエージェントで処理するSIDです。この指定は、単一行コマンド・モードでは必須です。

例

agtctl show max_dispatchers salesDB

構成パラメータのデフォルト値へのリセット

unsetコマンドを使用すると、構成パラメータをデフォルト値にリセットできます。

構文

agtctl unset parameter agent_sid

parameterは、リセット(変更)するパラメータです。

agent_sidは、このマルチスレッドextprocエージェントで処理するSIDです。この指定は、単一行コマンド・モードでは必須です。

例

agtctl unset max_dispatchers salesDB

制御ファイルからの特定のSIDのエントリの削除

指定したSIDエントリを制御ファイルから削除するには、deleteコマンドを使用します。

構文

agtctl delete agent_sid

agent_sidは、削除するSIDエントリです。

例

agtctl delete salesDB

ヘルプのリクエスト

helpコマンドを使用して、agtctlに使用可能なコマンドのリストまたは特定のコマンドの構文を表示します。

構文

agtctl help [command]

commandは、構文を表示するコマンドの名前です。デフォルトは、全agtctlコマンドです。

例

agtctl help set

シェル・モード・コマンドの使用

シェル・モードでagtctlを起動するには、次のとおり入力します。

agtctl

これにより、AGTCTL>プロンプトが表示されます。その後はagtctlシェルからコマンドを発行するため、コマンド文字列に接頭辞agtctlを付ける必要はありません。

次のように入力し、エージェントのSID名を設定します。

AGTCTL> set agent_sid agent_sid

これ以降に発行するコマンドはすべて、agent_sid値を変更するまでは、指定したSIDに対するものとみなされます。単一行コマンド・モードとは異なり、コマンド文字列でagent_sidを指定する必要はありません。

エラー・メッセージの言語は次のように設定できます。

AGTCTL> set language language

コマンド自体は、単一行コマンド・モードの場合と同じです。シェル・モードを終了するには、exitと入力します。

次にシェル・モードのコマンドの例を示します。

例: 構成パラメータの設定

この例では、shutdown_address構成パラメータに値を設定しています。

AGTCTL> set shutdown_address (address=(protocol=ipc)(key=oraDBsalesDB))

例: マルチスレッドextprocエージェントの起動

この例では、マルチスレッドextprocエージェントを起動しています。

AGTCTL> startup extproc

マルチスレッドextprocエージェント制御用の構成パラメータ

表A-2では、エージェント制御ユーティリティの構成パラメータについて説明しデフォルト値を示します。

表A-2 agtctlの構成パラメータ

パラメータ

説明

デフォルト値

max_dispatchers

最大ディスパッチャ数

1

tcp_dispatchers

TCPでリスニングするディスパッチャ数(その他はIPCを使用)

0

max_task_threads

タスク・スレッドの最大数

2

max_sessions

各タスク・スレッドのセッションの最大数

5

listener_address

リスナーのリスニング対象アドレス(登録に必要)

(ADDRESS_LIST=
(ADDRESS=
(PROTOCOL=IPC)
(KEY=PNPKEY))
(ADDRESS=
(PROTOCOL=IPC)
(KEY=listener_sid))
(ADDRESS=
(PROTOCOL=TCP)
(HOST=127.0.0.1)
(PORT=1521)))

注意: listener_sidは、Oracle Database上の、リスナーがリスニングしているアドレスのIPCキーです。

shutdown_address

リスナーと通信するためにエージェントが使用するアドレス。エージェントはこのアドレスで、agtctlからの停止メッセージを含むすべての通信をリスニングします。

(ADDRESS=
(PROTOCOL=IPC)
(KEY=listener_sid || agent_sid))
(ADDRESS=
(PROTOCOL=TCP)
(HOST=127.0.0.1)
(PORT=1521))

注意:

- agent_sidは、このマルチスレッドextprocエージェントのSIDです。

- ||は、listener_sidおよびagent_sidが1つの文字列として連結されることを示します。

max_dispatchers、tcp_dispatchers、max_task_threadsおよびmax_sessions

パフォーマンスを向上させるために、max_dispatchers、tcp_dispatchers、max_task_threadsおよびmax_sessionsパラメータの一部あるいはすべての値を変更する必要がある場合があります。

max_dispatchers、tcp_dispatchers、max_task_threadsの最適な値は次の式を使用して計算できます。

max_dispatchers = CEIL(x/y)
tcp_dispatchers = CEIL(x_tcpip/y)
max_task_threads = CEIL(x/max_sessions)

パラメータは次のとおりです。

- CEILは、引数以上の最小の整数を返すSQL関数です。

- xは、extprocに同時に接続できるセッションの最大数です。

- yは、システムが各ディスパッチャに対してサポートする接続の最大数です。

- x_tcpipは、TCP/IPでextprocに同時に接続できるセッションの最大数です。
(x - x_tcpipは、IPCでextprocに同時に接続できるセッションの最大数です。)

max_sessionsの最適な値を計算するための式はありません。これは、max_task_threadsに影響します。

ハードウェアの性能に応じてこれらのパラメータ設定を微調整する必要があります。同時スレッドによってオペレーティング・システムに負荷がかかりすぎないようにしてください。

max_dispatchersの値は1(デフォルト)以上にする必要があります。

例

次の場合について考えます。

- extprocに同時に接続できるセッションの最大数(x)は650です。

- TCP/IPでextprocに同時に接続できるセッションの最大数(x_tcpip)は400です。
(IPCでextprocに同時に接続できるセッションの最大数は、650-400=250です。)

- システムが各ディスパッチャに対してサポートする接続の最大数(y)は100です。

- 各タスク・スレッドのセッションの最大数(max_sessions)は20です。

パラメータの最適値は次のようになります。

max_dispatchers = CEIL(650/100) = CEIL(6.5)  = 7
tcp_dispatchers  = CEIL(400/100) = CEIL(4)    = 4
max_task_threads = CEIL(650/20)  = CEIL(32.5) = 33

つまり最適な設定は次のとおりです。

- ディスパッチャの最大数は7です。

- 7つのディスパッチャのうち4つがTCP/IPでリスニングし、残りの3つがIPCでリスニングします。

- タスク・スレッドの最大数は33です。

listener_addressおよびshutdown_address

構成パラメータlistener_addressおよびshutdown_addressの値が、表A-2と例A-1の両方で示すようにADDRESSに指定されています。ADDRESSには、パラメータHOSTを指定できます。これは、IPv6またはIPv4アドレス、あるいはホスト名です。HOSTがホスト名の場合は、ADDRESSのオプション・パラメータIPの次の値が対応します。

IP値

意味

FIRST

ホスト名のDNS解決によって返される最初のIPアドレスをリスニングします。

V4_ONLY

システムのIPv4インタフェースのみをリスニングします。

V6_ONLY

システムのIPv6インタフェースのみをリスニングします。

たとえば、listener_addressまたはshutdown_addressに次の値を指定するとIPv6インタフェースに限定されます。

"(ADDRESS=(PROTOCOL=tcp)(HOST=sales)(PORT=1521)(IP=V6_ONLY))"

参照:
Oracle DatabaseでのIPv6サポートの詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。

索引
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y

記号

%ROWTYPE属性, 6.1.2.2.3

%TYPE属性, 6.1.2.2.3

数値

32ビットIEEE 754形式, 1.3.2.1

3GL(第3世代言語), 6.7.4

64ビットIEEE 754形式, 1.3.2.1

A

抽象データ型(ADT)

エディション, 19.1.1.2

進化をリセット, 19.1.1.3

Active Server Pages(ASP), 10.4 実オブジェクト, 19.1.3 実オブジェクト化, 19.1.3

スキーマ・オブジェクト依存性, 19.1.3.2

行のアドレス

「ROWID」を参照

ADT

エディション, 19.1.1.2

進化をリセット, 19.1.1.3

AFTER SUSPENDトリガー, 2.9.2.1 エージェント, 16.3 エージェント制御ユーティリティ(agtctl)

コマンド

シェル・モード, A.3.3

単一行モード, A.3.2

リスト, A.3.1

extproc管理, A.3 extprocアーキテクチャ, A.2 集計関数, 6.11 オンラインでのアプリケーション変更

「エディションベースの再定義」を参照

祖先エディション, 19.1.2 無名ブロック, 6.1.1 ANSIデータ型, 1.5.7 ANYDATAデータ型, 1.5.6 ANYDATASETデータ型, 1.5.6 AP(アプリケーション・プログラム), 15.1.1 アプリケーション・アーキテクチャ, 13.1 アプリケーション・ドメイン索引, 4.3 アプリケーション・プログラム(AP), 15.1.1 アプリケーションSQL, 19.3.3.2.3 APPLYING_CROSSEDITION_TRIGGERファンクション, 19.3.4.1.1 AQ(Oracle Advanced Queuing), 16.2.2 アーカイブ

「フラッシュバック・データ・アーカイブ」を参照

ARGnデータ型, 1.9.1 算術演算子

日時データ型の使用, 1.4.4

ネイティブ浮動小数点データ型の使用, 1.3.4

Active Server Pages(ASP), 10.4 代入

データ型変換, 1.8.1, 1.8.1

PL/Scopeによるレポート, 7.6

属性

%ROWTYPE, 6.1.2.2.3

%TYPE, 6.1.2.2.3

Java STATICクラス, 6.9.4.3

監査方針, エディショニング・ビュー, 19.5.1 自動UNDO管理システム, 12.1 自律型トランザクション, 2.8

トリガー, 2.9.2.1

B

下位互換性

LONGおよびLONG RAWデータ型, 1.5.3.2

RESTRICT_REFERENCESプラグマ, 6.9.4.4

REDOオプションのBATCHコミット, 2.2.4 BFILEデータ型, 1.5.3.1 2進数, 1.3.2.1 バイナリ内部ROWID形式, 1.7.2.3 バイナリ・ラージ・オブジェクト(BLOB)データ型, 1.5.3.1 2進数, 1.3.2 BINARY_DOUBLEデータ型, 1.3 BINARY_FLOATデータ型, 1.3 BLOBデータ型, 1.5.3.1 ブロック, 無名, 6.1.1 ブランチ, 15.1.1 組込み関数

「SQLファンクション」を参照

バルク・バインド, 6.1.2.14

使用する場合, 6.1.2.15

ビジネス・ルール, 5

C

外部Cサブプログラム

コールバック, 14.13

グローバル変数, 14.13.6

PL/SQLとのインタフェース, 14.5.2

起動, 14.10.4

ロード, 14.4.2

パラメータ渡し, 14.9

発行, 14.7

実行, 14.10

サービス・ルーチン, 14.12

「外部サブプログラム」も参照

C++クラス・ライブラリ, 13.11.5 コール仕様

外部サブプログラム, 14.3

位置, 14.8

CALL文, 14.10 サブプログラムのコール

「サブプログラムの起動」を参照

連鎖的な無効化, 18.4 CHANGE_DUPKEY_ERROR_INDEXヒント, 19.3.4.1.1 CHARデータ型

VARCHAR2データ型との比較, 1.2.2

長さの指定, 1.2.1

格納される値, 1.2

文字データ型クラス, 18.10.2.4 文字データ型, 1.2 キャラクタ・ラージ・オブジェクト(CLOB)データ型, 1.5.3.1 CHECK制約

NOT NULL制約との比較, 5.12.4

設計, 5.12.2

複数, 5.12.3

ネーミング, 5.13.2

制限事項, 5.12.1

使用する場合, 5.12

クライアント通知, 16.2.3 クライアント/サーバー・アーキテクチャ, 13.1.1 CLOBデータ型, 1.5.3.1 緩やかな無効化, 18.4 コレクション

エディション, 19.1.1.2

DML文による参照, 6.1.2.15.1

FORループによる参照, 6.1.2.15.3

SELECT文による参照, 6.1.2.15.2

列

デフォルト値

使用する場合, 5.5

複数の外部キー制約, 5.8.3 長さの指定, 1.2.1 REDO管理のコミット, 2.2.4 COMMIT文, 2.2.3 トランザクションのコミット, 2.2.3 比較演算子, 1.3.3 コンパイル時のエラー, 処理

複数言語プログラム, 14.11

同時実行性

シリアライズ可能トランザクション, 2.7

明示的なロック, 2.5.5

条件式のデータとしての表現, 1.6 接続プール, 13.6.1 制約, 5

変更, 5.15

CHECK

「CHECK制約」を参照

トリガーとの比較, 5.1 crosseditionトリガー

衝突, 19.3.4.1.1

削除, 19.3.6

チェックの遅延, 5.8.4 使用禁止

効果, 5.14

既存, 5.14.5, 5.14.5

新規, 5.14.3, 5.14.3

理由, 5.14.1

削除, 5.17, 5.17 エディショニング・ビュー, 19.2.6 使用可能

効果, 5.14

既存, 5.14.4

新規, 5.14.2

例外, 5.14.7 FOREIGN KEY

「FOREIGN KEY制約」を参照

オーバーヘッドの最小化, 5.9 ネーミング, 5.13.2 NOT NULL

「NOT NULL制約」を参照

ビュー, 5 PRIMARY KEY

「PRIMARY KEY制約」を参照

定義に必要な権限, 5.13.1 参照整合性

「FOREIGN KEY制約」を参照

名前の変更, 5.16 UNIQUE

「UNIQUE制約」を参照

定義のビュー, 5.19 違反, 5.14.7 連続問合せ通知(CQN), 11 データ型の変換

「データ型変換」を参照

変更時にコピー, 19.1.3 結合, 15.1.1 CQ_NOTIFICATION$_DESCRIPTORオブジェクト, 11.8.1 CQ_NOTIFICATION$_QUERYオブジェクト, 11.8.3 CQ_NOTIFICATION$_REG_INFOオブジェクト, 11.6.6.2 CQ_NOTIFICATION$_ROWオブジェクト, 11.8.4 CQ_NOTIFICATION$_TABLEオブジェクト, 11.8.2 CQN(連続問合せ通知), 11 CREATE OR REPLACEの最適化, 18.4

実オブジェクト化, 19.1.3

crosseditionトリガー, 19.3

作成, 19.3.4

情報の表示, 19.4

削除, 19.3.6

実行, 19.3.3.4

フォワード, 19.3.1

エディションとの相互作用, 19.3.3

読取り専用エディショニング・ビュー, 19.2.1

読取り/書込みエディショニング・ビュー, 19.2.1

リバース, 19.3.2

子カーソルの共有, 19.4

crosseditionトリガーSQL

フォワード, 19.3.3.2.1

リバース, 19.3.3.2.2

セッション間PL/SQLファンクション結果キャッシュ, 6.1.2.7 現在の日付および時刻, 表示, 1.4.1 現行エディション, 19.1.6 カーソル, 2.4

取消し, 2.4.5

クローズ, 2.4.4

crosseditionトリガー, 19.4

セッションでの数, 2.4.1

Oracle XAアプリケーション, 15.3.4

文の再実行, 2.4.2

スキーマ・オブジェクト依存性, 18.11

スクロール可能, 2.4.3

「カーソル変数」も参照

カーソル変数, 6.3

宣言, 6.3.1

例, 6.3.2

オープン, 6.3.1

D

データ定義言語文

「DDL文」を参照

データの整合性, 5

「制約」も参照

データ型, 1.1

ANSI, 1.5.7

DB2, 1.5.7

動的, 1.5.6

外部, 1.1

ファミリ, 1.9.3

文字データ, 1.2

日時データ, 1.4

地理データ, 1.5.1

大量のデータ, 1.5.3

マルチメディア・データ, 1.5.2

数値データ, 1.3

空間データ, 1.5.1

XMLデータ, 1.5.5

オブジェクト, 13.11.3

サブプログラムの仮パラメータ, 6.1.2.2.2

SQL/DS, 1.5.7

データ型クラス, 18.10.2.4 データ型変換, 1.8

ANSIおよびIBMデータ型, 1.5.7

日時データ型, 1.4.5

ネイティブ浮動小数点データ型, 1.3.5

日付

デフォルト書式, 1.4.1

デフォルト値, 1.4.3

表示

現行, 1.4.1

デフォルト以外の書式, 1.4.2

デフォルト以外の書式での挿入, 1.4.2 「日時データ型」も参照 日時データ型クラス, 18.10.2.4 日時データ型, 1.4

算術演算, 1.4.4

変換ファンクション, 1.4.5

インポート、エクスポートおよび比較, 1.4.6

DB2データ型, 1.5.7 DBMS_DEBUGパッケージ, 6.6.8 DBMS_DEBUG_JDWPパッケージ, 6.6.7 DBMS_FLASHBACKパッケージ, 12.7 DBMS_FLASHBACK.TRANSACTION_BACKOUTプロシージャ, 12.8 DBMS_HPROFパッケージ, 8.2 DBMS_LOCKパッケージ, 2.6 DBMS_OUTPUTパッケージ, 6.6.4 DBMS_PARALLEL_EXECUTEパッケージ, 19.3.5 DBMS_STATSパッケージ, 12.11 DBMS_TYPESパッケージ, 1.5.6 DBMS_XAパッケージ, 15.3.10 DDL文

フラッシュバック・データ・アーカイブ, 12.9.6

無効, 18.4

Oracle XA, 15.5.4.2

処理, 2.1

通知を生成する, 11.3.2

デッドロック, 検出されない, 2.6 デバッグ

PL/SQLサーバー・ページ, 10.10

サブプログラム, 6.6

10進数, 1.3.2 デフォルトの列値, 5.5 デフォルト・サブプログラム・パラメータ値, 6.1.2.2.5 制約チェックの遅延, 5.8.4 定義者権限サブプログラム, 6.7.1 非正規の浮動小数点数, 1.3.2.1 依存モード, 18.10 依存オブジェクト

「スキーマ・オブジェクトの依存性」を参照

依存トランザクション, 12.8.1 子孫エディション, 19.1.2 DETERMINISTICファンクション, 6.9.4.2

ファンクション索引, 4.4.2

RPCシグネチャ, 18.10.2

内容を保証しない読込み, 2.7.1 制約を使用禁止にする

効果, 5.14

既存, 5.14.5

新規, 5.14.3

理由, 5.14.1

ディスパッチャ・スレッド, A.2 分散データベース

FOREIGN KEY制約, 5.11

リモートの依存性管理, 18.9

分散問合せ, ランタイム・エラー, 6.5.3 分散トランザクション, 15.1.1

動作方法, 6.8.2

DLL(動的リンク・ライブラリ), 14.2 DML文

バルク・バインド, 6.1.2.15.1

パラレル, 6.9.4.3

コレクションを参照, 6.1.2.15.1

DML_LOCKS初期化パラメータ, 2.5, 2.5 ドメイン索引, 4.3 倍精度IEEE 754形式, 1.3.2.1 ドライバ, Oracle JDBC, 13.4.2.1 DTP(X/Open Distributed Transactionアーキテクチャ), 15.1 動的リンク・ライブラリ(DLL), 14.2 動的登録, 15.1.1 動的SQL文, 6.9.4.4.2 動的に型指定されたデータ, 1.5.6

E

エディション, 19.1

祖先, 19.1.2

作成, 19.1.2

crosseditionトリガー, 19.3.3

現行, 19.1.6

子孫, 19.1.2

情報の表示, 19.4

ユーザーに対する有効化, 19.1.1.3

リーフ, 19.1.2

使用可能にする

すべてのユーザー, 19.1.5

一部のユーザー, 19.1.4

ora$base, 19.1, 19.1.2 リタイア中, 19.1.7 ルート, 19.1.2 セッション, 19.1.6 トリガーの表示可能性, 19.3.3.1 エディション対応のスキーマ・オブジェクト・タイプ, 19.1.1.1 エディションベースの再定義, 19 エディション・オブジェクト, 19.1.1 エディショニング・ビュー, 19.2

監査方針, 19.5.1

実表の変更, 19.2.5

書込み可能性の変更, 19.2.3

表をカバー, 19.5.1

作成, 19.2.1

情報の表示, 19.4

パーティション拡張名, 19.2.2

アプリケーションの準備, 19.5.1

読取り専用, 19.2.1

読取り/書込み, 19.2.1

置換, 19.2.4

SQLオプティマイザ・ヒント, 19.2.7

エディションが有効化されているユーザー, 19.1.1.3 電子製品コード(EPC), 17.7.2.1 埋込みPL/SQLゲートウェイ, 9.2.1.2

使い方, 9.4

制約を使用可能にする

効果, 5.14

既存, 5.14.4

新規, 5.14.2

ユーザーに対するエディションの有効化, 19.1.1.3 コード体系, 追加, 17.3.4 環境, プログラミング, 13 EPC(電子製品コード), 17.7.2.1 エラー処理

コンパイル時, 6.4

複数言語プログラム, 14.11

実行時

「ランタイム・エラー処理」を参照

例外

IEEE 754標準

発生なし, 1.3.2.2

変換時に発生, 1.3.5

複数言語プログラム, 14.11 制約, 5.14.7 未処理, 6.5.2 ユーザー定義, 6.5.1 「ランタイム・エラー処理」も参照 LOCK TABLE文のEXCLUSIVE MODEオプション, 2.5.2.4 EXPRデータ型, 1.9.2 式

条件, データとしての表現, 1.6

評価, データ型変換中に, 1.8.2

作成される索引

「ファンクション索引」を参照

正規

「正規表現」を参照

PSPスクリプトの式ディレクティブ, 10.5.7 拡張内部ROWID形式, 1.7.2.2 外部バイナリ内部ROWID形式, 1.7.2.3 外部データ型, 1.1 外部ラージ・オブジェクト(BFILE)データ型, 1.5.3.1 外部サブプログラム, 14.2

コール仕様, 14.3

デバッグ, 14.13.4

ロード, 14.4

発行, 14.5

外部トランザクション・マネージャ, 15.1.1 extprocエージェント, A

F

データ型のファミリ, 1.9.3, 1.9.3

ファイングレイン監査(FGA)方針, エディショニング・ビュー, 19.5.1

高度な無効化, 18.4

トリガーの起動順序, 19.3.3.3

FIXED_DATE初期化パラメータ, 1.4.1

フラッシュバック・データ・アーカイブ, 12.9

フラッシュバック・トランザクション, 12.8

FLASHBACK_TRANSACTION_QUERYビュー, 12.5

浮動小数点データ型, 1.3

範囲および精度, 1.3.2.1

「ネイティブ浮動小数点データ型」も参照

浮動小数点数

コンポーネント, 1.3.1

非正規, 1.3.2.1

書式, 1.3.2

丸め, 1.3.2

非正規, 1.3.2.1

FORループ

バルク・バインド, 6.1.2.15.3

コレクションを参照, 6.1.2.15.3

ALTER USER文のFORCEオプション, 19.1.1.3 FOREIGN KEY制約, 5.8

分散データベース, 5.11

削除, 5.17

エディション・ビュー, 19.1.1.2

使用可能, 5.18

フラッシュバック・トランザクション, 12.8.1

索引付け, 5.10

複数, 5.8.3

ネーミング, 5.13.2

NOT NULL制約, 5.8.2, 5.8.2

NULL値, 5.8.1

作成に必要な権限, 5.18.4

施行される参照整合性, 5.18.5

UNIQUE制約, 5.8.2, 5.8.2

他の制約なし, 5.8.2

外部キーの依存性, 12.8.1 外部ROWID, 1.7.3 サブプログラムの仮パラメータ, データ型, 6.1.2.2.2 forward crosseditionトリガー, 19.3.1 forward crosseditionトリガーSQL, 19.3.3.2.1 関数

集計, 6.11

組込み

「SQLファンクション」を参照

副作用の制御, 6.9.4 DETERMINISTIC, 6.9.4.2

ファンクション索引, 4.4.2

RPCシグネチャ, 18.10.2

SQL文からの起動, 6.9 MGD_ID ADT, 17.3.3 OCIまたはOCCI, 13.7.2 PARALLEL_ENABLE, 6.9.4.2, 6.9.4.2

RPCシグネチャ, 18.10.2

純粋度, 6.9.4

RPCシグネチャ, 18.10.2

結果キャッシュ, 6.1.2.7 大量のデータの戻し, 6.10 SQL

「SQLファンクション」を参照

「サブプログラム」も参照 ファンクション結果キャッシュ, 6.1.2.7 ファンクション索引, 4.4

エディション・ファンクション, 19.1.1.2

例, 4.4.3

オプティマイザ, 4.4, 4.4.1

G

地理情報システム(GIS)データ, 1.5.1

グローバル・トランザクション, 15.1.1

グローバル変数, 外部Cサブプログラム, 14.13.6

正規表現での最長一致演算子, 3.4.1

グループ・コミット, 2.2.4

H

階層プロファイラ, 8

ホスト言語, 13.6

ホスト・プログラム, 13.6

ホット・ロールオーバー, 19

PSPスクリプトのHTML構文エラー, 10.5.1.3

I

IA-32およびIA-64命令セット・アーキテクチャ, 1.3.4

IBM CICS, 15.1.1

IBM Transarc Encina, 15.1.1

識別コード・パッケージ, 17

IEEE 754形式, 1.3

「ネイティブ浮動小数点データ型」も参照

IEEE 754標準

例外

発生なし, 1.3.2.2

変換時に発生, 1.3.5

データ型のOCIサポート, 1.3.6.1 サポートされている特別な値, 1.3.2.2 IGNORE_ROW_ON_DUPKEY_INDEXヒント, 19.3.4.1.1 REDOオプションのIMMEDIATEコミット, 2.2.4 IN OUTサブプログラム・パラメータ・モード, 6.1.2.2.1 INサブプログラム・パラメータ・モード, 6.1.2.2.1 独立したトランザクション

「自律型トランザクション」を参照

索引, 4

ドメイン, 4.3

エディションベースの再定義, 19.2.6

ファンクション

「ファンクション索引」を参照

MGD_ID列, 17.3.2 無限大, 1.3.2.2, 1.3.2.2 継承オブジェクト, 19.1.3

削除, 19.1.3.1

初期化パラメータ

DML_LOCKS, 2.5

FIXED_DATE, 1.4.1

NLS_DATE_FORMAT, 1.4.1

OPEN_CURSORS, 2.4.1

整数データ型クラス, 18.10.2.4 整合性制約

「制約」を参照

データの整合性, 5 インタフェース

PL/SQLとCの間, 14.5.2

PL/SQLとJavaの間, 14.5.1

OraDatabase, 13.11.2.3

プログラム, 13.2

TX, 15.1.1

ユーザー, 13.2.1

ステートフルまたはステートレス, 13.2.2

「Oracle Call Interface」を参照 無効化

連鎖的な, 18.4

緩やかな, 18.4

高度な, 18.4

依存オブジェクト, 18.4

パッケージ, 6.1.2.12

実行者権限サブプログラム, 6.7.1 サブプログラムの起動, 6.7

3GLアプリケーション, 6.7.4

サブプログラム, 6.7.3

トリガー, 6.7.3

Oracle Databaseツールから対話形式, 6.7.2

埋込みPL/SQLゲートウェイの使用, 9.4.4

分離レベル

「トランザクション分離レベル」を参照

J

Javaクラス・メソッド

コール, 14.10.3

PL/SQLとのインタフェース, 14.5.1

ロード, 14.4.1

発行, 14.6

「外部サブプログラム」も参照

Java Database Connectivity

「Oracle JDBC」を参照

Java言語

PL/SQLとの比較, 13.5

Oracle Databaseのサポート, 13.4

STATICクラス属性, 6.9.4.3

Java Server Pages(JSP), 10.4 Java仮想マシン

「Oracle JVM」を参照

JavaScript, 10.9.5 JDBC

「Oracle JDBC」を参照

JSP(Java Server Pages), 10.4 JVM

「Oracle JVM」を参照

K

キー

外部

「FOREIGN KEY制約」を参照

主

「PRIMARY KEY制約」を参照

一意

「UNIQUE制約」を参照

L

ラージ・オブジェクト(LOB), 1.5.3.1

Oracle Objects for OLEのサポート, 13.11.3

リーフ・エディション, 19.1.2 LGWR(ログ・ライター・プロセス), 2.2.4, 2.2.4 libunit, 14.2 軽量キュー, 16.3 loadpspユーティリティ, 10.6 LOB

「ラージ・オブジェクト(LOB)」を参照

LOCK TABLE文, 2.5.2

SELECT FOR UPDATE文, 2.5.5

明示的な行ロック, 2.5.4 表のロック

明示的, 2.5

暗黙的, 2.5.3

ログ・ライター・プロセス(LGWR), 2.2.4 論理ROWID, 1.7.3 LONGおよびLONG RAWデータ型, 1.5.3.2 疎結合, 15.1.1

M

メイン・トランザクション, 2.8

表の最大可用性, 19.2.1

正規表現のメタキャラクタ, 3.1

SQL演算子または関数のメタデータ, 1.9

MGD_ID ADT, 17.1

MGD_IDデータベースのADTファンクション, 17.3.3

mod_plsqlモジュール, 9.2.1.1

モード

agtctlコマンド, A.3

依存性, 18.10

ロック, 2.5.2

シリアライズ

「シリアライズ可能トランザクション」を参照

サブプログラム・パラメータ, 6.1.2.2.1 ALTER TABLE文のMODIFY CONSTRAINT句, 5.15 変更

「変更」を参照

監視スレッド, A.2 複数言語プログラム, 14.1

エラーおよび例外, 14.11

複数行モード, 3.2 多言語データ, 3.4.2 マルチメディア・データ, 1.5.2 マルチスレッドextprocエージェント, A

N

名前解決, 18.7

エディション, 19.1.3.2

NaN(非数), 1.3.2.2 各国語キャラクタ・ラージ・オブジェクト(NCLOB)データ型, 1.5.3.1 システム固有の実行, サブプログラムのコンパイル, 6.2 ネイティブ浮動小数点データ型, 1.3

算術演算, 1.3.4

2進数, 1.3.2.1

サポートしているクライアント, 1.3.6

比較演算子, 1.3.3

変換ファンクション, 1.3.5

特殊な数値, 1.3.2.2

NCHARデータ型

長さの指定, 1.2.1

格納される値, 1.2

NCLOBデータ型, 1.5.3.1 負の無限大, 1.3.2.2 負のゼロ, 1.3.2.2 新機能, Preface NLS_DATE_FORMAT初期化パラメータ, 1.4.1 非エディション対応のスキーマ・オブジェクト・タイプ, 19.1.1.1 非エディション・オブジェクト, 19.1.1 正規表現での最短一致演算子, 3.4.3 非永続キュー, 16.3 正規化された仮数, 1.3.2.1 NOT NULL制約

CHECK制約との比較, 5.12.4

ネーミング, 5.13.2

FOREIGN KEY制約, 5.8.2, 5.8.2

使用する場合, 5.4

REDOオプションのNOWAITコミット, 2.2.4 LOCK TABLE文のNOWAITオプション, 2.5.2 NULL値

FOREIGN KEY制約, 5.8.1

ファンクション索引, 4.4

索引付け, 5.4

数値

2進数, 1.3.2

10進数, 1.3.2

丸め, 1.3.2

NUMBERデータ型, 1.3 数値データ型クラス, 18.10.2.4 数値データ型, 1.3 NVARCHAR2データ型

長さの指定, 1.2.1

格納される値, 1.2

O

オブジェクト

実, 19.1.3

依存

「スキーマ・オブジェクトの依存性」を参照

エディション化, 19.1.1 継承, 19.1.3

削除, 19.1.3.1

ラージ

「ラージ・オブジェクト(LOB)」を参照

非エディション, 19.1.1 潜在的エディション, 19.1.1 参照

「スキーマ・オブジェクトの依存性」を参照

PL/SQLストアドのサイズ制限, 6.1.2.9 オブジェクト変更通知, 11.1 オブジェクト・データ型, 13.11.3 オブジェクト・タイプ

「スキーマ・オブジェクト型」を参照

OCCI

「Oracle C++ Call Interface」を参照

OCI

「Oracle Call Interface」を参照

OCIAnyDataおよびOCIAnyDataSetインタフェース, 1.5.6 ODC(Oracle Data Control), 13.11.4 ODP.NET, 13.9 アプリケーションのオンライン・アップグレード

「エディションベースの再定義」を参照

OO4O

「Oracle Objects for OLE」を参照

OPEN_CURSORS初期化パラメータ, 2.4.1 演算子

比較, 1.3.3

正規表現, 3.4

最長一致, 3.4.1

最短一致, 3.4.3

メタデータ, 1.9 関係, 1.3.3 オプティマイザ

エディショニング・ビュー, 19.2.7

ファンクション索引, 4.4, 4.4.1

RPCシグネチャ, 18.10.2

ora$baseエディション, 19.1, 19.1.2 Oracle Advanced Queuing(AQ), 16.2.2 Oracle C++ Call Interface, 13.7

アプリケーションを作成, 13.7.4

関数の種類, 13.7.2

手続き型要素および非手続き型要素, 13.7.3

Oracle Call Interface, 13.7

アプリケーションを作成, 13.7.4

REDOアクションのコミット, 2.2.4

プリコンパイラとの比較, 13.8

関数の種類, 13.7.2

手続き型要素および非手続き型要素, 13.7.3

Oracle XAでの使用, 15.3.5

Oracle Data Control(ODC), 13.11.4 Oracle Data Provider for .NET, 13.9 Oracleデータ型

「データ型」を参照

Oracle Databaseパッケージ, 6.1.2.13

低レベルのデバッグ・コードの書込み, 6.6.6

ランタイム・エラーの発生, 6.5

Oracle Expression Filter, 1.6 Oracle Flashback Query, 12.3 Oracle Flashback Technology, 12.1

アプリケーション開発機能, 12.1.1

データベースの構成, 12.2

データベース管理機能, 12.1.2

パフォーマンス・ガイドライン, 12.11

Oracle Flashback Transaction Query, 12.5 Oracle Flashback Version Query, 12.4 Oracle JDBC, 13.4.2

Oracle SQLJとの比較, 13.4.4

サンプル・プログラム

2.0, 13.4.2.2

2.0以前, 13.4.2.3

Oracle JDeveloper, 6.6.3

Oracle SQLJ, 13.4.3.1

Oracle JPublisher, 13.4.5 Oracle JVM, 13.4.1 Oracle Lock Managementサービス, 2.6 Oracle Multimedia, 1.5.2 Oracle Objects for OLE, 13.11

オートメーション・サーバー, 13.11.1

C++クラス・ライブラリ, 13.11.5

オブジェクト・データ型のサポート, 13.11.3

オブジェクト・モデル, 13.11.2

Oracle RACおよびOracle XA, 15.5.3 Oracle SQLJ, 13.4.3

Oracle JDBCとの比較, 13.4.4

Oracle JDeveloper, 13.4.3.1

Oracle Text, 1.5.4, 1.5.4 Oracle Total Recall, 12.9 Oracle Tuxedo, 15.1.1 Oracle仮想プライベート・データベース(VPD)・ポリシー, エディショニング・ビュー, 19.5.1 Oracle XA

Oracle RAC, 15.5.3

サブプログラム, 15.2

使用する場合, 15

OUTサブプログラム・パラメータ・モード, 6.1.2.2.1 領域不足エラー, 2.9 オーバーロードされたサブプログラム, 6.1.2.8

P

パッケージ, 6.1.2.8

メリット, 6.1.2.8

本体, 6.1.2.8

作成, 6.1.2.10

無効化, 6.1.2.12

ネーミング, 6.1.2.11

Oracle Database, 6.1.2.13

低レベルのデバッグ・コードの書込み, 6.6.6

ランタイム・エラーの発生, 6.5

作成に必要な権限, 6.1.2.10.2 削除に必要な権限, 6.1.2.10.2 セッション状態, 18.4.1 サイズ制限, 6.1.2.9 仕様, 6.1.2.8 シノニム, 6.8.1 パッケージの無効化, 6.1.2.12 パッケージ・サブプログラム, 6.1.2 パラレルDML文, 6.9.4.3 パラレル問合せ, 6.9.4.3 PARALLEL_ENABLEファンクション, 6.9.4.2

RPCシグネチャ, 18.10.2

パラメータ

初期化

「初期化パラメータ」を参照

サブプログラム

「サブプログラム・パラメータ」を参照

パラメータ・モード, 6.1.2.2.1 パーティション拡張エディショニング・ビュー名, 19.2.2 永続LOBインスタンス, 1.5.3.1 永続キュー, 16.3 仮読込み, 2.7.1 PL/Scopeツール, 7 plshprofユーティリティ, 8.5 PL/SQLファンクション結果キャッシュ, 6.1.2.7 PL/SQLゲートウェイ, 9.2.1 PL/SQL階層プロファイラ, 8 PL/SQL言語, 13.3

Javaとの比較, 13.5

PL/SQLオブジェクト, CREATE OR REPLACE, 18.4 PL/SQLサーバー・ページ

特性, 10.5.1

要素, 10.5

ロード, 10.6

スクリプト・エラー, 10.5.1.3

PL/SQLユニット, 6.1

ストアド, 6.1.2

PL/SQL Web Toolkit, 9.2.2 プール, 接続, 13.6.1 正の無限大, 1.3.2.2 正のゼロ, 1.3.2.2 正規表現のPOSIX標準

定義された演算子, 3.4.1

Oracle SQL, 3.3

Oracle SQLの多言語拡張機能, 3.4.2

Oracle SQLのPERLの影響を受ける拡張機能, 3.4.3

潜在的エディション・オブジェクト, 19.1.1 プリコンパイラ, 13.6

Oracle Call Interfaceとの比較, 13.8

Oracle XA, 15.3.4

PRIMARY KEY制約, 5.6

削除, 5.17

フラッシュバック・トランザクション, 12.8.1

ネーミング, 5.13.2

主キーの依存性, 12.8.1 権限

パッケージの作成用, 6.1.2.3

サブプログラム作成用, 6.1.2.3

サブプログラムのデバッグ用, 6.6.5

制約定義用, 5.13.1

パッケージの削除用, 6.1.2.5

パッケージ削除用, 6.1.2.10.2

サブプログラム削除用, 6.1.2.5

Oracle Flashback Technology用, 12.2.5

サブプログラム実行用, 6.7.1

権限取消, オブジェクト依存性, 18.4.2

Pro*C/C++プリコンパイラ, 13.6.1

ネイティブ浮動小数点データ型のサポート, 1.3.6.3

Pro*COBOLプリコンパイラ, 13.6.2 プロシージャ

PL/SQL Server Pages, 10.5.3

「サブプログラム」も参照

製品コード, 17.7.2 プロファイラ, 8 プログラム・インタフェース, 13.2 プログラミング環境, 13 PSP

「PL/SQLサーバー・ページ」を参照

パブリック情報, 必須, 15.1.2 パブリッシュ・サブスクライブ・モデル, 16 ファンクションの純粋度, 6.9.4

RPCシグネチャ, 18.10.2

Q

サービスのクオリティ・フラグ, 11.6.6.2

問合せ

パラレル, 6.9.4.3

連続問合せ通知用に登録, 11.6

分散でのランタイム・エラー, 6.5.3

問合せ結果変更通知, 11.2 キュー, 16.3

R

Radio Frequency Identification(RFID)テクノロジ, 17.7.1

RAISE文, 6.5.1

RAWデータ型, 1.5.3.2

RAWデータ型クラス, 18.10.2.4

READ COMMITTEDトランザクション分離レベル

SERIALIZABLEとの比較, 2.7.4.2

Oracle Database, 2.7.1

トランザクションの相互作用, 2.7.1

読込み一貫性

文レベル, 2.3

トランザクション・レベル, 2.3

明示的な表ロック, 2.5

読取り専用トランザクション, 2.3

読込みロック, 2.7.3 READ UNCOMMITTEDトランザクション分離レベル

Oracle Database, 2.7.1

トランザクションの相互作用, 2.7.1

読取り専用エディショニング・ビュー, 19.2.1 読取り専用トランザクション, 2.3 読取り/書込みエディショニング・ビュー, 19.2.1 再定義, エディションベース, 19 トランザクションのREDO情報, 2.2.4 REDO管理, 2.2.4 参照オブジェクト

「スキーマ・オブジェクトの依存性」を参照

参照整合性

シリアライズ可能トランザクション, 2.7.3

施行のトリガー, 2.7.3

参照整合性制約

「FOREIGN KEY制約」を参照

REGEXP_COUNTファンクション, 3.2 REGEXP_INSTRファンクション, 3.2 REGEXP_LIKE条件, 3.2 REGEXP_REPLACEファンクション, 3.2

後方参照の演算子, 3.4.1

REGEXP_SUBSTRファンクション, 3.2 登録

動的, 15.1.1

連続問合せ通知用, 11.6

パブリッシュ・サブスクライブ・モデル, 16.3

静的, 15.1.1

正規表現, 3

Oracle SQL, 3.2

SQL文, 3.5

メタキャラクタ, 3.1

POSIX標準

「正規表現のPOSIX標準」を参照

Unicode, 3.3 関係演算子, 1.3.3 リモートの依存性管理, 18.9 リモート・プロシージャ・コールの管理, 18.10 反復可能読取り, 2.3

読取り専用トランザクション, 2.3

REPEATABLE READトランザクション分離レベル

Oracle Database, 2.7.1

明示的な表ロック, 2.5

トランザクションの相互作用, 2.7.1

必須のパブリック情報, 15.1.2 SQL文の再実行, 2.4.2 リソース・マネージャ(RM), 15.1.1 RESTRICT_REFERENCESプラグマ

下位互換性, 6.9.4.4

オーバーロードされたファンクション, 6.9.4.4.3

静的SQL文および動的SQL文, 6.9.4.4.2

制限付き内部ROWID形式, 1.7.2.1 結果キャッシュ, 6.1.2.7 再開可能記憶域割当て, 2.9 UNDO表領域に対するRETENTION GUARANTEE句, 12.2.1 ALTER TABLE文のRETENTIONオプション, 12.2.4 reverse crosseditionトリガー, 19.3.2 reverse crosseditionトリガーSQL, 19.3.3.2.2 RFID(Radio Frequency Identification)テクノロジ, 17.7.1 RM(リソース・マネージャ), 15.1.1 ROLLBACK文, 2.2.5 トランザクションのロールバック, 2.2.5 ルート・エディション, 19.1.2 浮動小数点数の丸め, 1.3.2 ルーティン

「サブプログラム」を参照

行

アドレス

「ROWID」を参照

明示的ロック, 2.5.4 LOCK TABLE文のROW EXCLUSIVE MODEオプション, 2.5.2.1, 2.5.2.1 LOCK TABLE文のROW SHARE MODEオプション, 2.5.2.1 ROWID, 1.7

外部, 1.7.3

論理, 1.7.3

ユニバーサル(UROWID), 1.7.3

ROWIDデータ型, 1.7.2 ROWID擬似列, 1.7

CQN, 11.6.2.3

「ROWID」も参照

ROWTYPE_MISMATCH例外, 6.3.2 RPC依存性管理, 18.10 RPCシグネチャ依存性モード, 18.10.2 RR日時書式要素1.4.1 キューでのルール, 16.3 ルール・エンジン, 16.3 ランタイム・エラー処理, 6.5

分散問合せ, 6.5.3

PL/SQLサーバー・ページ(PSP)スクリプト, 10.5.1.3

リモート・サブプログラム, 6.5.4

記憶域割当てエラー用, 2.9

ユーザー定義例外用, 6.5.1

「例外」も参照

S

SAVEPOINT文, 2.2.6, 2.2.6

スキーマ・オブジェクトの依存性, 18

実オブジェクト化, 19.1.3.2

分散データベース, 18.9

無効化, 18.4

他のオブジェクトの不在, 18.7

取り消された権限, 18.4.2

共有プール, 18.11

スキーマ・オブジェクト・タイプ

エディション対応, 19.1.1.1

非エディション対応, 19.1.1.1

スクロール可能カーソル, 2.4.3 検索可能なテキスト, 1.5.4 SELECT FOR UPDATE文, 2.5.4

LOCK TABLE文, 2.5.5

参照整合性

トリガー内, 2.7.3

トリガー外, 2.7.3

SELECT文

バルク・バインド, 6.1.2.15.2

コレクションを参照, 6.1.2.15.2

AS OF句使用, 12.3

FOR UPDATE句使用

「SELECT FOR UPDATE文」を参照

VERSIONS BETWEEN句使用, 12.4 準可用性を備えた表, 19.2.1 予期せぬ変更, 19.3.5

データ変換における衝突, 19.3.4.1.1

識別, 19.3.4.1.1

シリアライズ可能トランザクション

同時実行性の制御, 2.7

相互作用, 2.7.1

参照整合性, 2.7.3

SERIALIZABLEトランザクション分離レベル

READ COMMITTEDとの比較, 2.7.4.2

Oracle Database, 2.7.1

トランザクションの相互作用, 2.7.1

「シリアライズ可能トランザクション」も参照

サーバー側のプログラミング, 13.1.2 サービス・ルーチン, 外部Cサブプログラム, 14.12 セッション・エディション, 19.1.6 セッション状態, 18.4.1 セッション変数, 6.7.2 SET CONSTRAINTS文, 5.8.4 READ ONLYオプションを使用したSET TRANSACTION文, 2.3 LOCK TABLE文のSHARE MODEオプション, 2.5.2.2 LOCK TABLE文のSHARE ROW EXCLUSIVE MODEオプション, 2.5.2.3 共有SQL領域, 2.1 ファンクションの副作用, 制御, 6.9.4 シグネチャ・チェック, 18.9.1 単精度IEEE 754形式, 1.3.2.1 空間データ, 1.5.1 SQL領域, 共有, 2.1 SQLデータ型

「データ型」を参照

SQLファンクション

型の表示, 1.9.2

データ型変換, 1.4.5

メタデータ, 1.9

SQLオプティマイザ・ヒントとエディショニング・ビュー, 19.2.7 SQL文

アプリケーション, 19.3.3.2.3

crosseditionトリガー

フォワード, 19.3.3.2.1

リバース, 19.3.3.2.2

動的, 6.9.4.4.2 PL/SQLファンクションの起動, 6.9 処理

DDL文, 2.1

ステージング, 2.1

システム管理文, 2.1, 2.1

再実行, 2.4.2 静的, 6.9.4.4.2 SQL/DSデータ型, 1.5.7 SQLJ

「Oracle SQLJ」を参照

SQLT_BDOUBLEデータ型, 1.3.6.1 SQLT_BFLOATデータ型, 1.3.6.1 スタンドアロン・サブプログラム, 6.1.2 状態

セッション, 18.4.1

ユーザー・インタフェース, 13.2.2

Webアプリケーション, 9.6.8

文

「SQL文」を参照

文レベルの読取り一貫性, 2.3 静的登録, 15.1.1 静的SQL文, 6.9.4.4.2 静的変数, 外部Cサブプログラム, 14.13.7 統計

アプリケーション用, 8

識別子用, 7

記憶域割当てエラー, 2.9 ストアドPL/SQLユニット, 6.1.2 非正規の浮動小数点数, 1.3.2.1 サブプログラム

システム固有の実行用にコンパイル, 6.2

作成, 6.1.2.3

定義者権限, 6.7.1

エディション化, 19.1.1.2

例外処理, 6.5.1

外部

「外部サブプログラム」を参照

実行者権限, 6.7.1 起動

「サブプログラムの起動」を参照

ネーミング, 6.1.2.1 Oracle XA, 15.2 オーバーロード, 6.1.2.8 パッケージ, 6.1.2 パラメータ

「サブプログラム・パラメータ」を参照

デバッグに必要な権限, 6.6.5 実行に必要な権限, 6.7.1 リモート, 6.5.4 サイズ制限, 6.1.2.9 スタンドアロン, 6.1.2 シノニム, 6.8.1 「ファンクション」および「プロシージャ」も参照 サブプログラム・パラメータ, 6.1.2.2

コンポジット変数, 6.1.2.2.4

仮パラメータのデータ型, 6.1.2.2.2

デフォルト値, 6.1.2.2.5

モード, 6.1.2.2.1

サブスクライバ, 16.3 サブスクリプション・サービス, 16.3 シノニム

CREATE OR REPLACE PACKAGE, 18.4

パッケージ, 6.8.1

サブプログラム, 6.8.1

パブリック, エディション・オブジェクト, 19.1.1.2

SYSDATEファンクション, 1.4.1 システム管理文, 2.1, 2.1

T

表

ロック

方法の選択, 2.5.2

明示的, 2.5

暗黙的, 2.5.3

最大可用性, 19.2.1 準可用性, 19.2.1 Tag Data Translationマークアップ言語スキーマ, 17.1 タスク・スレッド, A.2 一時LOBインスタンス, 1.5.3.1 Thinクライアント構成, 13.1.3 第3世代言語(3GL), 6.7.4 スレッド

ディスパッチャ, A.2

監視, A.2

Oracle XAライブラリ, 15.3.9

タスク, A.2

3層アーキテクチャ, 13.1.3 密結合, 15.1.1 時間

デフォルト書式, 1.4.3

デフォルト値, 1.4.3

表示

現行, 1.4.1

デフォルト以外の書式, 1.4.3

デフォルト以外の書式での挿入, 1.4.3 「日時データ型」も参照 タイムスタンプ・チェック, 18.9.1 タイムスタンプ依存性モード, 18.10.1 TM(トランザクション・マネージャ), 15.1.1 TPM(トランザクション処理モニター), 15.1.1 トランザクション

自律型, 2.8

トリガー, 2.9.2.1

分離レベルの選択, 2.7.4.2 コミット, 2.2.3 依存, 12.8.1 分散, 15.1.1

動作方法, 6.8.2

グローバル, 15.1.1 操作のグループ化, 2.2.1 パフォーマンスの改善, 2.2.2 メイン, 2.8, 2.8 読取り専用, 2.3 REDOエントリ, 2.2.4 ロールバック, 2.2.5 セーブポイント, 2.2.6 シリアライズ可能

「シリアライズ可能トランザクション」を参照

文, 2.2.6 トランザクションの相互作用

種類, 2.7.1

シリアライズ可能トランザクション, 2.7.1

トランザクション分離レベル, 2.7.1

トランザクション分離レベル

選択, 2.7.4.2

設定, 2.7.2

トランザクションの相互作用, 2.7.1

トランザクション・マネージャ(TM), 15.1.1 トランザクション処理モニター(TPM), 15.1.1 トランザクション集合の整合性, 2.7.4.1 トランザクション・レベルの読取り一貫性, 2.3

明示的な表ロック, 2.5

読取り専用トランザクション, 2.3

変換, 19.3.1

適用, 19.3.5

トリガー, 6.1.2.16

AFTER SUSPEND, 2.9.2.1

自律型トランザクションとして, 2.9.2.1

制約との比較, 5.1

crossedition

「crosseditionトリガー」を参照

参照整合性の施行, 2.7.3 エディション

起動順序, 19.3.3.3

可視性, 19.3.3.1

起動できる種類, 19.3.3.2

サブプログラムの起動, 6.7.3 サイズ制限, 6.1.2.9 RESTRICT_REFERENCESプラグマのTRUSTキーワード, 6.9.4.4.1 2フェーズ・コミット・プロトコル, 15.1.1 2層アーキテクチャ, 13.1.3 TXインタフェース, 15.1.1 型属性, 6.1.2.2.3

U

検出されないデッドロック, 2.6

UNDOデータ, 12.1

UNDO_RETENTIONパラメータ, 2.3

トランザクションの取消し, 2.2.5

未処理例外, 6.5.2

Unicode

文字リテラル, 1.2.1

正規表現, 3.3

UNIQUE制約

crosseditionトリガー, 19.3.4.1.1

削除, 5.17

ネーミング, 5.13.2

FOREIGN KEY制約, 5.8.2, 5.8.2

使用する場合, 5.7

ユニバーサルROWID(UROWID), 1.7.3 反復不能な読込み, 2.7.1 オンラインでのアプリケーション・アップグレード

「エディションベースの再定義」を参照

UROWIDデータ型, 1.7.3 ユーザー・インタフェース, 13.2.1

ステートフルおよびステートレス, 13.2.2

ユーザー・ロック, 2.6 ユーザー定義例外, 6.5.1 ユーザー定義型, サブプログラム・パラメータとして, 6.1.2.2.4 UTLLOCKT.SQLスクリプト, 2.6.2

V

VARCHARデータ型クラス, 18.10.2.4

VARCHAR2データ型

CHARデータ型との比較, 1.2.2

長さの指定, 1.2.1, 1.2.1

格納される値, 1.2

変数

カーソル

「カーソル変数」を参照

外部Cサブプログラム

グローバル, 14.13.6

静的, 14.13.7

VERSIONS_ENDSCN疑似列, 12.4 VERSIONS_ENDTIME疑似列, 12.4 VERSIONS_OPERATION疑似列, 12.4 VERSIONS_STARTSCN疑似列, 12.4 VERSIONS_STARTTIME疑似列, 12.4 VERSIONS_XID疑似列, 12.4 ビュー

制約, 5

エディション化

FOREIGN KEY制約, 19.1.1.2

マテリアライズド・ビュー, 19.1.1.2

エディション

「エディショニング・ビュー」を参照

VPD方針, エディショニング・ビュー, 19.5.1

W

REDOオプションのWAITコミット, 2.2.4

LOCK TABLE文のWAITオプション, 2.5.2, 2.5.2

Webアプリケーション, 9.1

実装, 9.2

状態, 9.6.8

Webページ

「PL/SQLサーバー・ページ」も参照

Webサービス, 13.4.7 Web Toolkit

「PL/SQL Web Toolkit」を参照

ROLLBACK文のWORKオプション, 2.2.5 wrapユーティリティ, デバッグ, 6.6.5 エディショニング・ビューの書込み可能性, 19.2.3 Write-after-Write依存性, 12.8.1

X

xa_open文字列, 15.3.3

XMLTypeデータ型, 1.5.5

X/Open Distributed Transactionアーキテクチャ, 15.1

X/Open Distributed Transaction Processing(DTP)アーキテクチャ, 15.1

Y

YY日時書式要素1.4.2

オラクル社の法律上の注意点について

コピーライトについて

Copyright © 1994-2015, Oracle and/or its affiliates.All rights reserved.

商標と登録商標について

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

制限付権利

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション（人的傷害を発生させる可能性があるアプリケーションを含む）への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性（redundancy）、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

ドラフトのアルファ版およびベータ版ドキュメントについて

このドキュメントが試作版の場合:

このドキュメントは試作版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。オラクル社およびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。