11 Oracle動的SQL: 方法4
この章ではOracle動的SQL方法4を実装する方法を説明します。この方法では、ホスト変数を含む動的SQL文を受け取ったり、作成できます。含まれるホスト変数の個数は様々です。
新しいアプリケーションは、「ANSI動的SQL」で説明されている、より新しいANSI SQL方法4を使用して開発する必要があります。Oracle方法4ではカーソル変数、グループ項目の表、DML RETURNING句およびLOBはサポートされませんが、ANSI方法4ではOracleの型がすべてサポートされます。
内容は次のとおりです。
ノート:
動的SQL方法1、2、3の詳細およびOracle方法4の概要は、「Oracle動的SQL」を参照してください。
関連項目
11.1 方法4の特殊要件
方法4の要件を学ぶ前に、選択リスト項目およびプレースホルダの用語を十分に理解してください。選択リスト項目とは、問合せ内でキーワードSELECTの後に続く列または式のことです。たとえば、次の動的問合せは3つの選択リスト項目を含んでいます。
SELECT ENAME, JOB, SAL + COMM FROM EMP WHERE DEPTNO = 20
プレースホルダとは、SQL文の中で実際のバインド変数用に場所を確保する、ダミーのバインド(入力)変数のことです。宣言する必要はなく、任意の名前を付けられます。バインド変数のプレースホルダは、SET、VALUESおよびWHERE句で多く使用されます。たとえば、次の動的SQL文にはそれぞれ2つのプレースホルダが記述されています。
INSERT INTO EMP (EMPNO, DEPTNO) VALUES (:E, :D) DELETE FROM DEPT WHERE DEPTNO = :DNUM AND LOC = :DLOC
プレースホルダでは、表または列の名前は参照できません。
11.1.2 データベースに必要な情報
Pro*COBOLは、実行可能なすべての動的SQL文についてOracleのコールを作成します。データベースは、選択リスト項目もプレースホルダも組み込まれていない動的SQL文の実行には追加情報を必要としません。次のDELETE文がこのカテゴリに該当します。
* Dynamic SQL statement... MOVE 'DELETE FROM EMP WHERE DEPTNO = 30' TO STMT.
しかし、ほとんどの動的SQL文には選択リスト項目またはバインド変数のプレースホルダが組み込まれています。次のUPDATE文はその一例です。
* Dynamic SQL statement with place-holders... MOVE 'UPDATE EMP SET COMM = :C WHERE EMPNO = :E' TO STMT.
選択リスト項目またはバインド変数のプレースホルダ(あるいはその両方)が組み込まれている動的SQL文を実行する場合、データベースは出力値または入力値を格納するプログラム変数についての情報を必要とします。データベースでは、特に次の情報が必要です。
-
選択リスト項目およびバインド変数の数
-
各選択リスト項目および各バインド変数の長さ
-
各選択リスト項目および各バインド変数のデータ型
-
選択リスト項目の値を格納する各出力変数のメモリー・アドレスおよび各バインド変数のアドレス
たとえば、選択リスト項目の値を書き込むには、データベースは対応する出力変数のアドレスが必要です。
11.1.3 情報の格納位置
選択リスト項目またはバインド変数のプレースホルダに関してデータベースが必要とする情報は、(その値を除いて)すべてSQL記述子領域(SQLDA)と呼ばれるプログラム・データ構造に格納されます。
選択リスト項目の記述は選択SQLDAに格納され、バインド変数のプレースホルダの記述はバインドSQLDAに格納されます。
選択リスト項目の値は出力バッファに格納され、バインド変数の値は入力バッファに格納されます。これらのデータ・バッファのアドレスをライブラリ・ルーチンSQLADRを使用して選択SQLDAまたはバインドSQLDAに格納すると、データベースは出力値の書込み先や入力値の読取り元を認識できます。
値はどのようにしてこれらのデータ変数に格納されるのでしょうか。FETCHはカーソルを使用して出力値を生成します。入力値は、通常はユーザーが対話形式で入力した情報をもとに、プログラムによって代入されます。
11.1.4 情報の取得方法
データベースが必要とする情報を取得するには、DESCRIBE文を使用します。DESCRIBE SELECT LIST文は、各選択リスト項目を調べて、その名前、データ型、制約、長さ、位取りおよび精度を確認した後、それらの情報を選択SQLDAに格納します。たとえば、格納された情報は、後で印刷出力の列見出しとして選択リスト名を使用するときなどに使用できます。DESCRIBEでは、選択リスト項目の総数もSQLDAに格納されます。
DESCRIBE BIND VARIABLES文は、各プレースホルダを調べて、その名前および長さを確認した後、それらの情報を入力バッファおよびバインドSQLDAに格納します。格納された情報は、後でプレースホルダ名を使用してバインド変数の値の入力をユーザーに求めるときなどに使用できます。
11.2 SQL記述子領域(SQLDA)の理解
11.2.1 SQLDAの目的
方法4は、選択リスト項目の数またはバインド変数のプレースホルダの数が不明な動的SQL文の処理に必要とされます。このような動的SQL文を処理するには、プログラムでSQLDA (記述子とも呼ばれます)を明示的に宣言する必要があります。個々の記述子は、プログラム内のグループ項目に対応します。
選択記述子には、選択リスト項目の記述、および選択リスト項目の名前および値を格納する出力バッファのアドレスが格納されます。
バインド記述子にはバインド変数と標識変数の記述、およびバインド変数と標識変数の名前と値が格納されている入力バッファのアドレスを格納します。
記述子変数の中には、値ではなくアドレスを格納するものがあります。このため、値を保持するためのデータ・バッファを宣言する必要があります。必要な入力バッファおよび出力バッファのサイズは自由に設定できます。COBOLではポインタはサポートされていないので、入力バッファおよび出力バッファのアドレスを取得するにはライブラリ・サブルーチンSQLADRを使用する必要があります。SQLADRのコール方法については、「SQLADRの使用方法」の項を参照してください。
関連項目
11.2.2 複数のSQLDA
プログラムにアクティブな動的SQL文が2つ以上ある場合は、それぞれの文が専用のSQLDAを持つ必要があります。別の名前で任意の数のSQLDAを宣言できます。たとえば、同時にオープンされている3つのカーソルからFETCHするために、SELDSC1、SELDSC2およびSELDSC3の名前の3つの選択SQLDAを宣言できます。ただし、非並行のカーソルではSQLDAを再利用できます。
11.2.3 SQLDAの宣言
選択およびバインドSQLDAを宣言するには、図11-1に示す選択およびバインドSQLDAのサンプルを使用して、プログラムに記述する方法があります。配列の大きさは、必要に応じて変更できます。
ノート:
バイトスワップ・プラットフォームの場合は、SQLDAの宣言時にCOMPのかわりにCOMP5を使用します。
図11-1 サンプルPro*COBOL SQLDA記述子およびデータ・バッファの例(32ビット)
「図11-1 サンプルPro*COBOL SQLDA記述子およびデータ・バッファの例(32ビット)」の説明
ノート:
64ビット・プラットフォームの場合は、SQLDAの宣言時に、PIC S9(9)のかわりにPIC S9(18)を使用します。
次に示すように、SQLDAを(たとえばSELDSCおよびBNDDSCの名前の)ファイルに格納して、INCLUDE文を使用してそのファイルをプログラムにコピーできます。
EXEC SQL INCLUDE SELDSC END-EXEC. EXEC SQL INCLUDE BNDDSC END-EXEC.
図11-2は、変数がSQLADRコール、DESCRIBEコマンド、FETCHコマンドまたはプログラム代入のどれによって設定されるかを示しています。
11.3 SQLDA変数
SQLDNUM
この変数では、DESCRIBEに含めることができる選択リスト項目またはプレースホルダの最大数を指定します。したがって、SQLDNUMによって記述子表の要素の数(ディメンション)が決まります。
DESCRIBEコマンドを発行する前に、この変数を記述子表のサイズに設定する必要があります。また、DESCRIBEの実行後に、この変数をDESCRIBE内の実際の変数の数(これはSQLDFNDに格納されます)に再設定する必要があります。
SQLDFND
SQLDFND変数は、DESCRIBEコマンドで実際に検出された選択リスト項目またはプレースホルダの数です。
SQLDFNDはDESCRIBEによって設定されます。SQLDFNDが負の値の場合は、DESCRIBEコマンドが検出した選択リスト項目またはプレースホルダの数が、記述子のサイズに対して多すぎることを意味します。たとえば、SQLDNUMを10に設定した場合にDESCRIBEで11個の選択リスト項目またはプレースホルダが検索されると、SQLDFNDは-11に設定されます。この場合、記述子を再び割り当てないかぎりSQL文の処理はできません。
DESCRIBEの後で、SQLDNUMをSQLDFNDの値に設定してください。
SELDV | BNDDV
選択記述子
次の文を実行するとします。
EXEC SQL FETCH ... USING DESCRIPTOR ...
この文は、FETCHされた選択リスト変数を、SELDV(1)からSELDV(SQLDNUM)でアドレス指定されたデータ・バッファに格納するようにデータベースに指示します。したがって、データベースはJ番目の選択リスト値をSEL-DV(J)に格納します。
バインド記述子
バインド記述子は、OPENコマンドを発行する前に設定する必要があります。次の文を実行するとします。
EXEC SQL OPEN ... USING DESCRIPTOR ...
この文は、BNDDV(1)からBNDDV(SQLDNUM)でアドレス指定されたバインド変数の値を使用して動的SQL文を実行するように、Oracleに指示します。(通常、値はユーザーによって入力されます。)データベースは、J番目のバインド変数値をBND-DV(J)から検索します。
SELDFMT | BNDDFMT
SELDFMT | BNDDFMT表は、選択リストまたはバインド変数の変換フォーマット文字列の値を格納するデータ・バッファのアドレスの表です。現在は、COBOLのパック10進数にのみ使用できます。変換文字列の書式はPP.+SSまたはPP.-SSです。PPは精度、SSは位取りです。精度および位取りの定義の詳細は、データ型の強制変換の精度および位取りの抽出を参照してください。
フォーマット文字列の使用はオプションです。J番目の選択リスト項目またはバインド変数に変換形式を使用する場合は、SQLADRを使用してSELDFMT(J)またはBNDDFMT(J)を設定し、パック10進形式(07.+02
など)をSEL-DFMTまたはBND-DFMTに格納します。変換形式を使用しない場合は、SELDFMT(J)またはBNDDFMT(J)を0 (ゼロ)に設定してください。
SELDVLN | BNDDVLN
選択記述子
この表は、DESCRIBE SELECT LISTによって、各選択リスト項目に期待される最大値に設定されます。しかし、FETCHコマンドを発行する前に長さを再設定する場合も考えられます。FETCHでは最大でn文字が戻されます(nは、FETCHコマンドを実行する前のSELDVLN(J)の値です)。
長さの形式はデータ型によって異なります。CHAR型の選択リスト項目の場合は、DESCRIBE SELECT LISTはSELDVLN(J)をその選択リスト項目の最大長(バイト数)に設定します。NUMBER型の選択リスト項目については、位取りおよび精度が変数の下位バイトおよびその次の上位側バイトにそれぞれ戻されます。ライブラリ・ルーチンSQLPRCを使用して、SELDVLNから精度および位取りを抽出できます。「精度および位取りの抽出」の項を参照してください。
FETCHを実行する前に、SELDVLN(J)を必要なデータ・バッファの長さに再設定する必要があります。たとえば、NUMBER型の数値をCOBOLの文字列に強制変換するときには、SELDVLN(J)を、その数値の精度に符号および小数点のために2を加えた長さに設定してください。また、NUMBER型の数値をCOBOLの浮動小数点数に強制変換するときには、SELDVLN(J)を、使用しているシステムでの適切な浮動小数点型の長さに設定してください。
強制変換するデータ型の長さの詳細は、「データの変換」の項を参照してください。
バインド記述子
OPENコマンドを発行する前に、バインド記述子の長さを設定する必要があります。たとえば、次の文を使用して、ユーザーが入力したバインド変数文字列の長さを設定できます。
PROCEDURE DIVISION. ... PERFORM GET-INPUT-VAR VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN BNDDSC. ... GET-INPUT-VAR. DISPLAY "Enter value of ", BND-DH-VNAME(J). ACCEPT INPUT-STRING. UNSTRING INPUT-STRING DELIMITED BY " " INTO BND-DV(J) COUNT IN BNDDVLN(J).
Oracleは、SELDV(J)またはBNDDV(J)に格納されているアドレスを使用して間接的にデータ・バッファにアクセスするため、データ・バッファ内の値の長さは認識しません。J番目の選択リスト値またはバインド変数値に対してOracleが使用する長さを変更する場合は、SELDVLN(J)またはBNDDVLN(J)を必要な長さに再設定してください。入力バッファまたは出力バッファにはそれぞれ異なる長さを指定できます。
SELDFMTL | BNDDFMTL
これは、選択リストまたはバインド変数の変換フォーマット文字列の長さの表です。現在は、COBOLのパック10進数にのみ使用できます。
フォーマット文字列の使用はオプションです。J番目の選択リスト項目に変換形式を使用する場合は、FETCHの前に、SELDFMTL(J)をSEL-DFMTに格納されているパック10進形式の長さに設定します。J番目のバインド変数に変換形式を使用する場合は、OPENの前に、BNDDFMTL(J)をBND-DFMTに格納されているパック10進形式の長さに設定します。変換形式を使用しない場合は、SELDFMTL(J)またはBNDDFMTL(J)を0(ゼロ)に設定してください。
SELDFMTL(J)の値が0 (ゼロ)の場合は、SELDFMT(J)は使用されません。同様に、BNDDFMTL(J)の値が0 (ゼロ)の場合は、BNDDFMT(J)は使用されません。
SELDVTYP | BNDDVTYP
SELDVTYP | BNDDVTYP表は、選択リスト値またはバインド変数値のデータ型コードの表です。データ型コードによって、SELDVの要素でアドレス指定されたデータ・バッファに格納されたときに、Oracleのデータがどのように変換されるかが決定されます。データ型記述子表の詳細は、「データの変換」を参照してください。
選択記述子
DESCRIBE SELECT LISTにより、この表は、選択リスト項目の内部データ型(VARCHAR2、CHAR、NUMBER、DATEなど)に設定されます。
データ型の内部形式は処理が難しいため、FETCHを実行する前にデータ型を再設定することをお薦めします。表示用には、選択リスト値のデータ型をVARCHAR2に強制変換するのが一般的です。計算用には、数値をOracleからCOBOL書式に強制変換できます。「データ型の強制変換」を参照してください。
SELDVTYP(J)の上位ビットは、J番目の選択リスト列のNULL/NOT NULL状態を示します。OPENコマンドまたはFETCHコマンドを発行する前に、常にこのビットをクリアする必要があります。ライブラリ・ルーチンSQLNULを使用して、データ型コードを取り出し、NULL/NOT NULLビットをクリアします。詳細は、「NULLまたはNOT NULLデータ型の処理」を参照してください。
NUMBER内部データ型は、SELDV(J)でアドレス指定されたCOBOLデータ・バッファの外部データ型と互換性のある外部データ型に変更することをお薦めします。
バインド記述子
DESCRIBE BIND VARIABLESは、この表を0 (ゼロ)に設定します。OPENコマンドを発行する前に、このデータ型の表を再設定する必要があります。コードは、BNDDV(J)でアドレス指定されたバッファの外部(COBOL)データ型を表します。多くの場合、バインド変数値は文字列に格納されるので、データ型表の要素は1 (VARCHAR2データ型コード)に設定されます。
J番目の選択リスト値またはバインド変数値のデータ型を変更するには、SELDVTYP(J)またはBNDDVTYP(J)を希望するデータ型に再設定してください。
SELDI | BNDDI
選択記述子
この表は、FETCHコマンドを発行する前に設定する必要があります。次の文を実行するとします。
EXEC SQL FETCH ... USING DESCRIPTOR ...
戻された選択リストのJ番目の値がNULLの場合は、SELDI(J)でアドレス指定されたバッファが-1に設定されます。それ以外の場合は、(値がNULLでない) 0または(値が切り捨てられている)正の整数に設定されます。
バインド記述子
OPENコマンドを実行する前にこの表を初期化し、対応する標識変数を設定する必要があります。次の文を実行するとします。
EXEC SQL OPEN ... USING DESCRIPTOR ...
BNDDI(J)でアドレス指定されたバッファによって、J番目のバインド変数がNULLかどうかがわかります。標識変数の値が-1の場合、対応するバインド変数はNULLです。
SELDH-VNAME | BNDDH-VNAME
SELDH-VNAME | BNDDH-VNAME表は、動的SQL文に表示される選択リストまたはプレースホルダの名前を格納するデータ・バッファのアドレスの表です。SELDH-VNAMEまたはBNDDH-VNAMEの要素は、DESCRIBEコマンドを発行する前にSQLADRを使用して設定する必要があります。
DESCRIBEは、J番目の選択リスト項目またはプレースホルダの名前をSELDH-VNAME(J)またはBNDDH-VNAME(J)でアドレス指定されたデータ・バッファに格納するように、Oracleに指示します。Oracleは、J番目の選択リストまたはプレースホルダの名前をSEL-DH-VNAME(J)またはBND-DH-VNAME(J)に格納します。
ノート:
SELDH-VNAME | BNDDH-VNAME表は列名のみを格納します。SQL文中で指定した場合でも、表修飾子付きの列名は格納しません。たとえば、SQL文select a.owner from all_tables
で選択リストの記述を行うと、not a.owner
ではなくowner
が戻されます。必要に応じて列別名を使用して、選択リストの列が正しく識別されるようにします。
SELDH-MAX-VNAMEL | BNDDH-MAX-VNAMEL
SELDH-MAX-VNAMEL | BNDDH-MAX-VNAMEL表は、選択リストまたはプレースホルダの名前を格納するデータ・バッファの最大長の表です。バッファはSELDH-VNAMEまたはBNDDH-VNAMEの要素によってアドレス指定されます。
SELDH-MAX-VNAMELまたはBNDDH-MAX-VNAMELの要素は、DESCRIBEコマンドを発行する前に設定する必要があります。選択リスト名のバッファまたはプレースホルダ名のバッファは、それぞれ長さが異なっていてもかまいません。
SELDH-CUR-VNAMEL | BNDDH-CUR-VNAMEL
SELDH-CUR-VNAMEL | BNDDH-CUR-VNAMEL表は、選択リストまたはプレースホルダの実際の長さの表です。DESCRIBEはこの表を、各選択リスト名またはプレースホルダ名の文字数に設定します。
SELDI-VNAME | BNDDI-VNAME
SELDI-VNAME | BNDDI-VNAME表は、標識変数の値を格納するデータ・バッファのアドレスの表です。
標識変数の値は、選択リスト項目およびバインド変数と対応付けできます。ただし標識変数の名前は、バインド変数のみに対応付けることができます。この表はバインド記述子でのみ使用できます。BNDDI-VNAMEの要素は、DESCRIBEコマンドを発行する前にSQLADRを使用して設定する必要があります。
DESCRIBE BIND VARIABLESは、標識変数名をBNDDI-VNAME(1)からBNDDI-VNAME(SQLDNUM)でアドレス指定されたデータ・バッファに格納するように、Oracleに指示します。Oracleは、J番目の標識変数名をBND-DI-VNAME(J)に格納します。
SELDI-MAX-VNAMEL | BNDDI-MAX-VNAMEL
SELDI-MAX-VNAMEL | BNDDI-MAX-VNAMEL表は、標識変数名を格納するデータ・バッファの最大長の表です。バッファは、SELDI-VNAMEまたはBNDDI-VNAMEの要素によってアドレス指定されます。
標識変数名はバインド変数にのみ対応付けできます。この表はバインド記述子でのみ使用できます。
要素BNDDI-MAX-VNAMEL(1)からBNDDI-MAX-VNAMEL(SQLDNUM)は、DESCRIBEコマンドの発行前に設定する必要があります。標識変数名のバッファは、それぞれ長さが異なっていてもかまいません。
SELDI-CUR-VNAMEL | BNDDI-CUR-VNAMEL
SELDI-CUR-VNAMEL | BNDDI-CUR-VNAMEL表は、標識変数名の実際の長さの表です。標識変数名はバインド変数にのみ対応付けできます。この表はバインド記述子でのみ使用できます。
DESCRIBE BIND VARIABLESは、この表を、各標識変数名の文字数に設定します。
SELDFCLP | BNDDFCLP
SELDFCLP | BNDDFCLPは、将来の使用のために確保されている表です。Oracleはグループ項目SELDSCまたはBNDDSCが特定のサイズであるとみなすため、この表が必要となります。現在はSELDFCLPおよびBNDDFCLPの要素を0 (ゼロ)に設定する必要があります。
SELDFCRCP | BNDDFCRCP
11.4 前提知識
11.4.1 SQLADRの使用方法
入力値および出力値を格納するデータ・バッファのアドレスを取得するには、ライブラリ・サブルーチンSQLADRをコールする必要があります。取得したアドレスをバインドSQLDAまたは選択SQLDAに格納すると、Oracleはバインド変数値の読取り元や選択リスト値の書込み先を認識できるようになります。
CALL "SQLADR" USING BUFFER, ADDRESS.
各パラメータの意味は次のとおりです。
- BUFFER
-
選択リスト項目、バインド変数または標識変数の値または名前を格納するデータ・バッファ。
- ADDRESS
-
データ・バッファのアドレスを戻す整変数。
SQLADRをコールすると、BUFFERのアドレスがADDRESSに格納されます。次の例では、SQLADRを使用して、選択記述子表SELDV、SELDH-VNAME、SELDIを初期化します。これらの表の要素によって、選択リスト値、選択リスト名、インジケータ値のデータ・バッファのアドレスが指定されます。
PROCEDURE DIVISION. ... PERFORM INIT-SELDSC VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN SELDSC. ... INIT-SELDSC. CALL "SQLADR" USING SEL-DV(J), SELDV(J). CALL "SQLADR" USING SEL-DH-VNAME(J), SELDH-VNAME(J). CALL "SQLADR" USING SEL-DI(J), SELDI(J).
11.4.2 データの変換
この項では、データ型記述子表を詳しく説明します。データ型の同値化も動的SQL方法4も使用しないホスト・プログラムでは、内部データ型と外部データ型の間の変換はプリコンパイル時に決定されます。デフォルトでは、Pro*COBOLによって各ホスト変数に特定の外部データ型が割り当てられます。たとえば、型PIC S9(n) COMPのホスト変数にはINTEGER外部データ型がPro*COBOLにより割り当てられます。
しかし方法4を使用すると、データの変換および形式を制御できます。変換の指定は、データ型記述子表のデータ型コードを設定して行います。
内部データ型
内部データ型により、Oracleが疑似列値の表現のためにデータベース表に列値を格納する際の形式が指定されます。
DESCRIBE SELECT LISTコマンドを発行すると、Oracleは各選択リスト項目の内部データ型コードをSELDVTYP (データ型)記述子表に戻します。たとえば、J番目の選択リスト項目のデータ型コードはSELDVTYP(J)に戻されます。
表11-1は、内部のデータ型およびそのコードを示しています。
表11-1 内部のデータ型および関連コード
内部データ型 | コード |
---|---|
VARCHAR2 NUMBER LONG ROWID DATE RAW LONG RAW CHAR |
1 2 8 11 12 23 24 96 |
外部データ型
外部データ型には、入力ホスト変数および出力ホスト変数に値を格納するのに使用する形式を指定します。
DESCRIBE BIND VARIABLESコマンドは、データ型コードのBNDDVTYP表を0 (ゼロ)に設定します。このため、OPENコマンドを発行する前にそれらのコードを再設定する必要があります。データ型コードは、様々なバインド変数にどの外部データ型が使用されるかをOracleに知らせます。J番目のバインド変数の外部データ型を指定するには、BNDDVTYP(J)を希望する外部データ型に再設定してください。
次の表は、外部データ型とそのコード、および対応するCOBOLデータ型を示したものです。
表11-2 Oracleの外部データ型および関連するCOBOLデータ型
名前 | コード | COBOLデータ型 |
---|---|---|
VARCHAR2 |
1 |
PIC X(n)(MODE=ANSIの場合) |
NUMBER |
2 |
PIC X(n) |
INTEGER |
3 |
PIC S9(n) COMP (SPARC Solaris 64ビット・プラットフォームでは、COMP5ではなく、COMPを使用します。) PIC S9(n) COMP5 (バイトスワップ・プラットフォームの場合はCOMP5) |
FLOAT |
4 |
COMP-1 COMP-2 |
STRING (1) |
5 |
PIC X(n) |
VARNUM |
6 |
PIC X(n) |
DECIMAL |
7 |
PIC S9(n)V9(n) COMP-3 |
LONG |
8 |
PIC X(n) |
VARCHAR (2) |
9 |
PIC X(n) VARYING PIC N(n) VARYING |
ROWID |
11 |
PIC X(n) |
DATE |
12 |
PIC X(n) |
VARRAW (2) |
15 |
PIC X(n) |
RAW |
23 |
PIC X(n) |
LONG RAW |
24 |
PIC X(n) |
UNSIGNED |
68 |
(サポートされていません) |
DISPLAY |
91 |
PIC S9...9V9...9 DISPLAY SIGN LEADING SEPARATE PIC S9(n)V9(n) DISPLAY SIGN LEADING SEPARATE |
LONG VARCHAR (2) |
94 |
PIC X(n) |
LONG VARRAW (2) |
95 |
PIC X(n) |
CHARF |
96 |
PIC X(n)(MODE=ANSIの場合) PIC N(n)(MODE=ANSIの場合) |
CHARZ (1) |
97 |
PIC X(n) |
CURSOR |
102 |
SQL-CURSOR |
ノート:
-
EXEC SQL VAR文でのみ使用します。
-
nバイトの長さフィールドを含みます。
データ型およびその書式の詳細は、「Oracle Databaseのデータ型」を参照してください。
PL/SQLのデータ型
PL/SQLでは、各種の事前定義済スカラー・データ型および複合データ型を使用できます。スカラー型には内部コンポーネントはありません。複合型には、個々に操作できる内部コンポーネントがあります。「記述子の初期化」は、事前定義済のPL/SQLのスカラー・データ型およびそれに相当する内部データ型を示しています
表11-3 PL/SQLのデータ型とそれに相当する内部データ型
PL/SQLデータ型 | Oracle内部データ型 |
---|---|
VARCHAR VARCHAR2 |
VARCHAR2 |
BINARY_INTEGER DEC DECIMAL DOUBLE PRECISION FLOAT INT INTEGER NATURAL NUMBER NUMERIC POSITIVE REAL SMALLINT |
NUMBER |
LONG |
LONG |
ROWID |
ROWID |
DATE |
DATE |
RAW |
RAW |
LONG RAW |
LONG RAW |
CHAR CHARACTER STRING |
CHAR |
11.4.3 データ型の強制変換
選択記述子の場合、DESCRIBE SELECT LISTはいずれの内部データ型も戻すことができます。文字データの場合など、ほとんどの場合内部データ型は適切な外部データ型と正確に対応しています。ただし、内部データ型には扱いにくい外部データ型にマップするものもあります。このため、SELDVTYP記述子表の要素の中には再設定が必要なものもあります。
たとえば、NUMBER値をFLOAT値(これはCOBOLのPIC S9(n)V9(n) COMP-1値に対応)に再設定します。Oracleは、内部データ型と外部データ型の間の必要な変換をFETCH時に行います。データ型の再設定は必ずDESCRIBE SELECT LISTの後、FETCHの前に行ってください。
バインド記述子の場合は、DESCRIBE BIND VARIABLESによってバインド変数のデータ型が戻されることはなく、バインド変数の数および名前のみ戻されます。したがって、データ型コードのBNDDVTYP表を明示的に設定して、各バインド変数の外部データ型をOracleに認識させる必要があります。Oracleは、内部データ型と外部データ型の間の必要な変換をOPEN時に行います。
SELDVTYPまたはBNDDVTYPの記述子表でデータ型コードをリセットするときに、データ型を強制変換します。たとえば、J番目の選択リスト値をVARCHAR2に強制変換するには、次の文を使用します。
* Coerce select-list value to VARCHAR2. MOVE 1 TO SELDVTYP(J).
表示を目的としてNUMBER選択リスト値をVARCHAR2に強制変換する場合は、その値の精度および位取りのバイトを抽出し、その情報を使用して最大表示長を算出する必要があります。その後、FETCHを行う前にSELDVLN (長さ)記述子表の該当する要素を再設定して、使用するバッファの長さをOracleに認識させる必要があります。J番目の選択リスト値の長さを指定するには、SELDVLN(J)を必要な長さに設定します。
たとえば、DESCRIBE SELECT LISTでJ番目の選択リスト項目の型がNUMBERであるとわかった場合、戻り値をPIC S9(n)V9(n) COMP-1として宣言したCOBOL変数に格納するには、SELDVTYP(J)を4に設定し、SELDVLN(J)をシステムが定めるCOMP-1数値の長さに設定します。
例外
DESCRIBE SELECT LISTによって戻される内部データ型が、目的に合わない場合もあります。DATE型およびNUMBER型がその例です。DATE選択リスト項目をDESCRIBEすると、Oracleはデータ型コード12をSELDVTYP表に戻します。FETCHの前にコードを再設定しないかぎり、日付の値はその7バイト内部形式で戻されます。デフォルトの文字形式で日付を取得するには、データ型コードを12から1 (VARCHAR2)に変更して、SELDVLNの値を7から9に増やす必要があります。
同様に、NUMBER選択リスト項目をDESCRIBEすると、Oracleはデータ型コード2をSELDVTYP表に戻します。FETCHの前にコードを再設定しないかぎり、数値はその内部形式で戻されるため、求めている値と異なる可能性が高くなります。このような場合は、コードを2から1 (VARCHAR2)、3 (INTEGER)または4 (FLOAT)に変更するか、その他の適切なデータ型に変更してください。
精度および位取りの抽出
ライブラリ・サブルーチンSQLPRCにより、精度および位取りが抽出されます。このサブルーチンは通常、DESCRIBE SELECT LISTの後で使用され、その最初のパラメータはSELDVLN(J)です。次の構文で、SQLPRCをコールします。
CALL "SQLPRC" USING LENGTH, PRECISION, SCALE.
各パラメータの意味は次のとおりです。
構文 | 説明 |
---|---|
LENGTH |
NUMBER値の長さが格納される整変数。値の位取りおよび精度はそれぞれ、下位バイトおよびその上のバイトに格納されます。 |
PRECISION |
NUMBER値の精度を戻す整変数。精度とは有効桁数を指します。サイズが未指定のNUMBERが選択リスト項目によって参照される場合は、precisionの値は0 (ゼロ)に設定されます。この場合、サイズが未指定なので、最大精度の38とみなされます。 |
SCALE |
NUMBER値の位取りを戻す整変数。位取りには四捨五入する位置を指定します。たとえば、位取りが2の場合は最も近い100分の1の位に値が四捨五入され(3.456は3.46となります)、位取りが-3の場合は最も近い1000の位に値が四捨五入されます(3.456は3000となります)。 |
次の例に、SQLPRCを使用して、VARCHAR2に強制変換されるNUMBER値の最大表示長を算出する方法を示します。
WORKING-STORAGE SECTION. 01 PRECISION PIC S9(9) COMP. 01 SCALE PIC S9(9) COMP. 01 DISPLAY-LENGTH PIC S9(9) COMP. 01 MAX-LENGTH PIC S9(9) COMP VALUE 80. ... PROCEDURE DIVISION. ... PERFORM ADJUST-LENGTH VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN SELDSC. ADJUST-LENGTH. * If datatype is NUMBER, extract precision and scale. IF SELDVTYP(J) = 2 CALL "SQLPRC" USING SELDVLN(J), PRECISION, SCALE. MOVE 0 TO DISPLAY-LENGTH. * Precision is set to zero if the select-list item * refers to a NUMBER of unspecified size. We allow for * a maximum precision of 10. IF SELDVTYP(J) = 2 AND PRECISION = 0 MOVE 10 TO DISPLAY-LENGTH. * Allow for possible decimal point and sign. IF SELDVTYP(J) = 2 AND PRECISION > 0 ADD 2 TO PRECISION MOVE PRECISION TO DISPLAY-LENGTH. ...
このサブルーチン・コールの最初のパラメータは、選択リストの長さの表のJ番目の要素になるので注意してください。
SQLPRCプロシージャ(これはSQLLIBランタイム・ライブラリで定義されています)により、特定のSQLデータ型については精度および位取りの値として0 (ゼロ)が戻されます。SQLPR2プロシージャは、この表に示すデータ型を除けば、同じ構文で同じバイナリ値を戻すという点でSQLPRCに似ています。
表11-4 SQLPR2プロシージャのデータ型の例外
SQLデータ型 | 2進数精度 | 2進数位取り |
---|---|---|
FLOAT |
126 |
-127 |
FLOAT(n) |
n(1から126) |
-127 |
REAL |
63 |
-127 |
DOUBLE PRECISION |
126 |
-127 |
11.4.4 NULLまたはNOT NULLデータ型の処理
すべての選択リスト列(式は不可)について、DESCRIBE SELECT LISTは選択記述子のデータ型表にNULL/NOT NULLインジケータを戻します。J番目の選択リスト列にNOT NULL制約が指定されていると、SELDVTYP(J)データ型変数の上位ビットはクリアされます。それ以外の場合は上位ビットが設定されます。
NULLステータス・ビットがセットされている場合、OPEN文またはFETCH文でデータ型を使用する前にクリアする必要があります。このビットはセットしないでください。
ライブラリ・ルーチンSQLNULを使用して、列にNULLデータ型を使用できるかどうかを調べたり、そのデータ型のNULLステータス・ビットをクリアできます。次の構文で、SQLNULをコールします。
CALL "SQLNUL" USING VALUE-TYPE, TYPE-CODE, NULL-STATUS.
各パラメータの意味は次のとおりです。
構文 | 説明 |
---|---|
VALUE-TYPE |
選択リスト列のデータ型コードを戻す2バイトの整変数。 |
TYPE-CODE |
選択リスト列のデータ型コードを戻す2バイトの整変数。上位ビットはクリアされます。 |
NULL-STATUS |
選択リスト列のNULL状態を戻す整変数。1は列がNULLを許可し、0は許可しないことを意味します。 |
WORKING-STORAGE SECTION. ... * Declare variable for subroutine call. 01 NULL-STATUS PIC S9(9) COMP. ... PROCEDURE DIVISION. MAIN. EXEC SQL WHENEVER SQLERROR GOTO SQL-ERROR END-EXEC. ... PERFORM HANDLE-NULLS VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN SELDSC. ... HANDLE-NULLS. * Find out if column is NOT NULL, and clear high-order bit. CALL "SQLNUL" USING SELDVTYP(J), SELDVTYP(J), NULL-STATUS. * If NULL-STATUS = 1, NULLs are allowed.
このサブルーチン・コールの最初のパラメータと2番目のパラメータが同じことに注意してください。この2つのパラメータはそれぞれ、NULLステータス・ビットが消去される前と後のデータ型変数です。
11.5 基本ステップ
方法4は任意の動的SQL文に使用できます。「方法4でのホスト表の使用」の例では、入力ホスト変数および出力ホスト変数をどのように扱うかわかるように問合せが処理されています。
このサンプル・プログラムでは次のステップに従って動的問合せを処理します。
- 問合せテキストを保存するためのホスト文字列を宣言します。
- 選択記述子およびバインド記述子を宣言します。
- DESCRIBEできる選択リスト項目およびプレースホルダの最大数を設定します。
- 選択記述子およびバインド記述子を初期化します。
- 問合せテキストをホスト文字列に格納します。
- ホスト文字列から問合せをPREPAREします。
- 問合せ用のカーソルをDECLAREします。
- バインド記述子にバインド変数をDESCRIBEします。
- プレースホルダの数を、DESCRIBEで実際に検出された数に再設定します。
- DESCRIBEで検出されたバインド変数の値を取得します。
- バインド記述子を使用してカーソルをOPENします。
- 選択記述子に選択リストをDESCRIBEします。
- 選択リスト項目の最大数をDESCRIBEにより実際に検出された数に再設定します。
- 表示用にそれぞれの選択リスト項目の長さおよびデータ型を再設定します。
- 選択記述子を使用してデータベースからデータ・バッファに行をFETCH INTOします。
- FETCHにより戻された選択リストの値を処理します。
- FETCHする行がなくなった場合カーソルをCLOSEします。
ノート:
動的SQL文が問合せではない場合、または個数がわかっている選択リスト項目またはプレースホルダを含む場合は、前述の一部のステップは必要ありません。
関連項目
11.6 各ステップの詳細
この項では、個々のステップを詳しく説明します。方法4の完全なサンプル・プログラムをこの章の最後に示します。方法4では、埋込みSQL文を次のような順序で使用します。
EXEC SQL PREPARE <statement_name> FROM {:<host_string> | <string_literal>} END-EXEC. EXEC SQL DECLARE <cursor_name> CURSOR FOR <statement_name> END-EXEC. EXEC SQL DESCRIBE BIND VARIABLES FOR <statement_name> INTO <bind_descriptor_name> END-EXEC. EXEC SQL OPEN <cursor_name> [USING DESCRIPTOR <bind_descriptor_name>] END-EXEC. EXEC SQL DESCRIBE [SELECT LIST FOR] <statement_name> INTO <select_descriptor_name> END-EXEC. EXEC SQL FETCH <cursor_name> USING DESCRIPTOR <select_descriptor_name> END-EXEC. EXEC SQL CLOSE <cursor_name> END-EXEC.
動的問合せの選択リスト項目の数がわかっているときは、DESCRIBE SELECT LISTを省略するとともに次の方法3のFETCH文を使用できます。
EXEC SQL FETCH <cursor_name> INTO <host_variable_list> END-EXEC.
また、動的SQL文中のバインド変数のプレースホルダの数がわかっている場合は、DESCRIBE BIND VARIABLESを使用せずに、次に示す方法3のOPEN文を使用できます。
EXEC SQL OPEN <cursor_name> [USING <host_variable_list>] END-EXEC.
次の項では、これらの文により、記述子を使用してホスト・プログラムで動的SQL文を受け入れ、それを処理する方法を説明します。
ノート:
以降では、図を使用して説明します。図が複雑になるのを避けるため、記述子表の要素は3つまで、名前および値の最大長はそれぞれ5文字と10文字に制限しました。
11.6.1 ホスト文字列の宣言
プログラムには、動的SQL文のテキストを格納するためのホスト変数が必要です。このホスト変数(例ではSELECTSTMT)は、文字列として宣言する必要があります。
EXEC SQL BEGIN DECLARE SECTION END-EXEC. ... 01 SELECTSTMT PIC X(120). EXEC SQL END DECLARE SECTION END-EXEC.
11.6.2 SQLDAの宣言
例では、問合せの選択リスト項目またはプレースホルダの数が不明な場合があるため、選択記述子およびバインド記述子を宣言する必要があります。SQLDAをハードコードするかわりに、次のように、INCLUDEを使用してSQLDAをプログラムにコピーします。
EXEC SQL INCLUDE SELDSC END-EXEC. EXEC SQL INCLUDE BNDDSC END-EXEC.
参考のため、INCLUDEされるSELDSCの宣言を次に示します。
WORKING-STORAGE SECTION. ... 01 SELDSC. 05 SQLDNUM PIC S9(9) COMP. 05 SQLDFND PIC S9(9) COMP. 05 SELDVAR OCCURS 3 TIMES. 10 SELDV PIC S9(9) COMP. 10 SELDFMT PIC S9(9) COMP. 10 SELDVLN PIC S9(9) COMP. 10 SELDFMTL PIC S9(4) COMP. 10 SELDVTYP PIC S9(4) COMP. 10 SELDI PIC S9(9) COMP. 10 SELDH-VNAME PIC S9(9) COMP. 10 SELDH-MAX-VNAMEL PIC S9(4) COMP. 10 SELDH-CUR-VNAMEL PIC S9(4) COMP. 10 SELDI-VNAME PIC S9(9) COMP. 10 SELDI-MAX-VNAMEL PIC S9(4) COMP. 10 SELDI-CUR-VNAMEL PIC S9(4) COMP. 10 SELDFCLP PIC S9(9) COMP. 10 SELDFCRCP PIC S9(9) COMP. 01 XSELDI. 05 SEL-DI OCCURS 3 TIMES PIC S9(9) COMP. 01 XSELDIVNAME. 05 SEL-DI-VNAME OCCURS 3 TIMES PIC X(5). 01 XSELDV. 05 SEL-DV OCCURS 3 TIMES PIC X(10). 01 XSELDHVNAME. 05 SEL-DH-VNAME OCCURS 3 TIMES PIC X(5).
11.6.3 DESCRIBEへの最大数の設定
次に、記述できる選択リスト項目またはプレースホルダの最大数を設定します。
MOVE 3 TO SQLDNUM IN SELDSC. MOVE 3 TO SQLDNUM IN BNDDSC.
11.6.4 記述子の初期化
初期化を必要とする記述子変数もあります。また、初期化にライブラリ・サブルーチンSQLADRが必要なものもあります。
例では、名前バッファの最大長がSELDH-MAX-VNAMEL表、BNDDH-MAX-VNAMELおよびBNDDI-MAX-VNAMEL表に格納され、SQLADRを使用して値バッファおよび名前バッファのアドレスが表SELDV、SELDI、BNDDV、BNDDI、SELDH-VNAME、BNDDH-VNAMEおよびBNDDI-VNAMEに格納されています。
PROCEDURE DIVISION. ... PERFORM INIT-SELDSC VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN SELDSC. PERFORM INIT-BNDDSC VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN BNDDSC. ... INIT-SELDSC. MOVE SPACES TO SEL-DV(J). MOVE SPACES TO SEL-DH-VNAME(J). MOVE 5 TO SELDH-MAX-VNAMEL(J). CALL "SQLADR" USING SEL-DV(J), SELDV(J). CALL "SQLADR" USING SEL-DH-VNAME(J), SELDH-VNAME(J). CALL "SQLADR" USING SEL-DI(J), SELDI(J). ... INIT-BNDDSC. MOVE SPACES TO BND-DV(J). MOVE SPACES TO BND-DH-VNAME(J). MOVE SPACES TO BND-DI-VNAME(J). MOVE 5 TO BNDDH-MAX-VNAMEL(J). MOVE 5 TO BNDDI-MAX-VNAMEL(J). CALL "SQLADR" USING BND-DV(J), BNDDV(J). CALL "SQLADR" USING BND-DH-VNAME(J), BNDDH-VNAME(J). CALL "SQLADR" USING BND-DI(J), BNDDI(J). CALL "SQLADR" USING BND-DI-VNAME(J), BNDDI-VNAME(J). ...
11.6.5 ホスト文字列への問合せテキストの格納
次に、ユーザーにSQL文の入力を要求し、入力された文字列をSELECTSTMTに格納します。
DISPLAY "Enter a SELECT statement: " WITH NO ADVANCING. ACCEPT SELECTSTMT.
このときユーザーが次の文字列を入力したと仮定します。
SELECT ENAME, EMPNO, COMM FROM EMP WHERE COMM < :BONUS
11.6.7 カーソルのDECLARE
DECLARE CURSORは名前を指定し、特定のSELECT文に対応付けることにより、カーソルを定義します。
EXEC SQL DECLARE cursor_name CURSOR FOR SELECT ...
動的問合せ用にカーソルを宣言するには、PREPAREにより動的問合せに指定された文の名前で静的問合せを置換します。例では、次に示すように、DECLARE CURSORはEMPCURSORの名前のカーソルを定義し、それをSQLSTMTと対応付けます。
EXEC SQL DECLARE EMPCURSOR CURSOR FOR SQLSTMT END-EXEC.
ノート:
問合せのみでなく、すべての動的SQL文にカーソルを宣言する必要があります。また、問合せ以外の場合も、カーソルのOPENにより動的SQL文を実行します。
11.6.8 バインド変数のDESCRIBE
DESCRIBE BIND VARIABLESは、バインド変数の記述をバインド記述子に格納します。例では、DESCRIBEでBNDDSCを準備します。
EXEC SQL DESCRIBE BIND VARIABLES FOR SQLSTMT INTO BNDDSC END-EXEC.
BNDDSCの前にはコロンを付けないでください。
DESCRIBE BIND VARIABLES文はPREPARE文の後で、かつOPEN文の前に指定する必要があります。
図11-5に、DESCRIBE実行後のバインド記述子の例を示します。DESCRIBEにより、処理対象のSQL文で検出されたプレースホルダの実際の数に、SQLDFNDが設定されていることに注意してください。
11.6.9 プレースホルダの数の再設定
次に、プレースホルダの最大数を、DESCRIBEで実際に検出された数に再設定する必要があります。
IF SQLDFND IN BNDDSC < 0 DISPLAY "Too many bind variables" GOTO ROLL-BACK ELSE MOVE SQLDFND IN BNDDSC TO SQLDNUM IN BNDDSC END-IF.
11.6.10 バインド変数の値の取得
プログラムはSQL文中のバインド変数の値を取得する必要があります。値はどのように取得してもかまいません。たとえば値をハードコードしたり、ファイルから読み込むことや対話形式で入力することもできます。
例では、問合せのWHERE句のプレースホルダBONUSに置き換わるバインド変数に値を代入する必要があります。次のように、ユーザーに値の入力を求め、入力された値を処理します。
PROCEDURE DIVISION. ... PERFORM GET-INPUT-VAR VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN BNDDSC. ... GET-INPUT-VAR. ... * Replace the 0 DESCRIBEd into the datatype table * with a 1 to avoid an "invalid datatype" Oracle error. MOVE 1 TO BNDDVTYP(J). * Get value of bind variable. DISPLAY "Enter value of ", BND-DH-VNAME(J). ACCEPT INPUT-STRING. UNSTRING INPUT-STRING DELIMITED BY " " INTO BND-DV(J) COUNT IN BNDDVLN(J).
ここでは、ユーザーがBONUSの値として625を入力したとして、次の表に結果として得られるバインド記述子を示します。
11.6.11 カーソルのOPEN
動的問合せのOPEN文は、カーソルがバインド記述子に対応付けられることを除けば、静的問合せのOPEN文と同じです。実行時に決定され、バインド記述子表の要素でアドレス指定されたバッファに格納された値を使用して、SQL文を評価します。問合せの場合は、アクティブ・セットの識別にも同じ値を使用します。
例では、OPENがEMPCURSORをBNDDSCに対応付けています。
EXEC SQL OPEN EMPCUR USING DESCRIPTOR BNDDSC END-EXEC.
BNDDSCの前にはコロンを付けないでください。
OPENはSQL文を実行します。問合せのときは、OPENはアクティブ・セットを決定するとともにカーソルを先頭行に位置づけます。
11.6.12 選択リストのDESCRIBE
動的SQL文が問合せのときは、DESCRIBE SELECT LIST文はOPEN文の後で、かつFETCH文の前に指定する必要があります。
DESCRIBE SELECT LISTは、選択リスト項目の記述を選択記述子に格納します。例では、DESCRIBEによってSELDSCを準備しています。
EXEC SQL DESCRIBE SELECT LIST FOR SQLSTMT INTO SELDSC END-EXEC.
DESCRIBEは、データ・ディクショナリにアクセスして、各選択リスト値の長さおよびデータ型を設定します。
図11-7に、DESCRIBE実行後の選択記述子の例を示します。DESCRIBEにより、問合せの選択リストで実際に検出された項目の数に、SQLDFNDが設定されていることに注意してください。SQL文が問合せではない場合は、SQLDFNDは0 (ゼロ)に設定されます。また、NUMBER型の長さはまだ使用できないことに注意してください。NUMBERとして定義された列については、ライブラリ・サブルーチンSQLPRCを使用して精度および位取りを抽出する必要があります。「データ型の強制変換」の項を参照してください。
関連項目
11.6.13 選択リスト項目の最大数の再設定
次に選択リスト項目の最大数を、DESCRIBEにより実際に検出された数に再設定する必要があります。
MOVE SQLDFND IN SELDSC TO SQLDNUM IN SELDSC.
11.6.14 各選択リスト項目の長さおよびデータ型の再設定
例では、選択リストの値をフェッチする前に、長さおよびデータ型の表の要素の一部を表示するために再設定します。
PROCEDURE DIVISION. ... PERFORM COERCE-COLUMN-TYPE VARYING J FROM 1 BY 1 UNTIL J > SQLDNUM IN SELDSC. ... COERCE-COLUMN-TYPE. * Clear NULL bit. CALL "SQLNUL" USING SELDVTYP(J), SELDVTYP(J), NULL-STATUS. * If datatype is DATE, lengthen to 9 characters. IF SELDVTYP(J) = 12 MOVE 9 TO SELDVLN(J). * If datatype is NUMBER, extract precision and scale. MOVE 0 TO DISPLAY-LENGTH. IF SELDVTYP(J) = 2 AND PRECISION = 0 MOVE 10 TO DISPLAY-LENGTH. IF SELDVTYP(J) = 2 AND PRECISION > 0 ADD 2 TO PRECISION MOVE PRECISION TO DISPLAY-LENGTH. IF SELDVTYP(J) = 2 IF DISPLAY-LENGTH > MAX-LENGTH DISPLAY "Column value too large for data buffer." GO TO END-PROGRAM ELSE MOVE DISPLAY-LENGTH TO SELDVLN(J). * Coerce datatypes to VARCHAR2. MOVE 1 TO SELDVTYP(J).
図11-8に、結果として得られる選択記述子を示します。NUMBERの長さが使用でき、すべてのデータ型がVARCHAR2になっていることに注意してください。符号と小数点を使用できるよう、DESCRIBEした長さ4および7をそれぞれ2ずつ増加させたため、SELDVLN(2)およびSELDVLN(3)の長さが6および9になっています。
11.6.15 アクティブ・セットからの行のFETCH
FETCHはアクティブ・セットから1行を戻し、データ・バッファに選択リストの値を格納してから、カーソルをアクティブ・セットの次の行に進めます。行がなくなると、FETCHは「データが見つかりません。」のエラー・コードをSQLCAのSQLCODE、SQLCODE変数、またはSQLSTATE変数に設定します。次の例では、FETCHはENAME列、EMPNO列、およびCOMM列からSELDSC列の値を戻します。
EXEC SQL FETCH EMPCURSOR USING DESCRIPTOR SELDSC END-EXEC.
「FETCH実行後の選択記述子」に、FETCH実行後の選択記述子の例を示します。Oracleが、SELDVおよびSELDIの要素によってアドレス指定されたデータ・バッファに、選択リストおよびインジケータの値を格納していることに注意してください。
データ型1の出力バッファの場合、OracleはSELDVLNに格納されている長さを使用して、CHARデータまたはVARCHAR2データは左揃えにし、NUMBERデータは右揃えにします。
値MARTIN
は、EMP表のVARCHAR2(10)列から取り出されました。Oracleは、SELDVLN(1)に格納された長さを使用して、この値を10バイトのフィールドに左揃えにして入れ、バッファの残りの部分を埋めます。
値7654はNUMBER(4)列から取り出され、7654
に強制変換されています。しかし、SELDVLN(2)の長さが2増加して符号および小数点を使用できるようになっているため、Oracleでは6バイトのフィールドで値が右揃えになります。
値482.50はNUMBER(7,2)列から取り出され、482.50に強制変換されています。ここでも、SELDVLN(3)の長さが2増加しているため、Oracleでは9バイトのフィールドで値が右揃えになります。
11.7 方法4でのホスト表の使用
方法4で入力ホスト表または出力ホスト表を使用するには、オプションのFOR句を使用してホスト表のサイズをOracleに認識させる必要があります。FOR句の詳細は、「ホスト表」を参照してください。
J番目の選択リスト項目またはバインド変数の記述子エントリを設定します。ただし、SELDVLN(J)またはBNDDVLN(J)は、単一のデータ・バッファをアドレス指定するのではなく、データ・バッファの表をアドレス指定します。EXECUTE文またはFETCH文のいずれか適切な方にFOR句を指定して、処理対象の表要素の数をOracleに通知する必要があります。
Oracleがホスト表のサイズを認識する方法は他にないため、このステップは必須です。
次の例(32ビットのみ)では、2つの入力ホスト表を使用して、EMPNOおよびDEPTNOの8組の値をEMP表に挿入します。方法4では、問合せ以外のSQL文に対してEXECUTEを使用できるので注意してください。
IDENTIFICATION DIVISION. PROGRAM-ID. DYN4INS. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 BNDDSC. 02 SQLDNUM PIC S9(9) COMP VALUE 2. 02 SQLDFND PIC S9(9) COMP. 02 BNDDVAR OCCURS 2 TIMES. 03 BNDDV PIC S9(9) COMP. 03 BNDDFMT PIC S9(9) COMP. 03 BNDDVLN PIC S9(9) COMP. 03 BNDDFMTL PIC S9(4) COMP. 03 BNDDVTYP PIC S9(4) COMP. 03 BNDDI PIC S9(9) COMP. 03 BNDDH-VNAME PIC S9(9) COMP. 03 BNDDH-MAX-VNAMEL PIC S9(4) COMP. 03 BNDDH-CUR-VNAMEL PIC S9(4) COMP. 03 BNDDI-VNAME PIC S9(9) COMP. 03 BNDDI-MAX-VNAMEL PIC S9(4) COMP. 03 BNDDI-CUR-VNAMEL PIC S9(4) COMP. 03 BNDDFCLP PIC S9(9) COMP. 03 BNDDFCRCP PIC S9(9) COMP. 01 XBNDDI. 03 BND-DI OCCURS 2 TIMES PIC S9(4) COMP. 01 XBNDDIVNAME. 03 BND-DI-VNAME OCCURS 2 TIMES PIC X(80). 01 XBNDDV. * Since you know what the SQL statement will be, you can set * up a two-dimensional table with a maximum of 2 columns and * 8 rows. Each element can be up to 10 characters long. (You * can alter these values according to your needs.) 03 BND-COLUMN OCCURS 2 TIMES. 05 BND-ELEMENT OCCURS 8 TIMES PIC X(10). 01 XBNDDHVNAME. 03 BND-DH-VNAME OCCURS 2 TIMES PIC X(80). 01 COLUMN-INDEX PIC 999. 01 ROW-INDEX PIC 999. 01 DUMMY-INTEGER PIC 9999. EXEC SQL BEGIN DECLARE SECTION END-EXEC. 01 USERNAME PIC X(20). 01 PASSWD PIC X(20). 01 DYN-STATEMENT PIC X(80). 01 NUMBER-OF-ROWS PIC S9(4) COMP. EXEC SQL END DECLARE SECTION END-EXEC. EXEC SQL INCLUDE SQLCA END-EXEC. PROCEDURE DIVISION. START-MAIN. EXEC SQL WHENEVER SQLERROR GOTO SQL-ERROR END-EXEC. MOVE "SCOTT" TO USERNAME. MOVE "TIGER" TO PASSWD. EXEC SQL CONNECT :USERNAME IDENTIFIED BY :PASSWD END-EXEC. DISPLAY "Connected to Oracle". * Initialize bind and select descriptors. PERFORM INIT-BNDDSC THRU INIT-BNDDSC-EXIT VARYING COLUMN-INDEX FROM 1 BY 1 UNTIL COLUMN-INDEX > 2. * Set up the SQL statement. MOVE SPACES TO DYN-STATEMENT. MOVE "INSERT INTO EMP(EMPNO, DEPTNO) VALUES(:EMPNO,:DEPTNO)" TO DYN-STATEMENT. DISPLAY DYN-STATEMENT. * Prepare the SQL statement. EXEC SQL PREPARE S1 FROM :DYN-STATEMENT END-EXEC. * Describe the bind variables. EXEC SQL DESCRIBE BIND VARIABLES FOR S1 INTO BNDDSC END-EXEC. PERFORM Z-BIND-TYPE THRU Z-BIND-TYPE-EXIT VARYING COLUMN-INDEX FROM 1 BY 1 UNTIL COLUMN-INDEX > 2. IF SQLDFND IN BNDDSC < 0 DISPLAY "TOO MANY BIND VARIABLES." GO TO SQL-ERROR ELSE DISPLAY "BIND VARS = " WITH NO ADVANCING MOVE SQLDFND IN BNDDSC TO DUMMY-INTEGER DISPLAY DUMMY-INTEGER MOVE SQLDFND IN BNDDSC TO SQLDNUM IN BNDDSC. MOVE 8 TO NUMBER-OF-ROWS. PERFORM GET-ALL-VALUES THRU GET-ALL-VALUES-EXIT VARYING ROW-INDEX FROM 1 BY 1 UNTIL ROW-INDEX > NUMBER-OF-ROWS. * Execute the SQL statement. EXEC SQL FOR :NUMBER-OF-ROWS EXECUTE S1 USING DESCRIPTOR BNDDSC END-EXEC. DISPLAY "INSERTED " WITH NO ADVANCING. MOVE SQLERRD(3) TO DUMMY-INTEGER. DISPLAY DUMMY-INTEGER WITH NO ADVANCING. DISPLAY " ROWS.". GO TO END-SQL. SQL-ERROR. * Display any SQL error message and code. DISPLAY SQLERRMC. EXEC SQL ROLLBACK WORK RELEASE END-EXEC. STOP RUN. END-SQL. EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC. EXEC SQL COMMIT WORK RELEASE END-EXEC. STOP RUN. INIT-BNDDSC. * Start of COBOL PERFORM procedures, initialize the bind * descriptor. MOVE 80 TO BNDDH-MAX-VNAMEL(COLUMN-INDEX). CALL "SQLADR" USING BND-DH-VNAME(COLUMN-INDEX) BNDDH-VNAME(COLUMN-INDEX). MOVE 80 TO BNDDI-MAX-VNAMEL(COLUMN-INDEX). CALL "SQLADR" USING BND-DI-VNAME(COLUMN-INDEX) BNDDI-VNAME (COLUMN-INDEX). MOVE 10 TO BNDDVLN(COLUMN-INDEX). CALL "SQLADR" USING BND-ELEMENT(COLUMN-INDEX,1) BNDDV(COLUMN-INDEX). MOVE ZERO TO BNDDI(COLUMN-INDEX). CALL "SQLADR" USING BND-DI(COLUMN-INDEX) BNDDI(COLUMN-INDEX). MOVE ZERO TO BNDDFMT(COLUMN-INDEX). MOVE ZERO TO BNDDFMTL(COLUMN-INDEX). MOVE ZERO TO BNDDFCLP(COLUMN-INDEX). MOVE ZERO TO BNDDFCRCP(COLUMN-INDEX). INIT-BNDDSC-EXIT. EXIT. Z-BIND-TYPE. * Replace the 0s DESCRIBEd into the datatype table with 1s to * avoid an "invalid datatype" Oracle error. MOVE 1 TO BNDDVTYP(COLUMN-INDEX). Z-BIND-TYPE-EXIT. EXIT. GET-ALL-VALUES. * Get the bind variables for each row. DISPLAY "ENTER VALUES FOR ROW NUMBER ",ROW-INDEX. PERFORM GET-BIND-VARS VARYING COLUMN-INDEX FROM 1 BY 1 UNTIL COLUMN-INDEX > SQLDFND IN BNDDSC. GET-ALL-VALUES-EXIT. EXIT. GET-BIND-VARS. * Get the value of each bind variable. DISPLAY " ENTER VALUE FOR ",BND-DH-VNAME(COLUMN-INDEX) WITH NO ADVANCING. ACCEPT BND-ELEMENT(COLUMN-INDEX,ROW-INDEX). GET-BIND-VARS-EXIT. EXIT.
関連項目
11.8 サンプル・プログラム10: 動的SQL方法4
このプログラムでは、動的SQL方法4の使用に必要な基本ステップを示します。
ノート:
次の例は32ビットのみです。問題を回避するには、$ORACLE_HOME/precomp/demo/procob2/sample10.pco
からの例を使用し、変数宣言ファイルの正しいバージョンを含めます。
bndsel.cob
(64ビット・バージョン)は、precomp/public
(64ビット・コンピュータ)にあります。
bndsel.cob_32
(32ビット・バージョン)は、precomp/public32
(64ビット・コンピュータ)にあります。
ログインすると、プログラムはSQL文のユーザーの入力を求め、文の準備を行い、カーソルを宣言し、DESCRIBE BINDを使用してバインド変数のチェックを行い、選択リスト変数を記述します。入力されたSQL文が問合せのときは、プログラムは各行のデータをフェッチしてからカーソルをクローズします。
*************************************************************** * Sample Program 10: Dynamic SQL Method 4 * * * * This program shows the basic steps required to use dynamic * * SQL Method 4. 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 BIND, 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. * *************************************************************** IDENTIFICATION DIVISION. PROGRAM-ID. DYNSQL4. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 BNDDSC. 02 SQLDNUM PIC S9(9) COMP VALUE 20. 02 SQLDFND PIC S9(9) COMP. 02 BNDDVAR OCCURS 20 TIMES. 03 BNDDV PIC S9(9) COMP. 03 BNDDFMT PIC S9(9) COMP. 03 BNDDVLN PIC S9(9) COMP. 03 BNDDFMTL PIC S9(4) COMP. 03 BNDDVTYP PIC S9(4) COMP. 03 BNDDI PIC S9(9) COMP. 03 BNDDH-VNAME PIC S9(9) COMP. 03 BNDDH-MAX-VNAMEL PIC S9(4) COMP. 03 BNDDH-CUR-VNAMEL PIC S9(4) COMP. 03 BNDDI-VNAME PIC S9(9) COMP. 03 BNDDI-MAX-VNAMEL PIC S9(4) COMP. 03 BNDDI-CUR-VNAMEL PIC S9(4) COMP. 03 BNDDFCLP PIC S9(9) COMP. 03 BNDDFCRCP PIC S9(9) COMP. 01 XBNDDI. 03 BND-DI OCCURS 20 TIMES PIC S9(4) COMP. 01 XBNDDIVNAME. 03 BND-DI-VNAME OCCURS 20 TIMES PIC X(80). 01 XBNDDV. 03 BND-DV OCCURS 20 TIMES PIC X(80). 01 XBNDDHVNAME. 03 BND-DH-VNAME OCCURS 20 TIMES PIC X(80). 01 SELDSC. 02 SQLDNUM PIC S9(9) COMP VALUE 20. 02 SQLDFND PIC S9(9) COMP. 02 SELDVAR OCCURS 20 TIMES. 03 SELDV PIC S9(9) COMP. 03 SELDFMT PIC S9(9) COMP. 03 SELDVLN PIC S9(9) COMP. 03 SELDFMTL PIC S9(4) COMP. 03 SELDVTYP PIC S9(4) COMP. 03 SELDI PIC S9(9) COMP. 03 SELDH-VNAME PIC S9(9) COMP. 03 SELDH-MAX-VNAMEL PIC S9(4) COMP. 03 SELDH-CUR-VNAMEL PIC S9(4) COMP. 03 SELDI-VNAME PIC S9(9) COMP. 03 SELDI-MAX-VNAMEL PIC S9(4) COMP. 03 SELDI-CUR-VNAMEL PIC S9(4) COMP. 03 SELDFCLP PIC S9(9) COMP. 03 SELDFCRCP PIC S9(9) COMP. 01 XSELDI. 03 SEL-DI OCCURS 20 TIMES PIC S9(4) COMP. 01 XSELDIVNAME. 03 SEL-DI-VNAME OCCURS 20 TIMES PIC X(80). 01 XSELDV. 03 SEL-DV OCCURS 20 TIMES PIC X(80). 01 XSELDHVNAME. 03 SEL-DH-VNAME OCCURS 20 TIMES PIC X(80). 01 TABLE-INDEX PIC 9(3). 01 VAR-COUNT PIC 9(2). 01 ROW-COUNT PIC 9(4). 01 NO-MORE-DATA PIC X(1) VALUE "N". 01 NULLS-ALLOWED PIC S9(9) COMP. 01 PRECISION PIC S9(9) COMP. 01 SCALE PIC S9(9) COMP. 01 DISPLAY-LENGTH PIC S9(9) COMP. 01 MAX-LENGTH PIC S9(9) COMP VALUE 80. 01 COLUMN-NAME PIC X(30). 01 NULL-VAL PIC X(80) VALUE SPACES. EXEC SQL BEGIN DECLARE SECTION END-EXEC. 01 USERNAME PIC X(20). 01 PASSWD PIC X(20). 01 DYN-STATEMENT PIC X(80). EXEC SQL END DECLARE SECTION END-EXEC. 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. * INITIALIZE THE BIND AND SELECT DESCRIPTORS. PERFORM INIT-BNDDSC VARYING TABLE-INDEX FROM 1 BY 1 UNTIL TABLE-INDEX > 20. PERFORM INIT-SELDSC VARYING TABLE-INDEX FROM 1 BY 1 UNTIL TABLE-INDEX > 20. * 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 ANY BIND VARIABLES. EXEC SQL DESCRIBE BIND VARIABLES FOR S1 INTO BNDDSC END-EXEC. IF SQLDFND IN BNDDSC < 0 DISPLAY "TOO MANY BIND VARIABLES." GO TO END-SQL ELSE DISPLAY "NUMBER OF BIND VARIABLES: " WITH NO ADVANCING MOVE SQLDFND IN BNDDSC TO VAR-COUNT DISPLAY VAR-COUNT MOVE SQLDFND IN BNDDSC TO SQLDNUM IN BNDDSC END-IF. * REPLACE THE 0S DESCRIBED INTO THE DATATYPE FIELDS OF THE * BIND DESCRIPTOR WITH 1S TO AVOID AN "INVALID DATATYPE" * ORACLE ERROR MOVE 1 TO TABLE-INDEX. FIX-BIND-TYPE. MOVE 1 TO BNDDVTYP(TABLE-INDEX) ADD 1 TO TABLE-INDEX IF TABLE-INDEX <= 20 GO TO FIX-BIND-TYPE. * LET THE USER FILL IN THE BIND VARIABLES. IF SQLDFND IN BNDDSC = 0 GO TO DESCRIBE-ITEMS. MOVE 1 TO TABLE-INDEX. GET-BIND-VAR. DISPLAY "ENTER VALUE FOR ", BND-DH-VNAME(TABLE-INDEX). ACCEPT BND-DV(TABLE-INDEX). ADD 1 TO TABLE-INDEX IF TABLE-INDEX <= SQLDFND IN BNDDSC GO TO GET-BIND-VAR. * OPEN THE CURSOR AND DESCRIBE THE SELECT-LIST ITEMS. DESCRIBE-ITEMS. EXEC SQL OPEN C1 USING DESCRIPTOR BNDDSC END-EXEC. EXEC SQL DESCRIBE SELECT LIST FOR S1 INTO SELDSC END-EXEC. IF SQLDFND IN SELDSC < 0 DISPLAY "TOO MANY SELECT-LIST ITEMS." GO TO END-SQL ELSE DISPLAY "NUMBER OF SELECT-LIST ITEMS: " WITH NO ADVANCING MOVE SQLDFND IN SELDSC TO VAR-COUNT DISPLAY VAR-COUNT DISPLAY " " MOVE SQLDFND IN SELDSC TO SQLDNUM IN SELDSC END-IF. * COERCE THE DATATYPE OF ALL SELECT-LIST ITEMS TO VARCHAR2. IF SQLDNUM IN SELDSC > 0 PERFORM COERCE-COLUMN-TYPE VARYING TABLE-INDEX FROM 1 BY 1 UNTIL TABLE-INDEX > SQLDNUM IN SELDSC DISPLAY " ". * FETCH EACH ROW AND PRINT EACH SELECT-LIST VALUE. IF SQLDNUM IN SELDSC > 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 COMMIT 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: * INIT-BNDDSC: INITIALIZE THE BIND DESCRIPTOR. INIT-BNDDSC. MOVE SPACES TO BND-DH-VNAME(TABLE-INDEX). MOVE 80 TO BNDDH-MAX-VNAMEL(TABLE-INDEX). CALL "SQLADR" USING BND-DH-VNAME(TABLE-INDEX) BNDDH-VNAME(TABLE-INDEX). MOVE SPACES TO BND-DI-VNAME(TABLE-INDEX). MOVE 80 TO BNDDI-MAX-VNAMEL(TABLE-INDEX). CALL "SQLADR" USING BND-DI-VNAME(TABLE-INDEX) BNDDI-VNAME (TABLE-INDEX). MOVE SPACES TO BND-DV(TABLE-INDEX). MOVE 80 TO BNDDVLN(TABLE-INDEX). CALL "SQLADR" USING BND-DV(TABLE-INDEX) BNDDV(TABLE-INDEX). MOVE ZERO TO BND-DI(TABLE-INDEX). CALL "SQLADR" USING BND-DI(TABLE-INDEX) BNDDI(TABLE-INDEX). MOVE ZERO TO BNDDFMT(TABLE-INDEX). MOVE ZERO TO BNDDFMTL(TABLE-INDEX). MOVE ZERO TO BNDDFCLP(TABLE-INDEX). MOVE ZERO TO BNDDFCRCP(TABLE-INDEX). * INIT-SELDSC: INITIALIZE THE SELECT DESCRIPTOR. INIT-SELDSC. MOVE SPACES TO SEL-DH-VNAME(TABLE-INDEX). MOVE 80 TO SELDH-MAX-VNAMEL(TABLE-INDEX). CALL "SQLADR" USING SEL-DH-VNAME(TABLE-INDEX) SELDH-VNAME(TABLE-INDEX). MOVE SPACES TO SEL-DI-VNAME(TABLE-INDEX). MOVE 80 TO SELDI-MAX-VNAMEL(TABLE-INDEX). CALL "SQLADR" USING SEL-DI-VNAME(TABLE-INDEX) SELDI-VNAME (TABLE-INDEX). MOVE SPACES TO SEL-DV(TABLE-INDEX). MOVE 80 TO SELDVLN(TABLE-INDEX). CALL "SQLADR" USING SEL-DV(TABLE-INDEX) SELDV(TABLE-INDEX). MOVE ZERO TO SEL-DI(TABLE-INDEX). CALL "SQLADR" USING SEL-DI(TABLE-INDEX) SELDI(TABLE-INDEX). MOVE ZERO TO SELDFMT(TABLE-INDEX). MOVE ZERO TO SELDFMTL(TABLE-INDEX). MOVE ZERO TO SELDFCLP(TABLE-INDEX). MOVE ZERO TO SELDFCRCP(TABLE-INDEX). * COERCE SELECT-LIST DATATYPES TO VARCHAR2. COERCE-COLUMN-TYPE. CALL "SQLNUL" USING SELDVTYP(TABLE-INDEX) SELDVTYP(TABLE-INDEX) NULLS-ALLOWED. * IF DATATYPE IS DATE, LENGTHEN TO 9 CHARACTERS. IF SELDVTYP(TABLE-INDEX) = 12 MOVE 9 TO SELDVLN(TABLE-INDEX). * IF DATATYPE IS NUMBER, SET LENGTH TO PRECISION. IF SELDVTYP(TABLE-INDEX) = 2 CALL "SQLPRC" USING SELDVLN(TABLE-INDEX) PRECISION SCALE. MOVE 0 TO DISPLAY-LENGTH. IF SELDVTYP(TABLE-INDEX) = 2 AND PRECISION = 0 MOVE 40 TO DISPLAY-LENGTH. IF SELDVTYP(TABLE-INDEX) = 2 AND PRECISION > 0 ADD 2 TO PRECISION MOVE PRECISION TO DISPLAY-LENGTH. IF SELDVTYP(TABLE-INDEX) = 2 IF DISPLAY-LENGTH > MAX-LENGTH DISPLAY "COLUMN VALUE TOO LARGE FOR DATA BUFFER." GO TO END-SQL ELSE MOVE DISPLAY-LENGTH TO SELDVLN(TABLE-INDEX). * COERCE DATATYPES TO VARCHAR2. MOVE 1 TO SELDVTYP(TABLE-INDEX). * DISPLAY COLUMN HEADING. MOVE SEL-DH-VNAME(TABLE-INDEX) TO COLUMN-NAME. DISPLAY COLUMN-NAME(1:SELDVLN(TABLE-INDEX)), " " WITH NO ADVANCING. *FETCH A ROW AND PRINT THE SELECT-LIST VALUE. FETCH-ROWS. EXEC SQL FETCH C1 USING DESCRIPTOR SELDSC END-EXEC. IF SQLCODE NOT = 0 MOVE "Y" TO NO-MORE-DATA. IF SQLCODE = 0 PERFORM PRINT-COLUMN-VALUES VARYING TABLE-INDEX FROM 1 BY 1 UNTIL TABLE-INDEX > SQLDNUM IN SELDSC DISPLAY " ". *PRINT A SELECT-LIST VALUE. PRINT-COLUMN-VALUES. IF SEL-DI(TABLE-INDEX) = -1 DISPLAY NULL-VAL(1:SELDVLN(TABLE-INDEX)), " " WITH NO ADVANCING ELSE DISPLAY SEL-DV(TABLE-INDEX)(1:SELDVLN(TABLE-INDEX)), " " WITH NO ADVANCING END-IF.