ヘッダーをスキップ
Pro*COBOLプログラマーズ・ガイド
11g リリース1(11.1)
E05690-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

10 ANSI動的SQL

この章では、新しい方法4アプリケーションに使用するANSI動的SQL(SQL92動的SQLとも呼ばれます)のOracleでの実装を説明します。実装は、第11章「Oracle動的SQL: 方法4」で説明する従来のOracle動的SQL方法4に拡張機能を加えたものです。Oracle方法4ではカーソル変数、グループ項目の表、DML RETURNING句およびLOBはサポートされませんが、ANSI方法4ではOracleの型がすべてサポートされます。

従来のOracle動的SQL方法4では記述子はユーザーのPro*COBOLプログラムで定義されますが、ANSI動的SQLでは記述子はOracle内部で管理されます。どちらの場合でも、方法4では、Pro*COBOLプログラムが様々な数のホスト変数を含むSQL文の受け入れまたは作成を行います。

この章の構成は、次のとおりです。

ANSI動的SQLの基礎

次のSQL文について考えます。

SELECT ename, empno FROM emp WHERE deptno = :deptno_data

ANSI動的SQLを使用する手順は、次のとおりです。

プリコンパイラのオプション

通常、ANSI動的SQLを使用する場合はプリコンパイラのANSI規格に従ってコードを記述するため、マクロ・コマンドライン・オプションMODE=ANSIを使用します。MODE=ANSIを使用せずにこの方法を使用する場合は、マイクロ・コマンドライン・オプションDYNAMIC=ANSIによって機能を制御します。

マイクロ・プリコンパイラ・オプションDYNAMICをANSIに設定するか、マクロ・オプションMODEをANSIに設定します。これによって、DYNAMICのデフォルト値がANSIに設定されます。DYNAMICのもう1つの設定はORACLEです。マイクロ・オプションの詳細は、「マクロ・オプションおよびマイクロ・オプション」および「DYNAMIC」を参照してください。

ANSI型コードを使用するには、TYPE_CODEプリコンパイラ・マイクロ・オプションをANSIに設定するか、MODEマクロ・オプションをANSIに設定します。これによって、TYPE_CODEのデフォルト設定がANSIになります。TYPE_CODEをANSIに設定するには、DYNAMICもANSIに設定する必要があります。

ANSI SQL型のリストは、表10-1を参照してください。データベース・プラットフォーム間での移植性があり、可能なかぎりANSIに準拠したアプリケーションを作成する場合は、プリコンパイラ・オプションTYPE_CODEをANSIに設定してANSI型を使用してください。

詳細は、「MODE」および「TYPE_CODE」を参照してください。

ANSI SQL文の概要

動的SQL文では、記述子領域は使用する前に割り当てます。

ALLOCATE DESCRIPTOR文の構文は次のとおりです。

     EXEC SQL ALLOCATE DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}
        [WITH MAX {:occurrences | numeric_literal}]
     END-EXEC.

グローバル記述子は、プログラム内の任意のモジュールで使用できます。ローカル記述子は、その記述子を割り当てたファイル内でのみアクセス可能です。デフォルトはローカルです。

記述子名desc_namは、ホスト変数です。かわりに文字列リテラルを使用することもできます。

occurrencesは、記述子に格納できるバインド変数または列の最大数です。デフォルトは100です。

記述子が必要なくなった場合は、割当てを解除してメモリーを節約します。データベース接続がなくなると、割当ての解除が自動的に行われます。

割当て解除文は次のとおりです。

     EXEC SQL DEALLOCATE DESCRIPTOR [GLOBAL | LOCAL]
        {:desc_nam | string_literal}
     END-EXEC.

準備済のSQL文に関する情報を取得するには、DESCRIBE文を使用します。DESCRIBE INPUTでは、準備済の動的文のバインド変数が記述されます。DESCRIBE OUTPUT(デフォルト)では、出力列の番号、型および長さが記述されます。単純化した構文は次のとおりです。

     EXEC SQL DESCRIBE [INPUT | OUTPUT] sql_statement
        USING [SQL] DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}
     END-EXEC.

SQL文に入力値および出力値がある場合は、入力値および出力値に1つずつ記述子を割り当てる必要があります。入力値がない次の例のような場合があります。

SELECT ename, empno FROM emp

この場合、入力記述子は必要ありません。

SELECT文のINSERTS、UPDATES、DELETESおよびWHERE句の入力値を指定するには、SET DESCRIPTOR文を使用します。入力記述子にDESCRIBEを行っていないときは、SET DESCRIPTORを使用して(COUNTに格納する)入力バインド変数の数を設定します。

     EXEC SQL SET DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal} 
        COUNT = {:kount | numeric_literal}
     END-EXEC.

kountには、ホスト変数または数値リテラル(5など)を指定できます。SET DESCRIPTOR文を各ホスト変数に使用して、少なくとも変数のデータ値は割り当てる必要があります。

     EXEC SQL SET DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}
        VALUE item_number DATA = :hv3
     END-EXEC.

また、次のように入力ホスト変数の型および長さを設定することもできます。

注意: 型および長さの設定をSET DESCRIPTOR文で明示的に、またはDESCRIBE OUTPUTを実行して暗黙的に行わなかった場合、TYPE_CODE=ORACLEの場合は、ホスト変数自体から導出された型および長さの値がプリコンパイラで使用されます。TYPE_CODE=ANSIの場合は、表10-1「ANSI SQLデータ型」に示す値を使用して型を設定する必要があります。また、ANSIのデフォルトの長さがホスト変数のデフォルトの長さと一致しない場合があるので、長さも設定してください。

     EXEC SQL SET DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}
        VALUE item_number TYPE = :hv1, LENGTH = :hv2, DATA = :hv3
     END-EXEC.

識別子hv1hv2およびhv3を使用していることからもわかるように、ホスト変数によって値を与える必要があります。item_numberは、SQL文での入力変数の位置です。ここには、ホスト変数または整数を指定できます。

TYPE_CODEをANSIに設定した場合は、次の表の型コードからTYPEを選択します。

表10-1 ANSI SQLデータ型

データ型 型コード

CHARACTER

1

CHARACTER VARYING

12

DATE

9

DECIMAL

3

DOUBLE PRECISION

8

FLOAT

6

INTEGER

4

NUMERIC

2

REAL

7

SMALLINT

5


Oracle型コードは、表11-2「Oracleの外部データ型および関連するCOBOLデータ型」を参照してください。ANSIデータ型が表になく、TYPE_CODE = ANSIである場合は、Oracleコードの負の値を使用してください。

DATAは、入力されるホスト変数値です。

インジケータ、精度、位取りなど、その他の入力値を設定することもできます。詳細は、「SET DESCRIPTOR」の使用できる記述子項目名のリストを参照してください。

SET DESCRIPTOR文の数値は、PIC S9(9) COMPまたはPIC S9(4) COMPのいずれかで宣言する必要があります。ただし、インジケータおよび戻される長さの値は、PIC S9(4) COMPとして宣言する必要があります。

次の例に、empnoを取り出すときの値の設定を示します。empnoは動的SQL文の2つ目の出力ホスト変数なので、VALUE=2と設定します。ホスト変数EMPNO-TYPは、3(整数のOracleタイプ)に設定されます。ホスト変数の長さEMPNO-LENは、4に設定されます。これは、ホスト変数のサイズを示します。DATAは、データベース表からの値を受け取るホスト変数EMPNO-DATAと等しくなります。コード・フラグメントを次に示します。

 ...
 01  DYN-STATEMENT PIC X(58)
     VALUE "SELECT ename, empno FROM emp WHERE deptno =:deptno_number".
 01  EMPNO-DATA PIC S9(9) COMP.
 01  EMPNO-TYP  PIC S9(9) COMP   VALUE 3.
 01  EMPNO-LEN  PIC S9(9) COMP   VALUE 4.
 ...
     EXEC SQL SET DESCRIPTOR 'out' VALUE 2  TYPE=:EMPNO-TYP, LENGTH=:EMPNO-LEN,
        DATA=:EMPNO-DATA END-EXEC.

入力値を設定した後で、入力記述子を使用して文を実行またはオープンします。文に出力値がある場合は、FETCHを実行する前に出力値を設定します。DESCRIBE OUTPUTを実行した場合は、ホスト変数の実際の型および長さを再設定する必要がある場合があります。これは、DESCRIBEを実行すると、ホスト変数の外部型および長さとは別の内部型および長さが生成されるためです。

出力記述子をFETCHした後、GET DESCRIPTORを使用して、戻されたデータにアクセスします。単純化した構文を次に示します。詳しい構文は、この章で後述します。

     EXEC SQL GET DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}
        VALUE item_number 
        :hv1 = DATA, :hv2 = INDICATOR, :hv3 = RETURNED_LENGTH
     END-EXEC.

desc_namおよびitem_numberには、リテラルまたはホスト変数を指定できます。記述子名には、リテラル(outなど)を指定できます。項目番号には、数値リテラル(2など)を指定できます。

hv1、hv2およびhv3は、それぞれホスト変数です。ここにはホスト変数を指定する必要があり、リテラルは指定できません。例では、戻されるデータを3つのみ示しています。戻されるデータとして取得できる項目は、表10-4「記述子項目名の定義」を参照してください。

数値には、プラットフォーム依存の上限がnであるPIC S9(n) COMPを使用するか、またはPIC S9(9) COMPPIC S9(4) COMPを使用します。ただし、標識変数および戻される長さの変数はPIC S9(4) COMPであることが必要です。

サンプル・コード

次の例に、ANSI動的SQLの使用方法を示します。この例では、SELECT文を実行するための入力記述子inおよび出力記述子outを割り当てます。入力値は、SET DESCRIPTOR文によって設定します。カーソルをオープンし、そこからフェッチを行います。結果の出力値をGET DESCRIPTOR文によって取り出します。

 ...
 01  DYN-STATEMENT PIC X(58)
     VALUE "SELECT ENAME, EMPNO FROM EMP WHERE DEPTNO =:DEPTNO-DAT".
 01  EMPNO-DAT  PIC S9(9) COMP.
 01  EMPNO-TYP  PIC S9(9) COMP   VALUE 3.
 01  EMPNO-LEN  PIC S9(9) COMP   VALUE 4.
 01  DEPTNO-TYP PIC S9(9) COMP   VALUE 3.
 01  DEPTNO-LEN PIC S9(9) COMP   VALUE 4.
 01  DEPTNO-DAT PIC S9(9) COMP   VALUE 10.
 01  ENAME-TYP  PIC S9(9) COMP   VALUE 3.
 01  ENAME-LEN  PIC S9(9) COMP   VALUE 30.
 01  ENAME-DAT  PIC X(30).
 01  SQLCODE PIC S9(9)    COMP   VALUE 0.
 ...
* Place preliminary code, including connection, here
...
     EXEC SQL ALLOCATE DESCRIPTOR 'in' END-EXEC.
     EXEC SQL ALLOCATE DESCRIPTOR 'out' END-EXEC.
     EXEC SQL PREPARE s FROM :DYN-STATEMENT END-EXEC.
     EXEC SQL DESCRIBE INPUT s USING DESCRIPTOR 'in' END-EXEC.
     EXEC SQL SET DESCRIPTOR 'in' VALUE 1 TYPE=:DEPTNO-TYP,
        LENGTH=:DEPTNO-LEN, DATA=:DEPTNO-DAT END-EXEC.
     EXEC SQL DECLARE c CURSOR FOR s END-EXEC.
     EXEC SQL OPEN c USING DESCRIPTOR 'in' END-EXEC.
     EXEC SQL DESCRIBE OUTPUT s USING DESCRIPTOR 'out' END-EXEC.
     EXEC SQL SET DESCRIPTOR 'out' VALUE 1 TYPE=:ENAME-TYP,
        LENGTH=:ENAME-LEN, DATA=:ENAME-DAT END-EXEC.
     EXEC SQL SET DESCRIPTOR 'out' VALUE 2 TYPE=:EMPNO-TYP,
        LENGTH=:EMPNO-LEN, DATA=:EMPNO-DAT END-EXEC.

     EXEC SQL WHENEVER NOT FOUND GOTO BREAK END-EXEC.
 LOOP.
     IF SQLCODE NOT = 0
        GOTO BREAK.
     EXEC SQL FETCH c INTO DESCRIPTOR 'out' END-EXEC.
     EXEC SQL GET DESCRIPTOR 'OUT' VALUE 1 :ENAME-DAT = DATA END-EXEC.
     EXEC SQL GET DESCRIPTOR 'OUT' VALUE 2 :EMPNO-DAT = DATA END-EXEC.
     DISPLAY "ENAME = " WITH NO ADVANCING
     DISPLAY ENAME-DAT  WITH NO ADVANCING
     DISPLAY "EMPNO = " WITH NO ADVANCING
     DISPLAY EMPNO-DAT.
     GOTO LOOP.
 BREAK:
     EXEC SQL CLOSE c END-EXEC.
     EXEC SQL DEALLOCATE DESCRIPTOR 'in' END-EXEC.
     EXEC SQL DEALLOCATE DESCRIPTOR 'out' END-EXEC.

Oracle拡張機能

この項では、次の拡張機能を説明します。

参照セマンティクス

ANSI規格では、値構文が指定されています。パフォーマンス向上のために、Oracleではこの規格を拡張して参照セマンティクスを導入しています。

値構文では、ホスト変数データのコピーを作成します。参照セマンティクスでは、ホスト変数のアドレスを使用し、コピーは行いません。そのため、参照セマンティクスを使用すると、大量データ処理のパフォーマンスが向上します。

フェッチの速度向上には、データ句の前にREFキーワードを使用します。

     EXEC SQL SET DESCRIPTOR 'out' VALUE 1 TYPE=:ENAME-TYP,
        LENGTH=:ENAME-LEN, REF DATA=:ENAME-DAT END-EXEC.
     EXEC SQL DESCRIPTOR 'out' VALUE 2 TYPE=:EMPNO-TYP,
        LENGTH=:EMPNO-LEN, REF DATA=:EMPNO-DAT END-EXEC.

これにより、取り出された結果がホスト変数に渡されます。GET文は必要ありません。FETCHが実行されるたびに、取り出されたデータは、ename_dataおよびempno_dataに直接書き込まれます。

次のコード例に示すように、REFキーワードが使用できるのは、DATA、INDICATORおよびRETURNED_LENGTH項目(フェッチする行によって変わる可能性があります)の前に限られます。

 01   INDI       PIC S9(4) COMP.
 01   RETRN-LEN  PIC S9(9) COMP.
 ...
      EXEC SQL SET DESCRIPTOR 'out' VALUE 1 TYPE=:ENAME-TYP,
         LENGTH=:ENAME-LEN, REF DATA=:ENAME-DAT,
         REF INDICATOR=:INDI, REF RETURNED_LENGTH =:RETRN-LEN END-EXEC.

フェッチするたびに、enameフィールドの実際に取り出された長さがRETRN-LENに送られます。これは、CHARまたはVARCHAR2データの場合に便利です。

ENAME-LENには取り出された長さは渡されません。ENAME-LENは、FETCH文によって変更されません。データの行をフェッチする前に列の最大幅を調べるには、GET文の前にDESCRIBEを使用します。

REFキーワードは、SELECT以外のSQL文の処理速度向上のためにも使用します。参照セマンティクスでは、記述子領域にコピーされた値ではなくホスト変数が使用されることに注意してください。SQL文を実行する時点でのホスト変数データが使用されるのであって、SETの時点でのデータではありません。次に例を示します。

 ...
     MOVE 1 to VAL.
 ...
     EXEC SQL SET DESCRIPTOR 'value' VALUE 1 DATA = :VAL END-EXEC.
     EXEC SQL SET DESCRIPTOR 'reference' VALUE 1 REF DATA = :VAL END-EXEC.
     MOVE 2 to VAL.
* Will use  VAL = 1
     EXEC SQL EXECUTE s USING  DESCRIPTOR 'value' END-EXEC.
*Will use VAL = 2
     EXEC SQL EXECUTE s USING DESCRIPTOR 'reference' END-EXEC.

この処理の違いの詳細は、「SET DESCRIPTOR」を参照してください。

バルク操作での表の使用方法

Oracleでは、SQL92 ANSI動的規格を拡張したバルク操作を提供しています。バルク操作を行うには、処理する入力データ量または行数を指定するために、FOR句で配列サイズを指定します。

FOR句は、ALLOCATE文で最大データ量または最大行数の指定に使用します。最大配列サイズ100を指定するには、次のように記述します。

     EXEC SQL FOR 100 ALLOCATE DESCRIPTOR 'out' END-EXEC.

または

     MOVE 100 TO INT-ARR-SIZE.
     EXEC SQL FOR :INT-ARR-SIZE ALLOCATE DESCRIPTOR 'out' END-EXEC.

次に、記述子にアクセスする文でFOR句を使用します。次に示すように、出力記述子では、ALLOCATE文で指定した配列サイズと等しいか、それよりも小さい配列サイズをFETCH文に割り当てる必要があります。

     EXEC SQL FOR 20 FETCH c1 USING DESCRIPTOR 'out' END-EXEC.

後続の、同じ記述子のDATA、INDICATORまたはRETURNED_LENGTH値を取得するGET文では、FETCH文と同じ配列サイズを指定する必要があります。

 01  VAL-DATA   OCCURS 20 TIMES  PIC S9(9) COMP.
 01  VAL-INDI   OCCURS 20 TIMES  PIC S9(4) COMP.
...
     EXEC SQL FOR 20 GET DESCRIPTOR 'out' VALUE 1 :VAL-DATA = DATA,
       :VAL-INDI = INDICATOR
     END-EXEC.

ただし、LENGTH、TYPE、COUNTなど、行によって変化しない項目を参照するGET文では、FOR句は使用しないでください。

 01  CNT  PIC S9(9) COMP.
 01  LEN  PIC S9(9) COMP.
...
     EXEC SQL GET DESCRIPTOR 'out'   :CNT = COUNT END-EXEC.
     EXEC SQL GET DESCRIPTOR 'out' VALUE 1 :LEN = LENGTH END-EXEC.

これは、参照セマンティクスを使用したSET文でも同じです。FETCHの前にあり、DATA、INDICATORまたはRETURNED_LENGTHに対する参照セマンティクスを使用したSET文には、FETCHと同じ配列サイズを指定する必要があります。

 ...
 01  REF-DATA   OCCURS 20 TIMES  PIC S9(9) COMP.
 01  REF-INDI   OCCURS 20 TIMES  PIC S9(4) COMP.
...
     EXEC SQL FOR 20 SET DESCRIPTOR 'out' VALUE 1 REF DATA = :REF-DATA,
        REF INDICATOR = :REF-INDI END-EXEC.

同様に、行のバッチの挿入など、入力に使用する記述子でも、ALLOCATE文で使用した配列サイズと等しいか、それよりも小さいサイズの配列サイズをEXECUTEまたはOPEN文に使用する必要があります。値および参照セマンティクスのどちらも、DATA、INDICATORまたはRETURNED_LENGTHにアクセスするSET文では、EXECUTE文と同じ配列サイズを使用する必要があります。

FOR句は、DEALLOCATEまたはPREPARE文では使用しません。

次のコード・サンプルに、出力記述子のないバルク操作の例を示します(出力はなく、表empに挿入する入力のみあります)。CNTの値は2です(INSERT文にENAMEおよびEMPNOの2つのホスト変数があることを示します)。データ表ENAME-TABLEには、TomDickおよびHarryの順で3つの文字列が保持されています。彼らの雇用者番号を表EMPNO-TABLEに格納します。インジケータ表ENAME-INDには2つ目の要素に-1の値を設定しているため、DickではなくNULLが挿入されます。

 01  DYN-STATEMENT  PIC X(240) value
         "INSERT INTO EMP(ENAME, EMPNO) VALUES (:ENAME,:EMPNO)".
 01  ARRAY-SIZE PIC S9(9) COMP   VALUE 3.
 01  ENAME-VALUES.
      05 FILLER PIC X(6)   VALUE "Tom   ".
      05 FILLER PIC X(6)   VALUE "Dick  ".
      05 FILLER PIC X(6)   VALUE "Harry ".
 01  ENAME-TABLE REDEFINES ENAME-VALUES.
      05 ENAME  PIC X(6)OCCURS 3 TIMES.
 01  ENAME-IND  PIC S9(4) COMPOCCURS 3 TIMES.
 01  ENAME-LEN  PIC S9(9) COMP   VALUE   6.
 01  ENAME-TYP  PIC S9(9) COMP   VALUE  96.
 01  EMPNO-VALUES.
      05 FILLER PIC S9(9) COMP   VALUE 8001.
      05 FILLER PIC S9(9) COMP   VALUE 8002.
      05 FILLER PIC S9(9) COMP   VALUE 8003.
 01  EMPNO-TABLE REDEFINES EMPNO-VALUES.
      05 EMPNO  PIC S9(9) DISPLAY SIGN LEADING  OCCURS 3 TIMES.
 01  EMPNO-LEN  PIC S9(9) COMP   VALUE   4.
 01  EMPNO-TYP  PIC S9(9) COMP   VALUE   3.
 01  CNT        PIC S9(9) COMP   VALUE   2.
........
     EXEC SQL FOR :ARRAY-SIZE ALLOCATE DESCRIPTOR 'in' END-EXEC.
     EXEC SQL PREPARE S FROM :DYN-STATEMENT  END-EXEC.
     MOVE 0 TO ENAME-IND(1).
     MOVE -1 TO ENAME-IND(2).
     MOVE 0 TO ENAME-IND(3).
     EXEC SQL SET DESCRIPTOR 'in' COUNT = :CNT END-EXEC.
     EXEC SQL SET DESCRIPTOR 'in' VALUE 1
        TYPE = :ENAME-TYP, LENGTH =:ENAME-LEN
     END-EXEC.
     EXEC SQL FOR :ARRAY-SIZE  SET DESCRIPTOR 'in' VALUE 1
        DATA = :ENAME, INDICATOR = :ENAME-IND
     END-EXEC.
     EXEC SQL SET DESCRIPTOR 'in' VALUE 2
        TYPE = :EMPNO-TYP, LENGTH =:EMPNO-LEN
     END-EXEC.
     EXEC SQL FOR :ARRAY-SIZE  SET DESCRIPTOR 'in' VALUE 2
        DATA = :EMPNO
     END-EXEC.
     EXEC SQL FOR :ARRAY-SIZE EXECUTE S
        USING DESCRIPTOR 'in' END-EXEC.
  ...

この例のコードによって、次の値が表に挿入されます。

      EMPNO   ENAME
      8001    Tom
      8002
      8003    Harry

制限および注意の詳細は、「FOR句」を参照してください。

ANSI動的SQLのプリコンパイラ・オプション

マクロ・オプションMODE(「MODE」を参照)では、ANSI互換特性を設定し、いくつかの機能を制御します。MODEの値にはANSIまたはORACLEを設定できます。個々の機能には、MODE設定に優先するマイクロ・オプションがあります。

プリコンパイラ・マイクロ・オプションDYNAMICでは、動的SQLの記述子の動作を指定します。プリコンパイラ・マイクロ・オプションTYPE_CODEでは、ANSIとOracleのどちらのデータ型コードを使用するかを指定します。

マクロ・オプションMODEをANSIに設定すると、マイクロ・オプションDYNAMICは自動的にANSIになります。MODEをORACLEに設定すると、DYNAMICはORACLEになります。

DYNAMICおよびTYPE_CODEはインラインでは使用できません。

次の表に、DYNAMIC設定による様々な機能への影響を示します。

表10-2 DYNAMICオプションの設定

機能 DYNAMIC=ANSI DYNAMIC=ORACLE

記述子の作成

ALLOCATE文を使用する必要があります。

Oracle形式の記述子を使用する必要があります。

記述子の破損

DEALLOCATE文を使用できます。

使用不可。

データの取出し

FETCH文およびGET文のどちらも使用できます。

FETCH文のみ使用できます。

入力データの設定

DESCRIBE INPUT文を使用できます。SET文を使用する必要があります。

コードに記述子値を設定する必要があります。DESCRIBE BIND VARIABLES文を使用する必要があります。

記述子の表現

引用符付きのリテラル、または記述子名を含むホスト識別子。

ホスト変数、SQLDAを指すポインタ。

利用可能なデータ型

BITを除くすべてのANSI型、およびすべてのOracle型。

オブジェクト、LOBおよびカーソル変数を除くOracle型。


マイクロ・オプションTYPE_CODEは、プリコンパイラによってマクロ・オプションMODEと同じ値に設定されます。DYNAMICがANSIの場合、TYPE_CODEはANSIにしか設定できません。

TYPE_CODEの設定に対応する機能を次の表に示します。

表10-3 TYPE_CODEオプションの設定

機能 TYPE_CODE=ANSI TYPE_CODE=ORACLE

動的SQLからの入出力に使用するデータ型コード番号

ANSI型があるときはANSIコード番号を使用します。ない場合はOracleコード番号の負の値を使用します。

DYNAMIC=ANSIのときのみ有効です。

Oracleコード番号を使用します。

DYNAMICの設定に関係なく使用できます。


動的SQL文の構文

次の文の詳細は、付録E「埋込みSQL文およびプリコンパイラ・ディレクティブ」のアルファベット順のリストを参照してください。

ALLOCATE DESCRIPTOR

この文はANSI動的SQLでのみ使用できます。

用途

この文は、SQL記述子領域を割り当てるために使用します。記述子、記述子のホスト・バインド項目の出現の最大数および配列サイズを指定します。

構文

     EXEC SQL [FOR [:]array_size] ALLOCATE DESCRIPTOR [GLOBAL | LOCAL]
        {:desc_nam | string_literal} [WITH MAX occurrences]
     END-EXEC.

変数

ALLOCATE記述子では様々な変数が使用できます。ALLOCATE記述子が使用できる変数にはarray_size、desc_nam、occurrencesなどがあります。

array_size

オプションのarray_size句(Oracle拡張機能)では表の処理をサポートしています。表の処理に記述子を使用できることをプリコンパイラに示します。

 GLOBAL | LOCAL

オプションのスコープ句です。入力しなかった場合のデフォルトはLOCALです。ローカル記述子は、その記述子を割り当てたファイル内でのみアクセス可能です。グローバル記述子は、コンパイル・ユニット内の任意のモジュールで使用できます。

desc_nam

desc_nam変数は、モジュール内で一意であることが必要なローカル記述子を定義します。事前に記述子が割り当てられ解除されていない場合は、ランタイム・エラーが発生します。グローバル記述子は、アプリケーション内で一意であることが必要です。一意でない場合は、ランタイム・エラーが発生します。

occurrences

オプションのoccurrences句は、記述子で使用できるホスト変数の最大数を示します。occurrences変数には、0から64000の整定数を指定する必要があります。これ以外の数を指定するとエラーが戻されます。デフォルトは100です。指定規則に反している場合は、プリコンパイラ・エラーが発生します。

     EXEC SQL ALLOCATE DESCRIPTOR 'SELDES' WITH MAX 50 END-EXEC.

     EXEC SQL FOR :BATCH ALLOCATE DESCRIPTOR GLOBAL :BINDDES WITH MAX 25
        END-EXEC.

DEALLOCATE DESCRIPTOR

用途

メモリーを解放するには、割当て解除文を使用します。この文は、事前に割り当てたSQL記述子領域を解除します。

構文

     EXEC SQL DEALLOCATE DESCRIPTOR [GLOBAL | LOCAL]
        {:desc_nam | string_literal}
     END-EXEC.

変数

desc_nam

割当て解除記述子が使用できる唯一の変数がdesc_nam(記述子名)です。同じ名前およびスコープの記述子が割り当てられていない場合、または割り当てられ、すでに解除されている場合は、ランタイム・エラーが発生します。

     EXEC SQL DEALLOCATE DESCRIPTOR GLOBAL 'SELDES' END-EXEC.

     EXEC SQL DEALLOCATE DESCRIPTOR :BINDDES END-EXEC.

GET DESCRIPTOR

用途

この文は、SQL記述子領域からの情報の取得に使用します。

構文

     EXEC SQL [FOR [:]array_size] GET DESCRIPTOR [GLOBAL | LOCAL]
        {:desc_nam | string_literal}
        {:hv0  = COUNT | VALUE item_number :hv1 = item_name1
        [{, :hvN = item_nameN }]}
     END-EXEC.

変数

array_size

array_size変数は、オプションのOracle拡張機能です。array_sizeは、FETCH文のarray_sizeフィールドと等しいことが必要です。

desc_nam

記述子名。

GLOBAL | LOCAL

GLOBALは、すべてのプログラム・ファイルで記述子名が認識されることを示します。LOCALは、記述子名を割り当てたファイル内でのみ記述子名が認識されることを示します。LOCALがデフォルトです。

COUNT

バインド変数の合計数。

VALUE item_number

SQL文での項目の位置。item_numberには変数または定数を指定できます。item_numberCOUNTよりも大きいと、「データが見つかりません。」という状態が戻されます。item_numberは0よりも大きくする必要があります。

hv1 .. hvN

値の転送先のホスト変数。

item_name1 .. item_nameN

ホスト変数に対応付けられた記述子項目名。使用できるANSI記述子項目名を次の表に示します。

表10-4 記述子項目名の定義

記述子項目名 意味

TYPE

ANSI型コードは表10-1を参照してください。Oracle型コードは表11-2を参照してください。ANSIデータ型が表になく、TYPE_CODE = ANSIである場合は、Oracleコードの負の値を使用してください。

LENGTH

列内のデータの長さ。NCHARは文字単位、それ以外はバイト単位です。DESCRIBE OUTPUTによって設定されます。

OCTET_LENGTH

バイト単位でのデータの長さ。

RETURNED_LENGTH

FETCH後の実際のデータ長。固定長キャラクタ・タイプについては未定義になります。

RETURNED_OCTET_LENGTH

戻されたデータのバイト単位での長さ。

PRECISION

桁数。

SCALE

真数値型での小数点の右側の桁数。

NULLABLE

1のときは、列にNULL値を使用できます。0のときは、列にNULL値は使用できません。

INDICATOR

対応付けられたインジケータ値。

DATA

データ値。

NAME

列名。

CHARACTER_SET_NAME

列のキャラクタ・セット。


次の表に、記述子項目名のOracle拡張機能を示します。

表10-5 記述子項目名の定義のOracle拡張機能

記述子項目名 意味

NATIONAL_CHARACTER

2はNCHARまたはNVARCHAR2を示します。1は文字を示します。0は文字以外を示します。

INTERNAL_LENGTH

内部でのバイト単位の長さ。


使用上の注意

FOR句は、DATA、INDICATORおよびRETURNED_LENGTH項目のみを含むGET DESCRIPTOR文で使用してください。

内部型は、DESCRIBE OUTPUT文によって設定されます。入力および出力のどちらでも、ホスト変数の外部型に使用する型を設定する必要があります。TYPEは、OracleコードまたはANSIコード(表10-1)です。ANSI型が表にはない場合は、Oracle型の負の値が戻されます。

LENGTHには、列の長さが格納され、固定幅の各国語キャラクタ・セットが設定されたフィールドでは文字単位になります。それ以外のキャラクタ列ではバイト単位になります。LENGTHはDESCRIBE OUTPUTによって設定されます。

RETURNED_LENGTHは、FETCH文によって設定される実際のデータ長です。LENGTHと同様にバイト単位または文字単位になります。フィールドOCTET_LENGTHおよびRETURNED_OCTET_LENGTHは、バイト単位の長さです。

NULLABLE = 1は、列にNULLを使用できることを示します。NULLABLE = 0は、列にNULLを使用できないことを示します。

CHARACTER_SET_NAMEは、キャラクタ列の場合にのみ意味があります。他の型では未定義になります。DESCRIBE OUTPUT文によって値が設定されます。

DATAおよびINDICATORは、その列のデータ値およびインジケータ・ステータスです。データがNULLでインジケータが要求されなかった場合は、実行時にエラーが発生します(DATA EXCEPTION, NULL VALUE, NO INDICATOR PARAMETER)。

Oracle固有の記述子項目名

列がNCHARまたはNVARCHAR2列の場合は、NATIONAL_CHARACTER = 2になります。列がキャラクタ(ただし、各国語キャラクタではない)列の場合、項目は1に設定されます。キャラクタ以外の列の場合、DESCRIBE OUTPUTの実行後にこの項目は0に設定されます。

INTERNAL_LENGTHは、Oracle動的方法4との互換性があるため、Oracle記述子領域の長さメンバーと同じ値に設定されます。「Oracle動的SQL: 方法4」を参照してください。

     EXEC SQL GET DESCRIPTOR :BINDDES :COUNT = COUNT END-EXEC.

     EXEC SQL GET DESCRIPTOR 'SELDES' VALUE 1 :TYP = TYPE, :LEN = LENGTH
        END-EXEC.

     EXEC SQL FOR :BATCH GET DESCRIPTOR LOCAL 'SELDES'
        VALUE :SEL-ITEM-NO :IND = INDICATOR, :DAT = DATA END-EXEC.

SET DESCRIPTOR

用途

この文は、ホスト変数からの記述子領域の情報を設定するために使用します。SET DESCRIPTOR文では、項目名のホスト変数のみサポートされます。

構文

     EXEC SQL [FOR [:]array_size] SET DESCRIPTOR [GLOBAL | LOCAL]
        {:desc_nam | string_literal}
        {COUNT = :hv0 | VALUE item_number
        [REF] item_name1 = :hv1
        [{, [REF] item_nameN = :hvN}]}
     END-EXEC.

変数

array_size

これは、オプションのOracle句です。この句によって、記述子項目のDATA、INDICATORおよびRETURNED_LENGTHのみ設定するときに配列を使用できます。FOR句を含むSET DESCRIPTORでは、他の項目は使用できません。すべてのホスト変数表のサイズが一致する必要があります。SET文の配列サイズは、FETCH文に使用する配列サイズと同じ設定にします。

desc_nam

記述子名。ALLOCATE DESCRIPTORでの規則が適用されます。

COUNT

バインド(入力)変数または定義(出力)変数の数。

VALUE item_number

動的SQL文でのホスト変数の位置。

hv1 .. hvN

設定するホスト変数(定数ではありません)。

item_name1 .. item_nameN

GET DESCRIPTOR構文(「GET DESCRIPTOR」を参照)と同様に、item_nameに次の値を指定できます。

表10-6 SET DESCRIPTORの記述子項目名

記述子項目名 意味

TYPE

ANSI型コードは表10-1を参照してください。Oracle型コードは表11-2を参照してください。ANSI型が表にはなく、TYPE_CODE = ANSIである場合は、Oracle型コードの負の値を使用してください。

LENGTH

列内のデータの最大長。

PRECISION

桁数。

SCALE

真数値型での小数点の右側のバイト数。

INDICATOR

対応付けられたインジケータ値。参照セマンティクスのために設定します。

DATA

設定するデータの値。参照セマンティクスのために設定します。

CHARACTER_SET_NAME

列のキャラクタ・セット。


次の表に、記述子項目名のOracle拡張機能を示します。

表10-7 SET DESCRIPTORの記述子項目名の拡張機能

記述子項目名 意味

RETURNED_LENGTH

FETCH後に戻される長さ。参照セマンティクスを使用する場合に設定します。

NATIONAL_CHARACTER

入力ホスト変数がNCHARまたはNVARCHAR2型のときは、2に設定します。


使用上の注意

参照セマンティクスは、パフォーマンス向上のために使用する別のオプションのOracle拡張機能です。記述子項目名がDATA、INDICATORおよびRETURNED_LENGTHの場合にのみ、それらの前にREFキーワードを指定します。REFキーワードを使用した場合は、GET文を使用する必要はありません。複合データ型およびDMLのRETURNING句には、SET DESCRIPTORのREF書式が必要です。「DML RETURNING句」を参照してください。

REFを使用すると、対応付けられたホスト変数自体がSETで使用されます。この場合、GETは必要ありません。値構文ではなく、REFセマンティクスを使用するときにのみ、RETURNED_LENGTHを設定できます。

SETまたはGET文の配列サイズは、FETCHで使用する配列サイズと同じにしてください。

NCHARホスト変数には、NATIONAL_CHARフィールドを2に設定します。

オブジェクト型の特性を設定するときは、USER_DEFINED_TYPE_NAMEおよびUSER_DEFINED_TYPE_NAME_LENGTHを設定する必要があります。

省略した場合は、USER_DEFINED_TYPE_SCHEMAおよびUSER_DEFINED_TYPE_SCHEMA_LENGTHはデフォルトで現行の接続に設定されます。

バルク表の例は、「バルク操作での表の使用方法」を参照してください。

 ...
 O1  BINDNO  PIC S9(9) COMP  VALUE 2.
 01  INDI    PIC S9(4) COMP  VALUE -1.
 01  DATA    PIC X(6)  COMP  VALUE "ignore".
 01  BATCH   PIC S9(9) COMP  VALUE 1.
 ...
     EXEC SQL FOR :batch ALLOCATE DESCRIPTOR :BINDDES END-EXEC.
     EXEC SQL SET DESCRIPTOR GLOBAL :BINDDES COUNT = 3 END-EXEC.
     EXEC SQL FOR :batch SET DESCRIPTOR :BINDDES
        VALUE :BINDNO INDICATOR = :INDI, DATA = :DATA END-EXEC.
...

PREPAREの使用

用途

この方法で使用するPREPARE文は、Oracle動的SQL方法で使用するPREPARE文と同じです。Oracle拡張機能によって、変数と同様にSQL文で引用符付き文字列を使用できます。

構文

     EXEC SQL PREPARE statement_id FROM :sql_statement END-EXEC.

変数

statement_id

この変数を宣言しないでください。これは、準備済のSQL文に対応付けられた宣言されていないSQL識別子です。

sql_statement

埋込みSQL文を格納する文字列(定数または変数)。

 ...
 01  STATEMENT    PIC X(255)
        VALUE "SELECT ENAME FROM emp WHERE deptno = :d".
 ...
     EXEC SQL PREPARE S1 FROM :STATEMENT END-EXEC.

DESCRIBE INPUT

用途

この文は、入力バインド変数に関する情報を戻します。

構文

     EXEC SQL DESCRIBE INPUT statement_id USING [SQL] DESCRIPTOR
        [GLOBAL | LOCAL] {:desc_nam | string_literal}
     END-EXEC.

変数

statement_id

PREPAREおよびDESCRIBE OUTPUTで使用するものと同じです。この変数を宣言しないでください。これはSQL識別子です。

GLOBAL | LOCAL

GLOBALは、すべてのプログラム・ファイルで記述子名が認識されることを示します。LOCALは、記述子名を割り当てたファイル内でのみ記述子名が認識されることを示します。LOCALがデフォルトです。

desc_nam

記述子名。

使用上の注意

このバージョンでは、COUNTおよびNAMEのみがバインド変数のために実装されています。

     EXEC SQL DESCRIBE INPUT S1 USING SQL DESCRIPTOR GLOBAL :BINDDES END-EXEC.
     EXEC SQL DESCRIBE INPUT S2 USING DESCRIPTOR 'input' END-EXEC.

DESCRIBE OUTPUT

用途

DESCRIBE INPUT文は、PREPARE文の列に関する情報を取得するために使用します。ANSI構文は以前の構文と違います。SQL記述子領域に格納される情報は、戻された値の個数、および関連する情報(型、長さ、名前など)です。

構文

     EXEC SQL DESCRIBE [OUTPUT] statement_id USING [SQL] DESCRIPTOR
        [GLOBAL | LOCAL] {:desc_nam | string_literal}
     END-EXEC.

変数

statement_id

statement_idはSQL識別子です。宣言しないでください。

GLOBAL | LOCAL

GLOBALは、すべてのプログラム・ファイルで記述子名が認識されることを示します。LOCALは、記述子名を割り当てたファイル内でのみ記述子名が認識されることを示します。LOCALがデフォルトです。

desc_nam

記述子名。ホスト変数の前に「:」を付けたもの、または引用符付き文字列。OUTPUTがデフォルト設定で、これは省略できます。

 ...
 01  DESNAME   PIC X(10) VALUE "SELDES".
 ...
     EXEC SQL DESCRIBE S1 USING SQL DESCRIPTOR 'SELDES' END-EXEC.
* Or:
     EXEC SQL DESCRIBE OUTPUT S1 USING DESCRIPTOR :DESNAME END-EXEC.

EXECUTE

用途

EXECUTEは、準備済のSQL文の入力変数および出力変数を照合し、文を実行します。ANSIバージョンのEXECUTEは、以前のEXECUTEとは違い、DML RETURNINGをサポートするために1つの文に記述子を2つ使用できます。

構文

     EXEC SQL [FOR [:]array_size] EXECUTE statement_id
        [USING [SQL] DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}]
        [INTO [SQL] DESCRIPTOR [GLOBAL | LOCAL] {:desc_nam | string_literal}]
     END-EXEC.

変数

array_size

文が処理する行数。

statement_id

PREPAREで使用するものと同じです。この変数を宣言しないでください。これはSQL識別子です。リテラルを指定できます。

GLOBAL | LOCAL

GLOBALは、すべてのプログラム・ファイルで記述子名が認識されることを示します。LOCALは、記述子名を割り当てたファイル内でのみ記述子名が認識されることを示します。LOCALがデフォルトです。

desc_nam

記述子名。ホスト変数の前に「:」を付けたもの、または引用符付き文字列。

使用上の注意

INTO句は、INSERT、UPDATEおよびDELETEのRETURNING句を実装します(「行の挿入」とその後のページを参照してください)。

     EXEC SQL EXECUTE S1 USING SQL DESCRIPTOR GLOBAL :BINDDES END-EXEC.

     EXEC SQL EXECUTE S2 USING DESCRIPTOR :bv1 INTO DESCRIPTOR 'SELDES'
        END-EXEC.

EXECUTE IMMEDIATEの使用

用途

EXECUTE IMMEDIATE文は、SQL文を含むリテラル文字列またはホスト変数文字列を実行します。この文のANSI SQL書式は、以前の動的SQLと同じです。

構文

     EXEC SQL EXECUTE IMMEDIATE [:]sql_statement END-EXEC.

変数

EXECUTE IMMEDIATE文で使用できる変数は1つです。

sql_statement

sql_statement変数は、文字列内のSQL文またはPL/SQLブロックです。ホスト変数にもリテラルにも使用できます。

     EXEC SQL EXECUTE IMMEDIATE :statement END-EXEC.

DYNAMIC DECLARE CURSORの使用

用途

DYNAMIC DECLARE CURSOR文は、問合せ文に対応付けられたカーソルを宣言します。これは、一般的なカーソル宣言部です。

構文

     EXEC SQL DECLARE cursor_name CURSOR FOR statement_id END-EXEC.

変数

cursor_name

カーソル変数(SQL識別子です。ホスト変数ではありません)。

statement_id

未定義のSQL識別子(PREPARE文で使用するものと同じです)。

     EXEC SQL DECLARE C1 CURSOR FOR S1 END-EXEC.

カーソルのOPEN

用途

OPEN文は、入力パラメータとカーソルとを対応付け、カーソルをオープンします。

構文

     EXEC SQL [FOR [:]array_size] OPEN dyn_cursor
        [[USING [SQL] DESCRIPTOR [GLOBAL | LOCAL] desc_nam1]
        [INTO [SQL] DESCRIPTOR [GLOBAL | LOCAL] desc_nam2] ]
     END-EXEC.

変数

array_size

この変数は、記述子を割り当てた時に指定した数と等しいか、それよりも小さい数に制限されます。

GLOBAL | LOCAL

GLOBALは、すべてのプログラム・ファイルで記述子名が認識されることを示します。LOCALは、記述子名を割り当てたファイル内でのみ記述子名が認識されることを示します。LOCALがデフォルトです。

dyn_cursor

カーソル変数。

desc_nam1、desc_nam2

オプションの記述子名。

使用上の注意

カーソルに対応付けられたプリコンパイルされたSQL文にコロンまたは疑問符が含まれる場合は、USING句を指定する必要があります。指定しない場合は、実行時にエラーが発生します。INTO句は、DML RETURNINGに対応しています(「行の挿入」およびその後のDELETEおよびUPDATEに関する項を参照してください)。

     EXEC SQL OPEN C1 USING SQL DESCRIPTOR :BINDDES END-EXEC.

     EXEC SQL FOR :LIMIT OPEN C2 USING DESCRIPTOR :B1, :B2
       INTO SQL DESCRIPTOR :SELDES
     END-EXEC.

FETCH

用途

FETCH文は、動的DECLARE文で宣言したカーソルの行をフェッチします。

構文

     EXEC SQL [FOR [:]array_size] FETCH cursor INTO [SQL] DESCRIPTOR
       [GLOBAL | LOCAL] {:desc_nam | string_literal}
     END-EXEC.

変数

array_size

文が処理する行数。

cursor

事前に宣言された動的カーソル。

GLOBAL | LOCAL

GLOBALは、すべてのプログラム・ファイルで記述子名が認識されることを示します。LOCALは、記述子名を割り当てたファイル内でのみ記述子名が認識されることを示します。LOCALがデフォルトです。

desc_nam

記述子名。

使用上の注意

FOR句のオプションのarray_sizeは、ALLOCATE DESCRIPTOR文で指定した数と等しいか、それより小さい必要があります。

RETURNED_LENGTHは、固定長キャラクタ・タイプに対しては未定義になります。

     EXEC SQL FETCH FROM C1 INTO DESCRIPTOR 'SELDES' END-EXEC.

     EXEC SQL FOR :ARSZ FETCH C2 INTO DESCRIPTOR :DESC END-EXEC.

動的カーソルのCLOSE

用途

CLOSE文は動的カーソルをクローズします。構文は方法4の場合と同じです。

構文

     EXEC SQL CLOSE cursor END-EXEC.

変数

CLOSE文で使用できる変数は1つです。

cursor

カーソル変数は、前に宣言した動的カーソルを記述します。

     EXEC SQL CLOSE C1 END-EXEC.

Oracle動的方法4との違い

ANSI動的SQLインタフェースでは、Oracle動的方法4でサポートされる機能がすべてサポートされます。それ以外に、次のサポートが追加されています。

  • ANSI動的SQLでは、すべてのデータ型(カーソル変数を含む)およびLOB型がサポートされます。

  • ANSIモードでは、内部のSQL記述領域が使用されます。これは、Oracleの以前の動的方法4で入力および出力情報の格納に使用される外部SQLDAを拡張したものです。

  • ALLOCATE DESCRIPTOR、DEALLOCATE DESCRIPTOR、DESCRIBE、GET DESCRIPTORおよびSET DESCRIPTORという新しい埋込みSQL文が導入されています。

  • ANSI動的SQLでは、DESCRIBE文は標識変数の名前を戻しません。

  • ANSI動的SQLでは、戻される列名または式の最大サイズを指定できません。デフォルト・サイズは128に設定されます。

  • 記述子名は、引用符で囲んだ識別子、または先頭にコロンをつけたホスト変数のどちらかであることが必要です。

  • 出力では、DESCRIBEのオプションのSELECT LIST FOR句がオプション・キーワードOUTPUTに変更されています。INTO句はUSING DESCRIPTOR句に変更されています。USING DESCRIPTOR句にはオプション・キーワードSQLを使用できます。

  • 入力では、DESCRIBEのオプションのBIND VARIABLES FOR句をキーワードINPUTに置き換えることができます。INTO句はUSING DESCRIPTOR句に変更されています。USING DESCRIPTOR句にはオプション・キーワードSQLを使用できます。

  • EXECUTE、FETCHおよびOPEN文でUSING句のキーワードDESCRIPTORの前にオプション・キーワードSQLを指定できます。

制限

ANSI動的SQLには次の制限が適用されます。

  • 同じモジュール内で2つの動的方法は併用できません。

  • プリコンパイラ・オプションDYNAMICをANSIに設定する必要があります。DYNAMICをANSIに設定したときにのみ、プリコンパイラ・オプションTYPE_CODEをANSIに設定できます。

  • SET文は、項目名としてのホスト変数のみサポートします。

サンプル・プログラム: SAMPLE12.PCO

次のANSI SQL動的方法4プログラムSAMPLE12.PCOは、デモ・ディレクトリにあります。SAMPLE12は、ユーザーが入力するSQL文を要求することによってSQL*Plusを模造したプログラムです。プログラムの流れの詳細は、最初のコメントを参照してください。

      ******************************************************************
      * Sample Program 12: Dynamic SQL Method 4 using ANSI Dynamic SQL *
      *                                                                *
      * This program shows the basic steps required to use dynamic     *
      * SQL Method 4 with ANSI Dynamic SQL.  After logging on to       *
      * ORACLE, the program prompts the user for a SQL statement,      *
      * PREPAREs the statement, DECLAREs a cursor, checks for any      *
      * bind variables using DESCRIBE INPUT, OPENs the cursor, and     *
      * DESCRIBEs any select-list variables.  If the input SQL         *
      * statement is a query, the program FETCHes each row of data,    *
      * then CLOSEs the cursor.                                        *
      * use option dynamic=ansi when precompiling this sample.         *
      ******************************************************************

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  ANSIDYNSQL4.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  USERNAME       PIC X(20).
       01  PASSWD         PIC X(20).
       01  BDSC           PIC X(6) VALUE "BNDDSC".
       01  SDSC           PIC X(6) VALUE "SELDSC".
       01  BNDCNT         PIC S9(9) COMP.
       01  SELCNT         PIC S9(9) COMP.
       01  BNDNAME        PIC X(80).
       01  BNDVAL         PIC X(80).
       01  SELNAME        PIC X(80) VARYING.
       01  SELDATA        PIC X(80).
       01  SELTYP         PIC S9(4) COMP.
       01  SELPREC        PIC S9(4) COMP.
       01  SELLEN         PIC S9(4) COMP.
       01  SELIND         PIC S9(4) COMP.
       01  DYN-STATEMENT  PIC X(80).
       01  BND-INDEX      PIC S9(9) COMP.
       01  SEL-INDEX      PIC S9(9) COMP.
       01  VARCHAR2-TYP   PIC S9(4) COMP VALUE 1.
       01  VAR-COUNT      PIC 9(2).
       01  ROW-COUNT      PIC 9(4).
       01  NO-MORE-DATA   PIC X(1) VALUE "N".
       01  TMPLEN         PIC S9(9) COMP.
       01  MAX-LENGTH     PIC S9(9) COMP VALUE 80.

           EXEC SQL INCLUDE SQLCA         END-EXEC.

       PROCEDURE DIVISION.
       START-MAIN.

           EXEC SQL WHENEVER SQLERROR GOTO SQL-ERROR END-EXEC.

           DISPLAY "USERNAME: " WITH NO ADVANCING.
           ACCEPT USERNAME.
           DISPLAY "PASSWORD: " WITH NO ADVANCING.
           ACCEPT PASSWD.
           EXEC SQL CONNECT :USERNAME IDENTIFIED BY :PASSWD END-EXEC.
           DISPLAY "CONNECTED TO ORACLE AS USER: ", USERNAME.

      *    ALLOCATE THE BIND AND SELECT DESCRIPTORS.

           EXEC SQL ALLOCATE DESCRIPTOR :BDSC WITH MAX 20 END-EXEC.
           EXEC SQL ALLOCATE DESCRIPTOR :SDSC WITH MAX 20 END-EXEC.

      *    GET A SQL STATEMENT FROM THE OPERATOR.

           DISPLAY "ENTER SQL STATEMENT WITHOUT TERMINATOR:".
           DISPLAY ">" WITH NO ADVANCING.
           ACCEPT DYN-STATEMENT.
           DISPLAY " ".

      *    PREPARE THE SQL STATEMENT AND DECLARE A CURSOR.

           EXEC SQL  PREPARE S1 FROM :DYN-STATEMENT  END-EXEC.
           EXEC SQL  DECLARE C1 CURSOR FOR S1        END-EXEC.

      *    DESCRIBE BIND VARIABLES.

           EXEC SQL DESCRIBE INPUT S1 USING DESCRIPTOR :BDSC END-EXEC.

           EXEC SQL GET DESCRIPTOR :BDSC :BNDCNT = COUNT END-EXEC.

           IF BNDCNT < 0
               DISPLAY "TOO MANY BIND VARIABLES."
               GO TO END-SQL
           ELSE
               DISPLAY "NUMBER OF BIND VARIABLES: " WITH NO ADVANCING
               MOVE BNDCNT TO VAR-COUNT
               DISPLAY VAR-COUNT
      *        EXEC SQL SET DESCRIPTOR :BDSC COUNT = :BNDCNT END-EXEC
           END-IF.

           IF BNDCNT = 0
               GO TO DESCRIBE-ITEMS.
           PERFORM SET-BND-DSC
                   VARYING BND-INDEX FROM 1 BY 1
                   UNTIL BND-INDEX > BNDCNT.

      *    OPEN THE CURSOR AND DESCRIBE THE SELECT-LIST ITEMS.

       DESCRIBE-ITEMS.
           EXEC SQL  OPEN C1 USING DESCRIPTOR :BDSC END-EXEC.

           EXEC SQL  DESCRIBE OUTPUT S1 USING DESCRIPTOR :SDSC  END-EXEC.

           EXEC SQL GET DESCRIPTOR :SDSC :SELCNT = COUNT END-EXEC.

           IF SELCNT < 0
               DISPLAY "TOO MANY SELECT-LIST ITEMS."
               GO TO END-SQL
           ELSE
               DISPLAY "NUMBER OF SELECT-LIST ITEMS: "
                   WITH NO ADVANCING
               MOVE SELCNT TO VAR-COUNT
               DISPLAY VAR-COUNT
               DISPLAY " "
      *        EXEC SQL SET DESCRIPTOR :SDSC COUNT = :SELCNT END-EXEC
           END-IF.

      *    SET THE INPUT DESCRIPTOR

           IF SELCNT > 0
               PERFORM SET-SEL-DSC
                   VARYING SEL-INDEX FROM 1 BY 1
                   UNTIL SEL-INDEX > SELCNT
               DISPLAY " ".

      *    FETCH EACH ROW AND PRINT EACH SELECT-LIST VALUE.

           IF SELCNT > 0
               PERFORM FETCH-ROWS UNTIL NO-MORE-DATA = "Y".

           DISPLAY " "
           DISPLAY "NUMBER OF ROWS PROCESSED: " WITH NO ADVANCING.
           MOVE SQLERRD(3) TO ROW-COUNT.
           DISPLAY ROW-COUNT.

      *    CLEAN UP AND TERMINATE.

           EXEC SQL CLOSE C1 END-EXEC.
           EXEC SQL DEALLOCATE DESCRIPTOR :BDSC END-EXEC.
           EXEC SQL DEALLOCATE DESCRIPTOR :SDSC END-EXEC.
           EXEC SQL ROLLBACK WORK RELEASE END-EXEC.
           DISPLAY " ".
           DISPLAY "HAVE A GOOD DAY!".
           DISPLAY " ".
           STOP RUN.

      *    DISPLAY ORACLE ERROR MESSAGE AND CODE.

       SQL-ERROR.
           DISPLAY " ".
           DISPLAY SQLERRMC.
       END-SQL.
           EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC.
           EXEC SQL ROLLBACK WORK RELEASE END-EXEC.
           STOP RUN.

      *    PERFORMED SUBROUTINES BEGIN HERE:

      *    SET A BIND-LIST ELEMENT'S ATTRIBUTE
      *    LET THE USER FILL IN THE BIND VARIABLES AND
      *    REPLACE THE 0S DESCRIBED INTO THE DATATYPE FIELDS OF THE
      *    BIND DESCRIPTOR WITH 1S TO AVOID AN "INVALID DATATYPE"
      *    ORACLE ERROR
       SET-BND-DSC.
               EXEC SQL GET DESCRIPTOR :BDSC VALUE
                      :BND-INDEX :BNDNAME = NAME END-EXEC.
               DISPLAY "ENTER VALUE FOR ", BNDNAME.
               ACCEPT BNDVAL.
               EXEC SQL SET DESCRIPTOR :BDSC VALUE :BND-INDEX
                 TYPE = :VARCHAR2-TYP, LENGTH = :MAX-LENGTH,
                 DATA = :BNDVAL END-EXEC.

      * SET A SELECT-LIST ELEMENT'S ATTRIBUTES
       SET-SEL-DSC.
           MOVE SPACES TO SELNAME-ARR.
           EXEC SQL GET DESCRIPTOR :SDSC VALUE :SEL-INDEX
                 :SELNAME = NAME, :SELTYP = TYPE,
                 :SELPREC = PRECISION, :SELLEN = LENGTH END-EXEC.

      *    IF DATATYPE IS DATE, LENGTHEN TO 9 CHARACTERS.
           IF SELTYP = 12
               MOVE 9 TO SELLEN.

      *    IF DATATYPE IS NUMBER, SET LENGTH TO PRECISION.
           MOVE 0 TO TMPLEN.
           IF SELTYP = 2 AND SELPREC = 0
               MOVE 40 TO TMPLEN.
           IF SELTYP = 2 AND SELPREC > 0
               ADD 2 TO SELPREC
               MOVE SELPREC TO TMPLEN.

           IF SELTYP = 2
               IF TMPLEN > MAX-LENGTH
                   DISPLAY "COLUMN VALUE TOO LARGE FOR DATA BUFFER."
                   GO TO END-SQL
               ELSE
                   MOVE TMPLEN TO SELLEN.


      * COERCE DATATYPES TO VARCHAR2.
           MOVE 1 TO SELTYP.

      *    DISPLAY COLUMN HEADING.
           DISPLAY "  ", SELNAME-ARR(1:SELLEN) WITH NO ADVANCING.

           EXEC SQL SET DESCRIPTOR :SDSC VALUE :SEL-INDEX
              TYPE = :SELTYP, LENGTH = :SELLEN END-EXEC.

      * FETCH A ROW AND PRINT THE SELECT-LIST VALUE.

       FETCH-ROWS.
           EXEC SQL  FETCH C1 INTO DESCRIPTOR :SDSC END-EXEC.
           IF SQLCODE NOT = 0
               MOVE "Y" TO NO-MORE-DATA.
           IF SQLCODE = 0
               PERFORM PRINT-COLUMN-VALUES
                   VARYING SEL-INDEX FROM 1 BY 1
                   UNTIL SEL-INDEX > SELCNT
               DISPLAY " ".

      * PRINT A SELECT-LIST VALUE.

       PRINT-COLUMN-VALUES.
           MOVE SPACES TO SELDATA.
      *    returned length is not set for blank padded types
           IF SELTYP EQUALS 1
              EXEC SQL GET DESCRIPTOR :SDSC VALUE :SEL-INDEX
                :SELDATA = DATA, :SELIND = INDICATOR,
                :SELLEN = LENGTH END-EXEC
           ELSE
              EXEC SQL GET DESCRIPTOR :SDSC VALUE :SEL-INDEX
                 :SELDATA = DATA, :SELIND = INDICATOR,
                 :SELLEN = RETURNED_LENGTH END-EXEC.
           IF (SELIND = -1)
              move "  NULL" to SELDATA.

           DISPLAY SELDATA(1:SELLEN), "  "
                 WITH NO ADVANCING.