5 埋込みSQL
この章では、埋込みSQLプログラムの基本的な方法を説明します。内容は次のとおりです。
5.1 ホスト変数の使用方法
5.1.1 出力ホスト変数および入力ホスト変数
ホスト変数は、使用方法によって出力ホスト変数または入力ホスト変数と呼ばれます。SELECT文またはFETCH文のINTO句内のホスト変数は、Oracleによって出力される列の値が入るため出力ホスト変数と呼ばれます。Oracleは、列の値をINTO句内の対応する出力ホスト変数に割り当てます。
SQL文のその他のホスト変数の値は、プログラムがそれをOracleに入力するため、すべて入力ホスト変数と呼ばれます。たとえば、INSERT文のVALUES句内およびUPDATE文のSET句内では入力ホスト変数を使用します。入力ホスト変数はWHERE句、HAVING句およびFOR句内でも使用されます。実際、入力ホスト変数は、SQL文内で値または式を使用できる位置であればどこにでも使用できます。
入力ホスト変数は、SQLキーワードまたはデータベース・オブジェクトの名前を指定するためには使用できません。つまり、ALTER、CREATEおよびDROPなどのデータ定義文(DDLとも呼ばれます)では入力ホスト変数を使用できません。次の例のDROP TABLE文は無効です。
EXEC SQL BEGIN DECLARE SECTION END-EXEC. 01 TABLE-NAME PIC X(30) VARYING. ... EXEC SQL END DECLARE SECTION END-EXEC. ... DISPLAY 'Table name? '. ACCEPT TABLE-NAME. EXEC SQL DROP TABLE :TABLE-NAME END-EXEC. * -- host variable not allowed
注意:
ORDER BY句ではホスト変数が使用できますが、定数またはリテラルとして扱われるのでホスト変数の内容は無効になります。たとえば、次のようなSQL文があるとします。
EXEC SQL SELECT ENAME, EMPNO INTO :NAME, :NUMBER FROM EMP ORDER BY :ORD END-EXEC.
この文では、入力ホスト変数ORDが使用されていますが、この場合のホスト変数は定数として扱われます。そのため、ORDの値が何であっても順序付けは行われません。
入力ホスト変数を含むSQL文をOracleで実行する前に、それらの入力ホスト変数に値を割り当てる必要があります。次に例を示します。
EXEC SQL BEGIN DECLARE SECTION END-EXEC. 01 EMP-NUMBER PIC S9(4) COMP. 01 EMP-NAME PIC X(20) VARYING. EXEC SQL END DECLARE SECTION END-EXEC. ... * -- get values for input host variables DISPLAY 'Employee number? '. ACCEPT EMP-NUMBER. DISPLAY 'Employee name? '. ACCEPT EMP-NAME. EXEC SQL INSERT INTO EMP (EMPNO, ENAME) VALUES (:EMP-NUMBER, :EMP-NAME) END-EXEC.
INSERT文のVALUES句内で入力ホスト変数の前にコロンが付いていることに注意してください。
5.2 標識変数の使用方法
任意のホスト変数に任意指定の標識変数を関連付けることができます。標識変数に関連付けたホスト変数をSQL文内で使用するたびに、結果コードが対応する標識変数内に格納されます。つまり、標識変数によってホスト変数を監視できます。
VALUES句またはSET句中の標識変数を使用して、入力ホスト変数にNULLを割り当てたり、INTO句中の標識変数を使用して、出力ホスト変数内のNULLまたは切り捨てられた値を検出できます。
5.2.1 入力変数
入力ホスト変数の場合、プログラムがインディケータ変数に割り当てる値の意味は次のとおりです。
変数 | 意味 |
---|---|
-1 |
Oracleによって、その列にNULLが割り当てられます。このホスト変数の値は無視されます。 |
>= 0 |
Oracleによって、このホスト変数の値が列に割り当てられます。 |
5.2.2 出力変数
出力ホスト変数の場合、Oracleが標識変数に割り当てる値の意味は次のとおりです。
変数 | 意味 |
---|---|
-2 |
列の値を切り捨ててホスト変数に割り当てましたが、数値が大きすぎるため、元の長さのまま標識変数に割り当てられませんでした。 |
-1 |
この列の値はNULLです。したがって、このホスト変数の値は予測不能です。 |
0 |
列の値がそのままこのホスト変数に割り当てられました。 |
> 0 |
列の値を切り捨ててホスト変数に割り当てました。列の元の長さ(マルチバイト・グローバリゼーション・サポートのホスト変数では、バイト数ではなく文字数で表される)を標識変数に割り当て、SQLCA内のSQLCODEを0 (ゼロ)に設定しました。 |
標識変数は、2バイトの整数として宣言する必要があります。また、SQL文中では、標識変数の前にコロンを付けてホスト変数の直後に置く必要があります(キーワードINDICATORを使用しない場合)。
5.2.3 NULL値の挿入
標識変数を使用して、NULLを挿入できます。挿入の前に、次に示すように、NULLにする列に対応する標識変数をそれぞれ-1に設定します。
MOVE -1 TO IND-COMM. EXEC SQL INSERT INTO EMP (EMPNO, COMM) VALUES (:EMP-NUMBER, :COMMISSION:IND-COMM) END-EXEC.
標識変数IND-COMMにより、COMM列にNULLを入れるように指定されます。
EXEC SQL INSERT INTO EMP (EMPNO, COMM) VALUES (:EMP-NUMBER, NULL) END-EXEC.
しかし、この方法は柔軟性がありません。
一般的には、次の例に示すように条件的にNULLを挿入します。
DISPLAY 'Enter employee number or 0 if not available: ' WITH NO ADVANCING. ACCEPT EMP-NUMBER. IF EMP-NUMBER = 0 MOVE -1 TO IND-EMPNUM ELSE MOVE 0 TO IND-EMPNUM END-IF. EXEC SQL INSERT INTO EMP (EMPNO, SAL) VALUES (:EMP-NUMBER:IND-EMPNUM, :SALARY) END-EXEC.
5.2.5 NULLのフェッチ
プリコンパイラ・オプションUNSAFE_NULL=YESと設定されている場合は、次の例に示すように、標識変数を持たないホスト変数に対してNULLを選択またはフェッチできます。
* -- assume that commission is NULL EXEC SQL SELECT ENAME, SAL, COMM INTO :EMP-NAME, :SALARY, :COMMISSION FROM EMP WHERE EMPNO = :EMP-NUMBER END-EXEC.
SQLCA内のSQLCODEが0 (ゼロ)に設定されます。これは、Oracleがエラーまたは例外を検出せずにその文を実行したことを示します。
標識変数を使用しないと、NULLが戻されたかどうか知ることができません。ホスト変数の値は未定義です。標識変数を使用しない場合は、プリコンパイラ・オプションUNSAFE_NULLをYESに設定してください。したがって、既存のプログラムをアップグレードするときにのみUNSAFE_NULL=YESに設定し、新規プログラムに対しては常に標識変数を使用することをお薦めします。
ただしUNSAFE_NULL=NOの場合は、標識変数を持たないホスト変数に対してNULLを選択またはフェッチすると、エラー・メッセージが発行されます。
関連項目
5.2.6 NULLのテスト
次の例のようにWHERE句で標識変数を使用して、NULLをテストできます。
EXEC SQL SELECT ENAME, SAL INTO :EMP-NAME, :SALARY FROM EMP WHERE :COMMISSION:IND-COMM IS NULL ...
しかし、関係演算子を使用してNULLとNULL、またはNULLと他の値を比較することはできません。たとえば、COMM列に1つ以上のNULLが含まれる場合、次のSELECT文ではエラーが出力されます。
EXEC SQL SELECT ENAME, SAL INTO :EMP-NAME, :SALARY FROM EMP WHERE COMM = :COMMISSION:IND-COMM END-EXEC.
次の例は、値のうちのいくつかがNULLである可能性がある場合の、値の等価性を比較する方法を示します。
EXEC SQL SELECT ENAME, SAL INTO :EMP_NAME, :SALARY FROM EMP WHERE (COMM = :COMMISSION) OR ((COMM IS NULL) AND (:COMMISSION:IND-COMM IS NULL)) END-EXEC.
5.2.7 切り捨てられた値のフェッチ
値がホスト変数にフェッチされる時に切り捨てられた場合、エラーは発生しません。いずれの場合もWARNINGが発生します(「警告フラグ」を参照)。標識変数が文字列に使用されている場合、値が切り捨てられたとき、標識変数はデータベース内の値の長さに設定されます。数値が切り捨てられる場合、警告は出ないことに注意してください。
5.3 基本的なSQL文
実行SQL文を使用すると、Oracleデータの問合せ、操作および制御ができます。さらに、表、ビューおよび索引などのOracleオブジェクトの作成、定義およびメンテナンスができます。この章では、データベース表のデータを操作する文(DMLと呼ばれることもある)およびカーソル制御文に重点を置いて説明します。
次のSQL文はOracleデータの問合せおよび操作に使用します。
SQL文 | 説明 |
---|---|
SELECT |
1つ以上の表から行を戻します。 |
INSERT |
表に新しい行を追加します。 |
UPDATE |
表内の行を変更します。 |
DELETE |
表から行を削除します。 |
INSERT、UPDATEまたはDELETEなどのDML文を実行する場合は、更新された行数と処理結果を知る必要があります。これは、SQLCAを調べればわかります。(SQL文を実行すると、SQLCA変数が設定されます。)次の2通りの方法で調べることができます。
-
WHENEVER文による暗黙的なチェック
-
SQLCA変数の明示的なチェック
MODE={ANSI | ANSI14}のときは、状態変数SQLSTATEまたはSQLCODEをチェックすることもできます。詳細は、「ANSI SQLSTATE変数」を参照してください。
ただし、SELECT文(問合せ)を実行している場合は、戻されたデータ行の処理もする必要があります。問合せは次のように分類されます。
-
行を戻さない問合せ(有無のみを調べる)
-
1行のみ戻す問合せ
-
複数行を戻す問合せ
複数行を戻す問合せには、明示的に宣言されたカーソルまたはカーソル変数が必要です。明示カーソルの定義および制御は、次の埋込みSQL文で行います。
SQL文 | 説明 |
---|---|
DECLARE |
カーソルに名前を付け、問合せに関連付けます。 |
OPEN |
問合せを実行してアクティブ・セットを決定します。 |
FETCH |
カーソルを移動して、アクティブ・セット内の各行を1つずつ取り出します。 |
CLOSE |
カーソルを使用禁止にします(アクティブ・セットは未定義)。 |
次の項では、最初にINSERT、UPDATE、DELETEおよび単一行のSELECT文を記述する方法を説明します。次に、複数行のSELECT文の使用方法を説明します。
関連項目:
Oracle Database SQL言語リファレンス(各文およびその句の詳細)5.3.1 行の選択
データベースへの問合せは日常的なSQL処理です。問合せを発行するには、SELECT文を使用します。次の例では、EMP表を問い合せています。
EXEC SQL SELECT ENAME, JOB, SAL + 2000 INTO :emp_name, :JOB-TITLE, :SALARY FROM EMP WHERE EMPNO = :EMP-NUMBER END-EXEC.
キーワードSELECTの後の列名と式により、選択リストが作成されます。例の選択リストには、3つの項目が含まれています。WHERE句(および存在する場合はそれに続く句)で指定された条件のもと、OracleではINTO句のホスト変数に列値を戻します。選択リスト内の項目数は、INTO句内のホスト変数と同数であり、すべての戻り値を格納する場所があります。
最も簡単な例として、問合せで1行のみ戻される場合の形式は前述の例のようになります(EMPNOは一意のキーです)。これに対し、問合せで複数行が戻される可能性がある場合は、カーソルを使用して行をフェッチするか、行を選択してホスト配列に入れる必要があります。
1行のみ戻すように作成した問合せで、実際には複数の行が戻される可能性がある場合、エラーになるかどうかはオプションSELECT_ERRORの指定によって決まります。SELECT_ERROR=YES (デフォルト)の場合は、複数行が戻されるとOracleはエラー・メッセージを発行します。
SELECT_ERROR=NOの場合は、1行のみ戻され、エラーにはなりません。
5.3.2 行の挿入
INSERT文を使用すると、表またはビューに行を追加できます。次の例では、EMP表に1行追加します。
EXEC SQL INSERT INTO EMP (EMPNO, ENAME, SAL, DEPTNO) VALUES (:EMP_NUMBER, :EMP-NAME, :SALARY, :DEPT-NUMBER) END-EXEC.
列リスト内に指定する各列は、INTO句で指定した表に含まれている必要があります。VALUES句には、挿入する行の値を指定します。指定する値は、定数、ホスト変数、SQL式または疑似列(USER、SYSDATEなど)のどの値でもかまいません。
VALUES句内の値の数は、列リスト内の名前の数と等しくする必要があります。CREATE TABLEで定義された順序と同じ順序で表の各列の値がVALUES句に含まれている場合は列リストを省略できますが、表の定義は変更されることがあるため、この方法はお薦めできません。
5.3.3 DML RETURNING句
INSERT、UPDATEおよびDELETE文では、オプションでDML RETURNING句を設定し、標識変数ivを付けて列値の式exprをホスト変数hvに戻すことができます。RETURNING句の構文は次のとおりです。
{RETURNING | RETURN} {expr [,expr]} INTO {:hv [[INDICATOR]:iv] [, :hv [[INDICATOR]:iv]]}
式の個数は、ホスト変数の個数と等しくする必要があります。この句を使用すると、INSERTまたはUPDATEの後、およびアプリケーションに対して情報を記録する必要がある場合のDELETEの前に、行を選択する必要がなくなります。DML returning clause
によって、ネットワークの非効率的なラウンドトリップ、余分な処理およびサーバーの使用メモリーを低減できます。たとえば、1つのトリガーでデフォルト値または主キー値を挿入できます。
RETURNING句は、副問合せでは使用できません。VALUES句の後でのみ使用できます。
たとえば、前のINSERTの例の最後に次の句を入れることができます。
RETURNING EMPNO, ENAME, DEPTNO INTO :NEW-EMP-NUMBER, :NEW-EMP-NAME, :DEPT
5.3.4 副問合せの使用方法
副問合せはネストされたSELECT文です。副問合せを使用すると、複数部分の検索を処理できます。副問合せは、次の処理に使用できます。
-
SELECT、UPDATEおよびDELETE文のWHERE、HAVINGおよびSTART WITH句内の比較のための値を指定します。
-
CREATE TABLEまたはINSERT文によって挿入する行の集合を定義します。
-
UPDATE文のSET句に対して値を定義します。
たとえば、ある表から別の表に複数の行をコピーする場合は、次の例に示すように、INSERT文のVALUES句を副問合せに置き換えます。
EXEC SQL INSERT INTO EMP2 (EMPNO, ENAME, SAL, DEPTNO) SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE JOB = :JOB-TITLE END-EXEC.
INSERT文が中間結果を得るためにどのように副問合せを使用しているのか注意してください。
5.3.5 行の更新
UPDATE文を使用すると、表またはビュー内の指定した列の値を変更できます。次の例では、EMP表内のSAL列およびCOMM列を更新します。
EXEC SQL UPDATE EMP SET SAL = :SALARY, COMM = :COMMISSION WHERE EMPNO = :EMP-NUMBER END-EXEC.
オプションのWHERE句を使用して、行を更新する条件を指定できます。WHERE句の使用方法 を参照してください。
SET句には、値を指定する必要のある1つ以上の列の名前の並びを指定します。次の例に示すように、副問合せを使用すると値を指定できます。
EXEC SQL UPDATE EMP SET SAL = (SELECT AVG(SAL)*1.1 FROM EMP WHERE DEPTNO = 20) WHERE EMPNO = :EMP-NUMBER END-EXEC.
5.4 カーソル
Oracleでは、SQL文を処理するためにプライベートSQL領域と呼ばれる作業領域がオープンされます。このプライベートSQL領域にはSQL文の実行に必要な情報が格納されます。カーソルと呼ばれる識別子を使用すると、SQL文に名前を付け、そのプライベートSQL領域に保存されている情報にアクセスし、その処理をある程度まで制御できます。
静的SQL文には、明示的および暗黙的という2種類のカーソルがあります。Oracleでは、INTO文を使用するSELECT文を含め、すべてのデータ定義文およびDML文についてカーソルが1つ暗黙的に宣言されます。
取得された一連の行は結果セットと呼ばれ、そのサイズは問合せの検索条件と何行一致するかによって異なります。現在処理している行(カレント行と呼ばれる)を識別するには、明示カーソルを使用します。
問合せで複数行を戻す場合、明示的にカーソルを定義して次の処理を行うことができます。
-
問合せによって戻された最初の行以後の処理
-
現在どの行が処理されているかの追跡および記録
カーソルは、問合せによって戻された行の集合内におけるカレント行を示します。これによって、プログラムは一度に1行ずつ処理できます。次の文を使用してカーソルを定義および操作します。
-
DECLARE
-
OPEN
-
FETCH
-
CLOSE
最初にDECLARE文(正確にはディレクティブ)を使用して、カーソルに名称を付け、問合せに関連付けます。
OPEN文によって問合せが実行され、この問合せの検索条件を満たす行がすべて判別されます。これらの行は、カーソルのアクティブ・セットと呼ばれる集合を形成します。カーソルをオープンした後、対応する問合せによって戻された行を取り出すことができます。
アクティブ・セットの行は1行ずつ取り出されます(ホスト配列を使用していない場合)。FETCH文を使用してアクティブ・セット内のカレント行を取り出します。FETCHは、すべての行が取り出されるまで繰返し実行できます。
アクティブ・セットからの行のフェッチが終了した後、CLOSE文によってカーソルを使用禁止にします(アクティブ・セットは未定義になります)。
5.4.1 カーソルの宣言
次の例に示すように、DECLARE文でカーソルに名称を与えることでカーソルを定義できます。
EXEC SQL DECLARE EMPCURSOR CURSOR FOR SELECT ENAME, EMPNO, SAL FROM EMP WHERE DEPTNO = :DEPT_NUMBER END-EXEC.
カーソル名は、ホスト変数やプログラム変数ではなく、プリコンパイラが使用する識別子であるため、COBOL文では定義しないでください。したがって、あるプリコンパイル単位から別のプリコンパイル・ユニットにカーソル名を渡すことはできません。カーソル名にハイフンは使用できません。長さは任意ですが、重要な意味があるのは先頭の31文字までです。ANSI互換性を維持するため、カーソル名は18文字までにしてください。
コマンドラインまたは構成ファイルでプリコンパイラ・オプションCLOSE_ON_COMMITが使用できます。CLOSE_ON_COMMIT=YESに設定すると、WITH HOLD句なしで宣言されたカーソルはすべてCOMMITまたはROLLBACKの後でクローズされます。
CLOSE_ON_COMMITより高いレベルでMODEが指定されていると、MODEが優先されます。デフォルトはMODE=ORACLEおよびCLOSE_ON_COMMIT=NOです。MODE=ANSIと指定した場合は、WITH HOLD句を使用していないカーソルはCOMMIT時にクローズされます。カーソルのクローズおよび再オープンの回数が多くなるため、アプリケーションの動作は遅くなります。MODE=ANSIのときは、CLOSE_ON_COMMIT=NOと設定するとパフォーマンスが向上します。MODEなどのマクロ・オプションがCLOSE_ON_COMMITなどのマイクロ・オプションに与える影響は、オプション値の優先順位を参照してください。
カーソルに関連付けられたSELECT文にINTO句を含めることはできません。INTO句および出力ホスト変数のリストはFETCH文の一部として指定します。
DECLARE文は宣言部なので、そのカーソルを参照する他のすべてのSQL文よりも物理的に(論理的にというだけでなく)前にあることが必要です。つまり、カーソルの前方参照は許可されていません。次の例では、OPEN文の位置が誤っています。
EXEC SQL OPEN EMPCURSOR END-EXEC. * -- MISPLACED OPEN STATEMENT EXEC SQL DECLARE EMPCURSOR CURSOR FOR SELECT ENAME, EMPNO, SAL FROM EMP WHERE ENAME = :EMP-NAME END-EXEC.
カーソル制御文(DECLARE、OPEN、FETCH、CLOSE)はすべて同一のプリコンパイル・ユニット内で指定する必要があります。たとえば、ソース・ファイルA.PCOではカーソルを宣言できませんが、ソース・ファイルB.PCOではカーソルをオープンするという処理ができます。
ホスト・プログラムでは、必要な数のカーソルを宣言できます。ただし、指定されたファイル内ではそれぞれのDECLARE文は一意であることが必要です。つまり、カーソルのスコープはファイル内でグローバルなので、1つのプリコンパイル・ユニットの中では、ブロックやプロシージャが異なる場合でも同じ名前のカーソルを2つ宣言することはできません。
MODE=ANSIまたはCLOSE_ON_COMMIT=YESを使用する場合は、DECLAREセクションにWITH HOLD句を使用して、2つのオプションで定義される動作をオーバーライドできます。これらのオプションを設定すると、COMMITが発行されたときにすべてのカーソルがクローズされます。この場合、処理を続行するのにカーソルを再びオープンする必要があるため、オーバーヘッドが生じてパフォーマンスが低下します。WITH HOLD句を適切に使用して処理を高速化するには、プリコンパイラがANSI規格に適合しているプログラムであることが必要です。
5.4.2 カーソルのオープン
OPEN文を使用して、問合せを実行し、アクティブ・セットを決定します。次の例では、EMPCURSORの名前のカーソルがオープンされます。
EXEC SQL OPEN EMPCURSOR END-EXEC.
OPENによって、カーソルはアクティブ・セットの最初の行の直前に位置付けられます。ただし、この時点では実際に取り出される行はありません。行の取出しはFETCH文によって行われます。
カーソルをオープンすると、問合せの入力ホスト変数はカーソルを再オープンするまで再検査されません。つまり、アクティブ・セットは変更されません。アクティブ・セットを変更するには、カーソルを再オープンします。
OPENによって行われる作業量は、HOLD_CURSOR、RELEASE_CURSORおよびMAXOPENCURSORSの3つのプリコンパイラ・オプションの値によって決まります。
5.4.3 カーソルからのフェッチ
FETCH文を使用すると、アクティブ・セットから行を取り出し、結果を格納する出力ホスト変数を指定できます。カーソルに関連付けられたSELECT文にはINTO句を組み込めないことを思い出してください。INTO句および出力ホスト変数のリストはFETCH文の一部として指定します。次の例では、フェッチした行を3つのホスト変数に格納します。
EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME, :EMP-NUMBER, :SALARY END-EXEC.
カーソルは、あらかじめ宣言し、オープンしておく必要があります。最初にFETCH文を実行すると、アクティブ・セットの最初の行より前にあるカーソルが最初の行に移動します。この行がカレント行になります。その後FETCHを実行するたびに、カレント行を変更しながら、カーソルをアクティブ・セットの次の行に進めます。カーソルはアクティブ・セット内を順方向にしか進みません。すでにフェッチした行に戻るには、カーソルを再オープンし、アクティブ・セットの最初の行からやり直す必要があります。
アクティブ・セットを変更する場合は、カーソルに対応する問合せの入力ホスト変数に新しい値を割り当て、カーソルを再オープンしてください。MODE=ANSIに設定されている場合は、再オープンする前にカーソルをクローズする必要があります。
次の例に示すように、異なる出力ホスト変数セットを使用して同じカーソルからフェッチできます。しかし、各FETCH文のINTO句内の対応するホスト変数は、同じデータ型であることが必要です。
EXEC SQL DECLARE EMPCURSOR CURSOR FOR SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 20 END-EXEC. ... EXEC SQL OPEN EMPCURSOR END-EXEC. EXEC SQL WHENEVER NOT FOUND DO ... LOOP. EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME1, :SAL1 END-EXEC EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME2, :SAL2 END-EXEC EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME3, :SAL3 END-EXEC ... GO TO LOOP. ... END-PERFORM.
アクティブ・セットが空であるか、行がなくなると、FETCHは「データが見つかりません」というOracle警告コードをSQLCAのSQLCODEに戻します(MODE=ANSIに設定されている場合は、オプションのSQLSTATE変数も設定されます)。出力ホスト変数のステータスは不確定です。(通常のプログラムでは、WHENEVER NOT FOUND文でこのエラーが検出されます。)カーソルを再利用するには、再オープンする必要があります。
5.4.4 カーソルのクローズ
アクティブ・セットからの行のフェッチ終了後、カーソルをクローズし、そのカーソルのオープンによって獲得していたリソース(記憶域など)を解放します。カーソルがクローズされると、解析ロックが解放されます。どのリソースが解放されるかは、オプションHOLD_CURSORおよびRELEASE_CURSORの指定によって異なります。次の例では、EMPCURSORの名前のカーソルをクローズします。
EXEC SQL CLOSE EMPCURSOR END-EXEC.
クローズしたカーソルのアクティブ・セットは未定義になるため、クローズしたカーソルからフェッチすることはできません。必要であれば、(たとえば、入力ホスト変数に新しい値を指定して)カーソルを再オープンできます。
CLOSE_ON_COMMIT=NO (MODE=ORACLEの場合のデフォルト)の場合、COMMITまたはROLLBACKを発行しても、クローズされるのはFOR UPDATE句を使用して宣言されたカーソルまたはCURRENT OF句で参照されるカーソルのみです。その他のカーソルはCOMMITまたはROLLBACK文による影響を受けず、オープンされている場合はオープンされたままです。ただし、CLOSE_ON_COMMIT=YES (MODE=ANSIの場合のデフォルト)のときにCOMMITまたはROLLBACKを発行すると、すべてのカーソルがクローズします。
関連項目
5.4.5 CURRENT OF句の使用方法
DELETE文またはUPDATE文でCURRENT OF cursor_name句を使用すると、指定したカーソルから最後にフェッチした行を参照できます。カーソルをオープンし、行に位置付けておく必要があります。フェッチが1度も行われていない場合や、そのカーソルがオープンされていない場合には、CURRENT OF句を使用するとエラーが発生し、1行も処理されません。
UPDATE文またはDELETE文のCURRENT OF句で参照するカーソルを宣言するときに、FOR UPDATE OF句を任意で指定できます。CURRENT OF句は、必要に応じてFOR UPDATE句を追加するようにプリコンパイラに指示します。
次の例では、CURRENT OF句を使用して、EMPCURSORの名前のカーソルから最後にフェッチした行を参照します。
EXEC SQL DECLARE EMPCURSOR CURSOR FOR SELECT ENAME, SAL FROM EMP WHERE JOB = 'CLERK' END-EXEC. ... EXEC SQL OPEN EMPCURSOR END-EXEC. EXEC SQL WHENEVER NOT FOUND DO ... LOOP. EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME, :SALARY END-EXEC. ... EXEC SQL UPDATE EMP SET SAL = :NEW-SALARY WHERE CURRENT OF EMPCURSOR END-EXEC. GO TO LOOP.
関連項目
5.4.6 制限事項
明示的なFOR UPDATE OFまたは暗黙的なFOR UPDATEによって行の排他ロックが取得されます。いずれの行も、フェッチされるときではなくオープン時にロックされ、コミットまたはロールバックを行うとロックは解除されます。コミットした後でFOR UPDATEカーソルからフェッチしようとすると、エラーが発行されます。
結合で宣言されたカーソルにCURRENT OF句を使用することはできません。内部的にはCURRENT OFメカニズムはROWID擬似列を使用し、どの表にROWIDが関連するかを指定する方法がないためです。かわりの方法については、「CURRENT OF句の模倣」を参照してください。さらに、動的SQLではCURRENT OF句を使用できません。
5.4.7 一般的な文の順序
次の例は、CURRENT OF句とFOR UPDATE句を使用した一般的なカーソル制御文の順序を示しています。
* -- Define a cursor. EXEC SQL DECLARE EMPCURSOR CURSOR FOR SELECT ENAME, JOB FROM EMP WHERE EMPNO = :EMP-NUMBER FOR UPDATE OF JOB END-EXEC. * -- Open the cursor and identify the active set. EXEC SQL OPEN EMPCURSOR END-EXEC. * -- Exit if the last row was already fetched. EXEC SQL WHENEVER NOT FOUND GOTO NO-MORE END-EXEC. * -- Fetch and process data in a loop. LOOP. EXEC SQL FETCH EMPCURSOR INTO :EMP-NAME, :JOB-TITLE END-EXEC. * -- host-language statements that operate on the fetched data EXEC SQL UPDATE EMP SET JOB = :NEW-JOB-TITLE WHERE CURRENT OF EMPCURSOR END-EXEC. GO TO LOOP. ... MO-MORE. * -- Disable the cursor. EXEC SQL CLOSE EMPCURSOR END-EXEC. EXEC SQL COMMIT WORK RELEASE END-EXEC. STOP RUN.
5.4.8 位置付け更新
次の例は、「ユニバーサルROWID」に定義されているユニバーサルROWIDを使用した位置付け更新を示しています。
... 01 MY-ROWID SQL-ROWID. ... EXEC SQL ALLOCATE :MY-ROWID END-EXEC. EXEC SQL DECLARE C CURSOR FOR SELECT ROWID, ... FROM MYTABLE FOR UPDATE OF ... END-EXEC. EXEC SQL OPEN C END-EXEC. EXEC SQL FETCH C INTO :MY-ROWID ... END-EXEC. * Process retrieved data. ... EXEC SQL UPDATE MYTABLE SET ... WHERE ROWID = :MY-ROWID END-EXEC. ... NO-MORE-DATA: EXEC SQL CLOSE C END-EXEC. EXEC SQL FREE :MY-ROWID END-EXEC. ...
5.4.9 PREFETCHプリコンパイラ・オプション
プリコンパイラ・オプションPREFETCHを使用すると、行をプリフェッチすることによって問合せの効率を上げることができます。これにより、必要なサーバーのラウンドトリップ回数と必要なメモリーが減少します。構成ファイルまたはコマンドラインのPREFETCHオプション値で設定した行数は、標準の優先順位規則に従って、明示カーソルを含むすべての問合せに使用されます。
インラインで使用する場合は、次に示すカーソル文の前にPREFETCHオプションを指定する必要があります。
-
EXEC SQL OPEN cursor
-
EXEC SQL OPEN cursor USING host_var_list
-
EXEC SQL OPEN cursor USING DESCRIPTOR desc_name
OPENを実行すると、問合せの実行時にプリフェッチする行数がPREFETCHの値によって指定されます。0 (プリフェッチなし)から9999までの値を設定できます。デフォルト値は1です。
注意:
PREFETCHプリコンパイラ・オプションは、単一行フェッチのパフォーマンスを向上させるためのものです。配列フェッチを実行する場合、PREFETCHの値は割り当てた値に関係なく無効になります。
5.5 スクロール可能カーソル
スクロール可能カーソルは、SQL文が実行され、実行中に処理された情報が格納される作業領域です。
カーソルが実行されると、結果セットと呼ばれる一連の行に問合せ結果が入れられます。結果セットは、順番にフェッチすることも、順不同でフェッチすることもできます。順不同の結果セットをスクロール可能カーソルと呼びます。
スクロール可能カーソルを使用すると、ユーザーは前から、後ろからまたはランダムな方法でデータベース結果セットの行にアクセスできます。これにより、プログラムは結果セットの任意の行をフェッチできます。
5.5.1 スクロール可能カーソルの使用方法
次の文を使用して、スクロール可能カーソルを定義および操作します。
5.5.1.1 DECLARE SCROLL CURSOR
DECLARE <cursor name> SCROLL CURSOR文を使用して、スクロール可能カーソルに名前を付け、問合せに対応付けます。
5.5.1.3 FETCH
FETCH文を使用すると、必要な行をランダムな方法でフェッチできます。アプリケーションでは、行を上方向へまたは下方向へフェッチしたり、最初または最後の行を直接フェッチしたり、または任意の1行をランダムにフェッチできます。
FETCH文には次のオプションがあります。
-
FETCH FIRST
結果セットの最初の行をフェッチします。
-
FETCH PRIOR
カレント行の直前の行をフェッチします。
-
FETCH NEXT
現在位置の次の行をフェッチします。これは、スクロール不可カーソルのFETCHに相当します。
-
FETCH LAST
結果セットの最後の行をフェッチします。
-
FETCH CURRENT
カレント行をフェッチします。
-
FETCH RELATIVE n
カレント行を基準にしてn番目の行をフェッチします。nはオフセットです。
-
FETCH ABSOLUTE n
n番目の行をフェッチします。nは、結果セットの始まりからのオフセットです。
次の例は、結果セットの最後の行をFETCHする方法を示します。
EXEC SQL DECLARE emp_cursor SCROLL CURSOR FOR SELECT ename, sal FROM emp WHERE deptno=20; ... EXEC SQL OPEN emp_cursor; EXEC SQL FETCH LAST emp_cursor INTO :emp_name, :sal; EXEC SQL CLOSE emp_cursor;
5.5.2 CLOSE_ON_COMMITプリコンパイラ・オプション
CLOSE_ON_COMMITマイクロ・プリコンパイラ・オプションを使用すると、マクロ・オプションMODE=ANSIでCOMMITが実行されるときにすべてのカーソルをクローズするかどうかを選択できます。MODE=ANSIのとき、CLOSE_ON_COMMITのデフォルト値はYESです。明示的にCLOSE_ON_COMMIT=NOと設定すると、COMMITが実行されてもカーソルはクローズされず、カーソルを再オープンして解析する必要がなくなるためパフォーマンスが向上します。
5.5.3 PREFETCHプリコンパイラ・オプション
プリコンパイラ・オプションPREFETCHを使用すると、一定の行数をプリフェッチすることによって問合せの効率を上げることができます。これにより、必要なサーバーのラウンドトリップ回数とメモリー使用量全体が減少します。PREFETCHオプションで設定した行数は、標準の優先順位規則に従って、明示カーソルを含むすべての問合せに使用されます。インラインで使用する場合は、次に示すカーソル文の前にPREFETCHオプションを指定する必要があります。
-
EXEC SQL OPEN cursor
-
EXEC SQL OPEN cursor USING host_var_list
-
EXEC SQL OPEN cursor USING DESCRIPTOR desc_name
OPENを実行すると、問合せの実行時にプリフェッチする行数がPREFETCHの値によって指定されます。0 (プリフェッチなし)から65535までの値を設定できます。デフォルト値は1です。
注意:
PREFETCHオプションのデフォルト値は1で、ラウンドトリップごとに1つの行が戻されます。PREFETCHオプションを使用しないように選択する場合は、コマンドラインでPREFETCHオプションを0に設定して、明示的に無効にする必要があります。
LONGまたはLOB列が取り出される場合は、PREFETCHが自動的に無効になります。
注意:
PREFETCHを使用すると、主に単一行フェッチのパフォーマンスが向上します。配列フェッチの使用時には、PREFETCHは無効です。
注意:
PREFETCHオプションは、状況に応じて広範囲に使用する必要があります。特定のFETCH文のパフォーマンスが最適化されるように、適切なプリフェッチ値を選択してください。そのためには、コマンドラインのPREFECTHオプションのかわりにインラインのPREFECTHオプションを使用します。
注意:
FETCH文にホスト変数とともに標識変数を使用するだけで、多数の大型アプリケーションのパフォーマンスを改善できます。
プリコンパイラ・アプリケーションで、単一行フェッチに対するPREFETCHオプションの使用による最大の利点が得られるように、標識変数を使用することをお薦めします。
5.6 B領域の長さの柔軟性
形式がANSIに設定されている場合、Pro*CobolプログラムのB領域の長さは72列に制限されていました。COBOLコンパイラでは、B領域の長さが最大253列までサポートされるようになりました。これにより、プログラマは72列より長い行を柔軟に入力できます。Pro*Cobolでは、Pro*Cobolアプリケーションが次のオプションでプリコンパイルされる場合にB領域の長さが最大253列までサポートされます。
FORMAT=VARIABLE
IRECLEN=300
オプション。
5.7 実行計画の修正
ある環境で開発した複数のモジュールを統合して、別の環境にデプロイするアプリケーション開発環境では、アプリケーションのパフォーマンスが影響を受けます。プリコンパイラ・アプリケーションのパフォーマンスは、データベース環境の変更によって影響を受けることがあります。これらの変更には、オプティマイザ統計の変更、オプティマイザ設定の変更またはメモリー構造のサイズに影響するパラメータの変更が含まれます。
開発環境においてPro*Cobolで使用されるSQLの実行計画を修正するには、プリコンパイル時にOracleのアウトライン機能を使用する必要があります。アウトラインは、SQL文と関連付けられた一連のオプティマイザ・ヒントとして実装されます。SQL文のアウトラインの使用を有効にすると、Oracleでは、格納されたヒントが自動的に考慮され、それらのヒントに従って実行計画を生成しようとします。これにより、モジュールの統合時および異なる環境へのデプロイ時に、パフォーマンスは影響を受けません。
次のSQL文を使用して、Pro*Cobolでアウトラインを作成できます。
-
SELECT
-
DELETE
-
UPDATE
-
INSERT... SELECT
-
CREATE TABLE... AS SELECT
アウトライン・オプションが設定されている場合、プリコンパイルが正常に終了すると、2つのファイル(SQLファイルおよびLOGファイル)が生成されます。コマンドライン・オプションoutline
およびoutlnprefix
は、アウトラインの生成を制御します。
関連項目:
コマンドライン・オプションの詳細は、「プリコンパイラ・オプション」を参照してください
生成される各アウトライン名は一意です。アプリケーションで使用するファイル名が一意であるため、アウトライン名の生成時にこの情報が使用されます。また、カテゴリ名も接頭辞として使用されます。
注意:
アウトライン名の最大長は128バイトです。この制限を超えると、プリコンパイラではエラーが発生します。outlnprefix
オプションを使用すると、アウトライン名の長さを制限できます。
例5-1 アウトラインを含むSQLファイルの生成
次のプログラムのアウトラインがサポートされているすべてのSQL文のアウトラインを含むSQLファイルを生成するには、アウトライン・オプションを使用して、次のプログラムをプリコンパイルする必要があります。
***************************************************************** * outlndemo: * * Outlines will be created for the following SQL operations, * * 1. CREATE ... SELECT * * 2. INSERT ... SELECT * * 3. UPDATE * * 4. DELETE * * 5. SELECT * ***************************************************************** IDENTIFICATION DIVISION. PROGRAM-ID. outlndemo. ENVIRONMENT DIVISION. CONFIGURATION SECTION. DATA DIVISION. WORKING-STORAGE SECTION. * EMBEDDED COBOL (file "OUTNDEMO.PCO") EXEC SQL BEGIN DECLARE SECTION END-EXEC. 01 USERNAME PIC X(10) VARYING. 01 PASSWD PIC X(10) VARYING. 01 ENAME PIC X(10). 01 JOB PIC X(9). 01 SAL PIC X(6). 01 COMM PIC X(6). EXEC SQL END DECLARE SECTION END-EXEC. 01 STRINGFIELDS. 02 STR PIC X(18) VARYING. EXEC SQL INCLUDE SQLCA END-EXEC. PROCEDURE DIVISION. BEGIN-PGM. EXEC SQL WHENEVER SQLERROR DO PERFORM SQL-ERROR END-EXEC. PERFORM LOGON. EXEC SQL INSERT INTO BONUS SELECT ENAME, JOB, SAL, COMM FROM EMP WHERE JOB LIKE 'SALESMAN' END-EXEC. EXEC SQL UPDATE BONUS SET SAL = SAL * 1.1 WHERE SAL < 1500 END-EXEC. EXEC SQL DECLARE C1 CURSOR FOR SELECT ENAME, JOB, SAL, COMM FROM BONUS ORDER BY SAL END-EXEC. EXEC SQL OPEN C1 END-EXEC. DISPLAY "Contents of updated BONUS table". DISPLAY "ENAME JOB SAL COMM". DISPLAY " ". EXEC SQL WHENEVER NOT FOUND GOTO END-FETCH END-EXEC. FETCH-DATA. EXEC SQL FETCH C1 INTO :ENAME, :JOB, :SAL, :COMM END-EXEC. DISPLAY ENAME, JOB, SAL, COMM. GO TO FETCH-DATA. END-FETCH. EXEC SQL CLOSE C1 END-EXEC. EXEC SQL WHENEVER NOT FOUND DO PERFORM SQL-ERROR END-EXEC. EXEC SQL DELETE FROM BONUS END-EXEC. EXEC SQL CREATE TABLE OUTLNDEMO_TAB AS SELECT EMPNO, ENAME, SAL FROM EMP WHERE DEPTNO = 10 END-EXEC. EXEC SQL DROP TABLE OUTLNDEMO_TAB END-EXEC. EXEC SQL ROLLBACK WORK RELEASE END-EXEC. STOP RUN. LOGON. MOVE "scott" TO USERNAME-ARR. MOVE 5 TO USERNAME-LEN. MOVE "tiger" TO PASSWD-ARR. MOVE 5 TO PASSWD-LEN. EXEC SQL CONNECT :USERNAME IDENTIFIED BY :PASSWD END-EXEC. * HANDLES SQL ERROR CONDITIONS SQL-ERROR. EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC. DISPLAY " ". DISPLAY "ORACLE ERROR DETECTED:". DISPLAY " ". DISPLAY SQLERRMC. EXEC SQL ROLLBACK WORK RELEASE END-EXEC. STOP RUN.
5.7.1 SQLファイル
生成されるファイル名の書式は次のとおりです。
<filename>_<filetype>.sql
Pro*Cobolでは、ファイル「abc.pco」の場合、生成されるSQLファイルはabc_pco.sqlになります。
生成されるファイル書式
outlnprefixオプションを使用しない場合は、アウトライン名およびコメントとして、次の一意識別子の書式が使用されます。
<category_name>_<filename>_<filetype>_<sequence no.>
outlnprefixオプションを使用する(outlnprefix=<prefix_name>)場合は、アウトライン名およびコメントとして、次の一意識別子の書式が使用されます。
<prefix_name>_<sequence no.>
outline=yes (デフォルトのカテゴリ)の場合、<category_name>はDEFAULTに、アウトライン名は次のいずれかになります。
DEFAULT_<filename>_<filetype>_<sequence no.>
または
<prefix_name>_<sequence no.>
<sequence no.>
に使用できる値の範囲は、0000から9999です。
生成されたプリコンパイル済ファイルのSQLには、SQLのアウトラインで表示されるように、コメントが追加されます。
5.7.1.1 例
次の例を考えてみます。
例1
abc.pcoには、次の文が含まれています。
EXEC SQL select * from emp where empno=:var END-EXEC. EXEC SQL select * from dept END-EXEC.
outline=mycat1で、outlnprefixを使用しない場合は、次のようになります。
abc_pco.sqlの内容
select * from emp where empno=:b1 /* mycat1_abc_pco_0000 */;
で、カテゴリmycat1のアウトラインmycat1_abc_pco_0000を作成または置換します。
select * from dept /* mycat1_abc_pco_0001 */;
で、カテゴリmycat1のアウトラインmycat1_abc_pco_0001を作成または置換します。
abc.cobの内容
01 SQ0001 GLOBAL. 02 FILLER PIC X(60) VALUE "select * from emp where empno=:b1 - /* mycat1_abc_pco_0000 */ - "".
例2
abc.pcoには、次の文が含まれています。
EXEC SQL select * from emp where empno=:var END-EXEC. EXEC SQL select * from dept END-EXEC.
outline=mycat1で、outlnprefix=myprefixの場合は、次のようになります。
abc_pco.sqlの内容
select * from emp where empno=:b1 /* myprefix_0000 */;
で、カテゴリmycat1のアウトラインmyprefix_0000を作成または置換します。
select * from dept /* myprefix_0001 */;
で、カテゴリmycat1のアウトラインmyprefix_0001を作成または置換します。
abc.cobの内容
01 SQ0001 GLOBAL. 02 FILLER PIC X(60) VALUE "select * from emp where empno=:b1 - /* myprefix_0000 */ - "".
例3
abc.pcoには、次の文が含まれています。
EXEC SQL select * from emp where empno=:var END-EXEC. EXEC SQL select * from dept END-EXEC.
outline=yesで、outlnprefix=myprefixの場合は、次のようになります。
abc_pco.sqlの内容
select * from emp where empno=:b1 /* myprefix_0000 */;
で、アウトラインmyprefix_0000を作成または置換します。
select * from dept /* myprefix_0001 */;
で、アウトラインmyprefix_0001を作成または置換します。
abc.cobの内容
01 SQ0001 GLOBAL. 03 FILLER PIC X(60) VALUE "select * from emp where empno=:b1 - /* myprefix_0000 */ - "".
5.7.2 LOGファイル
生成されるファイル名の書式は次のとおりです。
<filename>_<filetype>.log
Pro*Cobolでは、ファイル「abc.pco」の場合、生成されるLOGファイルはabc_pco.logになります。
次に例を示します。
例1
abc.pcoには、次の文が含まれています。
EXEC SQL select * from emp END-EXEC.
abc_pco.logの内容
CATEGORY <Category_name> Source SQL_0 SELECT * FROM emp OUTLINE NAME abc_pco_0000 OUTLINE SQL_0 Select * from emp /* abc_pco_0000 */
5.8 サンプル・プログラム2: カーソル操作
次のプログラムでは、Oracleにログインし、カーソルを宣言およびオープンします。次に、全営業担当者の名前、給料および歩合給をフェッチして結果を表示し、カーソルをクローズします。
最後の1つのフェッチを除くすべてのフェッチで1行ずつ戻され、フェッチ中にエラーが検出されなければ、成功のステータス・コードが戻されます。最後のフェッチは失敗し、「データが見つかりません」というOracle警告コードがSQLCAのSQLCODEに戻されます。実際にフェッチされた行の累積数は、SQLCAのSQLERRD(3)に示されています。
***************************************************************** * Sample Program 2: Cursor Operations * * * * This program logs on to ORACLE, declares and opens a cursor, * * fetches the names, salaries, and commissions of all * * salespeople, displays the results, then closes the cursor. * ***************************************************************** IDENTIFICATION DIVISION. PROGRAM-ID. CURSOR-OPS. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. EXEC SQL BEGIN DECLARE SECTION END-EXEC. 01 USERNAME PIC X(10) VARYING. 01 PASSWD PIC X(10) VARYING. 01 EMP-REC-VARS. 05 EMP-NAME PIC X(10) VARYING. 05 SALARY PIC S9(6)V99 DISPLAY SIGN LEADING SEPARATE. 05 COMMISSION PIC S9(6)V99 DISPLAY SIGN LEADING SEPARATE. EXEC SQL VAR SALARY IS DISPLAY(8,2) END-EXEC. EXEC SQL VAR COMMISSION IS DISPLAY(8,2) END-EXEC. EXEC SQL END DECLARE SECTION END-EXEC. EXEC SQL INCLUDE SQLCA END-EXEC. 01 DISPLAY-VARIABLES. 05 D-EMP-NAME PIC X(10). 05 D-SALARY PIC Z(4)9.99. 05 D-COMMISSION PIC Z(4)9.99. PROCEDURE DIVISION. BEGIN-PGM. EXEC SQL WHENEVER SQLERROR DO PERFORM SQL-ERROR END-EXEC. PERFORM LOGON. EXEC SQL DECLARE SALESPEOPLE CURSOR FOR SELECT ENAME, SAL, COMM FROM EMP WHERE JOB LIKE 'SALES%' END-EXEC. EXEC SQL OPEN SALESPEOPLE END-EXEC. DISPLAY " ". DISPLAY "SALESPERSON SALARY COMMISSION". DISPLAY "----------- ---------- ----------". FETCH-LOOP. EXEC SQL WHENEVER NOT FOUND DO PERFORM SIGN-OFF END-EXEC. EXEC SQL FETCH SALESPEOPLE INTO :EMP-NAME, :SALARY, :COMMISSION END-EXEC. MOVE EMP-NAME-ARR TO D-EMP-NAME. MOVE SALARY TO D-SALARY. MOVE COMMISSION TO D-COMMISSION. DISPLAY D-EMP-NAME, " ", D-SALARY, " ", D-COMMISSION. MOVE SPACES TO EMP-NAME-ARR. GO TO FETCH-LOOP. LOGON. MOVE "SCOTT" TO USERNAME-ARR. MOVE 5 TO USERNAME-LEN. MOVE "TIGER" TO PASSWD-ARR. MOVE 5 TO PASSWD-LEN. EXEC SQL CONNECT :USERNAME IDENTIFIED BY :PASSWD END-EXEC. DISPLAY " ". DISPLAY "CONNECTED TO ORACLE AS USER: ", USERNAME-ARR. SIGN-OFF. EXEC SQL CLOSE SALESPEOPLE END-EXEC. DISPLAY " ". DISPLAY "HAVE A GOOD DAY.". DISPLAY " ". EXEC SQL COMMIT WORK RELEASE END-EXEC. STOP RUN. SQL-ERROR. EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC. DISPLAY " ". DISPLAY "ORACLE ERROR DETECTED:". DISPLAY " ". DISPLAY SQLERRMC. EXEC SQL ROLLBACK WORK RELEASE END-EXEC. STOP RUN.