プライマリ・コンテンツに移動
Pro*C/C++プログラマーズ・ガイド
12c リリース1(12.1)
B71397-03
目次へ移動
目次
索引へ移動
索引

前
次

各手順の詳細

この項では、それぞれのステップを詳しく説明します。章の終わりには、方法4を使用したコメント付きの完全なプログラム例を示します。

方法4では、埋込みSQL文を次のような順序で使用します。

EXEC SQL PREPARE statement_name 
    FROM { :host_string | string_literal }; 
EXEC SQL DECLARE cursor_name CURSOR FOR statement_name; 
EXEC SQL DESCRIBE BIND VARIABLES FOR statement_name 
    INTO bind_descriptor_name; 
EXEC SQL OPEN cursor_name 
    [USING DESCRIPTOR bind_descriptor_name]; 
EXEC SQL DESCRIBE [SELECT LIST FOR] statement_name 
    INTO select_descriptor_name; 
EXEC SQL FETCH cursor_name 
    USING DESCRIPTOR select_descriptor_name; 
EXEC SQL CLOSE cursor_name; 

方法4では、スクロール可能カーソルも使用できます。スクロール可能カーソルには、埋込みSQL文を次の順序で使用する必要があります。

 EXEC SQL PREPARE statement_name 
           FROM { :host_string | string_literal }; 
 EXEC SQL DECLARE cursor_name SCROLL CURSOR FOR statement_name; 
 EXEC SQL DESCRIBE BIND VARIABLES  FOR statement_name 
           INTO bind_descriptor_name; 
 EXEC SQL OPEN cusor_name 
           [ USING DESCRIPTOR bind_descriptor_name]; 
 EXEC SQL DESCRIBE [ SELECT LIST FOR] statement_name 
           INTO select_descriptor_name; 
 EXEC SQL FETCH  [ FIRST| PRIOR|NEXT|LAST|CURRENT | RELATIVE fetch_offset 
           |ABSOLUTE fetch_offset ]  cursor_name USING DESCRIPTOR
            select_descriptor_name; 
 EXEC SQL CLOSE cursor_name;

動的問合せの選択リスト項目の数がわかっているときは、DESCRIBE SELECT LISTを省略するとともに次の方法3のFETCH文を使用できます。

EXEC SQL FETCH cursor_name INTO host_variable_list; 

または、動的SQL文のバインド変数に対するプレースホルダの数が明確な場合は、DESCRIBE BIND VARIABLESを省略するとともに次の方法3のOPEN文を使用できます。

EXEC SQL OPEN cursor_name [USING host_variable_list];
 

次にこれらの文により、ホスト・プログラムで記述子を使用して動的SQL文を受け入れ、それを処理する方法を説明します。

注意:

以降では、図を使用して説明します。図が複雑になるのを避けるために、次の条件を満たすことが必要です。

ホスト文字列の宣言

プログラムには、動的SQL文のテキストを格納するためのホスト変数が必要です。ホスト変数(ここではselect_stmt)は文字列として宣言する必要があります。

    ... 
    int      emp_number; 
    VARCHAR  emp_name[10]; 
    VARCHAR  select_stmt[120]; 
    float    bonus; 

SQLDAの宣言

ここでは、SQLDAのデータ構造体をハードコードするかわりに、次のようにINCLUDEを使用してSQLDAをプログラムにコピーします。

#include <sqlda.h>

問合せに含まれる選択リスト項目の数またはバインド変数のプレースホルダの数が不明なため、次のように選択記述子とバインド記述子のポインタを宣言します。

sqlda  *select_des; 
sqlda  *bind_des; 

記述子用の記憶域の割当て

記述子用の記憶域を割り当てるには、SQLSQLDAAlloc()ライブラリ関数を使用することを思い出してください。ANSI C表記法による構文は次のとおりです。

SQLDA *SQLSQLDAAlloc(dvoid *context, unsigned int max_vars, unsigned int
max_name, unsigned int max_ind_name);

SQLSQLDAAlloc()関数は、記述子構造体およびポインタ変数VLTIによってアドレス指定される配列を割り当てます。

max_nameが0(ゼロ)以外のときは、ポインタ変数SMCによってアドレス指定される配列が割り当てられます。max_ind_nameが0(ゼロ)以外のときは、ポインタ変数XYZによってアドレス指定される配列が割り当てられます。max_namemax_ind_nameが0(ゼロ)のときは、領域は割り当てられません。

SQLSQLDAAlloc()は、成功すると構造体のポインタを戻します。SQLSQLDAAlloc()は、失敗すると0(ゼロ)を戻します。

この例では、選択記述子とバインド記述子を次のように割り当てます。

select_des = SQLSQLDAAlloc(SQL_SINGLE_RCTX, 3, (size_t) 5, (size_t) 0); 
bind_des = SQLSQLDAAlloc(SQL_SINGLE_RCTX, 3, (size_t) 5, (size_t) 4); 

選択記述子には、Xによってアドレス指定される配列に領域が割り当てられないようにするため、常にmax_ind_nameを0(ゼロ)に設定します。

DESCRIBEへの最大数の設定

DESCRIBEできる選択リスト項目またはプレースホルダの最大数を次のように設定します。

select_des->N = 3; 
bind_des->N = 3; 

図15-2図15-3に、結果として得られる記述子を示します。

注意:

選択記述子の場合(図15-2)、標識変数名の選択は消されて使用されないことを示します。

図15-2 初期化された選択記述子

初期化された選択記述子
「図15-2 初期化された選択記述子」の説明

図15-3 初期化されたバインド記述子

初期化されたバインド記述子
「図15-3 初期化されたバインド記述子」の説明

ホスト文字列への問合せテキストの設定

次の例では、ユーザーにSQL文の入力を求め、入力された文字列をselect_stmtに格納します。

printf("\n\nEnter SQL statement: "); 
gets(select_stmt.arr); 
select_stmt.len = strlen(select_stmt.arr); 

このときユーザーが次の文字列を入力したと仮定します。

"SELECT ename, empno, comm FROM emp WHERE comm < :bonus" 

ホスト文字列からの問合せのPREPARE

PREPAREは、このSQL文を解析して名前を指定します。例では、PREPAREはホスト文字列select_stmtを解析してから、それにsql_stmtという名前を指定します。

EXEC SQL PREPARE sql_stmt FROM :select_stmt; 

カーソルのDECLARE

DECLARE CURSORは名前を指定し、特定のSELECT文に対応付けることにより、カーソルを定義します。

静的問合せ用のカーソルを宣言するには、次の構文を使用します。

EXEC SQL DECLARE cursor_name CURSOR FOR SELECT ... 

動的問合せ用にカーソルを宣言するには、PREPAREにより動的問合せに指定された文の名前で静的問合せを置換します。例では、DECLARE CURSORはemp_cursorという名前のカーソルを定義し、このカーソルをsql_stmtに対応付けます。

EXEC SQL DECLARE emp_cursor CURSOR FOR sql_stmt; 

注意:

問合せのみでなく、すべての動的SQL文のカーソルを宣言できます。また、問合せ以外の場合も、カーソルのOPENにより動的SQL文を実行します。

バインド変数のDESCRIBE

DESCRIBE BIND VARIABLESは、バインド記述子にプレースホルダの記述を設定します。例では、DESCRIBEは次のようにbind_desを準備します。

EXEC SQL DESCRIBE BIND VARIABLES FOR sql_stmt INTO bind_des; 

bind_desはコロンで始めることはできません

DESCRIBE BIND VARIABLES文はPREPARE文の後で、かつOPEN文の前に指定する必要があります。

図15-4に、DESCRIBE実行後のバインド記述子を示します。SQL文の実行で検出されたプレースホルダの実際の数が、DESCRIBEによってFに設定されています。

図15-4 DESCRIBE後のバインド記述子

DESCRIBE後のバインド記述子
「図15-4 DESCRIBE後のバインド記述子」の説明

プレースホルダの最大数の再設定

次に、プレースホルダの最大数を、DESCRIBEによって実際に検出された数に再設定する必要があります。

bind_des->N = bind_des->F; 

バインド変数の値の取得と記憶域の割当て

プログラムでは、SQL文で検出されたバインド変数に対する値を取得し、メモリーを割り当てる必要があります。値はどのように取得してもかまいません。たとえば値をハードコードしたり、ファイルから読み込んだり、または対話形式で入力することもできます。

例では、問合せのWHERE句のプレースホルダbonusに置換されるバインド変数に値を割り当てる必要があります。そこで、ユーザーに値の入力を求め、入力された値を次のように処理します。

for (i = 0; i < bind_des->F; i++) 
{ 
    printf("\nEnter value of bind variable %.*s:\n? ", 
        (int) bind_des->C[i], bind_des->S[i]); 
    gets(hostval); 
    /* Set length of value. */ 
    bind_des->L[i] = strlen(hostval); 
    /* Allocate storage for value and null terminator. */ 
    bind_des->V[i] = malloc(bind_des->L[i] + 1); 
    /* Allocate storage for indicator value. */ 
    bind_des->I[i] = (unsigned short *) malloc(sizeof(short)); 
    /* Store value in bind descriptor. */ 
    strcpy(bind_des->V[i], hostval); 
    /* Set value of indicator variable. */ 
    *(bind_des->I[i]) = 0;  /* or -1 if "null" is the value */ 
    /* Set datatype to STRING. */ 
    bind_des->T[i] = 5; 
} 

ここでは、ユーザーがbonusの値として625を入力したと想定します。図15-5に、結果として得られるバインド記述子を示します。値はヌル文字で終了します。

図15-5 値を割り当てた後のバインド記述子

値を割り当てた後のバインド記述子
「図15-5 値を割り当てた後のバインド記述子」の説明

カーソルのOPEN

動的問合せに使用するOPEN文は、カーソルがバインド記述子に対応付けられることを除けば静的問合せに使用するものと同じです。実行時に決定され、バインド記述子表の要素でアドレス指定したバッファに格納された値を使用して、SQL文を評価します。問合せの場合は、アクティブ・セットの識別にも同じ値を使用します。

例では、OPENは次のようにemp_cursorbind_desに対応付けます。

EXEC SQL OPEN emp_cursor USING DESCRIPTOR bind_des; 

bind_desはコロンで始めることはできません

OPENはSQL文を実行します。問合せのときは、OPENはアクティブ・セットを決定するとともにカーソルを先頭行に位置づけます。

選択リストのDESCRIBE

動的SQL文が問合せのときは、DESCRIBE SELECT LIST文はOPEN文の後で、かつFETCH文の前に指定する必要があります。

DESCRIBE SELECT LISTは、選択記述子に選択リスト項目の記述を設定します。例では、DESCRIBEは次のようにselect_desを準備します。

EXEC SQL DESCRIBE SELECT LIST FOR sql_stmt INTO select_des;
 

Oracleのデータ・ディクショナリにアクセスすることで、DESCRIBEは各選択リストの値の長さとデータ型を設定します。

図15-6に、DESCRIBE実行後の選択記述子を示します。問合せの選択リストで検出された項目の実際の数がDESCRIBEによってFに設定されています。SQL文が問合せでないときは、Fは0(ゼロ)に設定されます。

また、NUMBER型の長さはまだ使用できないことに注意してください。NUMBERと定義した列には、ライブラリ関数SQLNumberPrecV6()を使用して精度と位取りを抽出する必要があります。

図15-6 DESCRIBE実行後の選択記述子

DESCRIBE実行後の選択記述子
「図15-6 DESCRIBE実行後の選択記述子」の説明

選択リスト項目の最大数の再設定

次に選択リスト項目の最大数を、DESCRIBEにより実際に検出された数に再設定する必要があります。

select_des->N = select_des->F; 

各選択リスト項目の長さとデータ型の再設定

例では、選択リストの値をFETCHする前に、ライブラリ関数malloc()を使用して、記憶域を割り当てます。また、表示用の長さとデータ型の配列の要素のいくつかを再設定します。

for (i=0; i<select_des->F; i++) 
{ 
    /* Clear null bit. */ 
    SQLColumnNullCheck(SQL_SINGLE_RCTX, (unsigned short *)&(select_des->T[i]),
         (unsigned short *)&(select_des->T[i]), &nullok); 
    /* Reset length if necessary. */ 
    switch(select_des->T[i]) 
    { 
        case  1: break; 
        case  2: SQLNumberPrecV6(SQL_SINGLE_RCTX, (unsigned long *)
                      &(select_des->L[i]), &prec, &scal); 
                 if (prec == 0) prec = 40; 
                 select_des->L[i] = prec + 2; 
                 if (scal < 0) select_des->L[i] += -scal; 
                 break; 
        case  8: select_des->L[i] = 240; 
                 break; 
        case 11: select_des->L[i] = 18; 
                 break; 
        case 12: select_des->L[i] = 9; 
                 break; 
        case 23: break; 
        case 24: select_des->L[i] = 240; 
                 break; 
    } 
    /* Allocate storage for select-list value. */ 
    select_des->V[i] = malloc(select_des->L[i]+1); 
    /* Allocate storage for indicator value. */ 
    select_des->I[i] = (short *)malloc(sizeof(short *)); 
    /* Coerce all datatypes except LONG RAW to STRING. */ 
    if (select_des->T[i] != 24) select_des->T[i] = 5; 
} 

図15-7に、結果として得られる選択記述子を示します。NUMBERの長さはこのとき使用可能となります。データ型はすべてSTRINGです。L[1]およびL[2]の長さはそれぞれ6と9になっています。これは、DESCRIBEされた長さ4と7にそれぞれ符号と小数点のための2を加算したためです。

図15-7 FETCH前の選択記述子

FETCH前の選択記述子
「図15-7 FETCH前の選択記述子」の説明

アクティブ・セットからの行のFETCH

FETCHはアクティブ・セットから1行を戻し、データ・バッファに選択リストの値を格納してから、カーソルをアクティブ・セットの次の行に進めます。行がなくなると、FETCHは「データが見つかりません。」のOracleエラー・コードをsqlca.sqlcodeに設定します。例では、次に示すように、FETCHによってENAME、EMPNOおよびCOMMの列の値をselect_desに戻します。

EXEC SQL FETCH emp_cursor USING DESCRIPTOR select_des;
 

図15-8に、FETCH実行後の選択記述子を示します。Oracleは選択リストの値とインジケータの値を、VIの要素によってアドレス指定されるデータ・バッファに格納しています。

データ型1の出力バッファについては、OracleはL配列に格納された長さを使用し、CHARまたはVARCHAR2のデータを左揃えにしてから、NUMBERデータを右揃えにします。データ型5(STRING)の出力バッファについては、値を左揃えにし、CHAR、VARCHAR2およびNUMBERのデータにヌル文字を付けます。

値'MARTIN'は、EMP表のVARCHAR2(10)列から取り出されました。L[0]の長さを使用して、Oracleは10バイトのフィールドの値を左揃えにしてバッファを埋めます。

値7654はNUMBER(4)列から取り出され、'7654'に強制変換されています。しかし、符号と小数点を使用可能にするため、L[1]の長さが2のみ増えています。そこでOracleは6バイトのフィールドの値を左揃えにしてから、ヌル文字を付けます。

値482.50はNUMBER(7,2)列から取り出され、'482.50'に強制変換されています。L[2]の長さが2のみ増えています。Oracleは9バイトのフィールドの値を左揃えにしてから、ヌル文字を付けます。

選択リストの値の取得および処理

FETCH後、プログラムで戻り値を処理できます。例では、列ENAME、EMPNOおよびCOMMの値が処理されます。

図15-8 FETCH後の選択記述子

FETCH後の選択記述子
「図15-8 FETCH後の選択記述子」の説明

記憶域の割当て解除

malloc()によって割り当てられた記憶域を解除するには、free()ライブラリ関数を使用します。構文は次のとおりです。

free(char *pointer); 

例では、選択リスト項目、バインド変数および標識変数の値に対する記憶域の割当てを次のように解除します。

for (i = 0; i < select_des->F; i++)   /* for select descriptor */ 
{ 
    free(select_des->V[i]); 
    free(select_des->I[i]); 
} 
for (i = 0; i < bind_des->F; i++)   /* for bind descriptor */ 
{ 
    free(bind_des->V[i]); 
    free(bind_des->I[i]); 
} 

記述子の記憶域の割当てを解除するには、次の構文のライブラリ関数SQLSQLDAFree()を使用します。

SQLSQLDAFree(context, descriptor_name); 

記述子はSQLSQLDAAlloc()を使用して割り当ててください。そうしないと結果は予測できなくなります。

例では、選択記述子とバインド記述子に対する記憶域の割当てを次のように解除します。

SQLSQLDAFree(SQL_SINGLE_RCTX, select_des); 
SQLSQLDAFree(SQL_SINGLE_RCTX, bind_des); 

カーソルのCLOSE

CLOSEはカーソルを使用禁止にします。例では、CLOSEは次のようにemp_cursorを使用禁止にします。

EXEC SQL CLOSE emp_cursor; 

ホスト配列の使用について

方法4で入力ホスト配列または出力ホスト配列を使用するには、オプションのFOR句を使用してホスト配列のサイズをOracleに通知する必要があります。

関連項目:

FOR句の詳細は、Host Arraysを参照してください

次の構文を使用して、i番目の選択リスト項目またはバインド変数に記述子エントリを設定する必要があります。

V[i] = array_address; 
L[i] = element_size; 

array_addressはホスト配列のアドレスで、element_sizeはある配列要素のサイズです。

EXECUTE文またはFETCH文(どちらか適切な方)にFOR句を指定して、処理対象の配列要素の数をOracleに通知する必要があります。Oracleがホスト配列のサイズを認識する方法は他にないので、この手順は必須です。

次の完全なプログラム例では、3つの入力ホスト配列を使用してEMP表に行をINSERTします。方法4による問合せ以外のDML文にもEXECUTEを使用できます。

#include <stdio.h>
#include <sqlcpr.h>
#include <sqlda.h>
#include <sqlca.h>
 
#define NAME_SIZE    10
#define INAME_SIZE   10
#define ARRAY_SIZE    5
 
/* connect string */
char *username = "scott/tiger";
 
char *sql_stmt =
"INSERT INTO emp (empno, ename, deptno) VALUES (:e, :n, :d)";
int  array_size = ARRAY_SIZE;  /* must have a host variable too */
 
SQLDA   *binda;
 
char    names[ARRAY_SIZE][NAME_SIZE];
int     numbers[ARRAY_SIZE], depts[ARRAY_SIZE];

/* Declare and initialize indicator vars. for empno and deptno columns */
short   ind_empno[ARRAY_SIZE] = {0,0,0,0,0};
short   ind_dept[ARRAY_SIZE] = {0,0,0,0,0};
 
main() 
{ 
    EXEC SQL WHENEVER SQLERROR GOTO sql_error; 
 
/* Connect */ 
    EXEC SQL CONNECT :username; 
    printf("Connected.\n"); 
 
/* Allocate the descriptors and set the N component. 
   This must be done before the DESCRIBE. */ 
    binda = SQLSQLDAAlloc(SQL_SINGLE_RCTX, 3, NAME_SIZE, INAME_SIZE); 
    binda->N = 3; 
 
/* Prepare and describe the SQL statement. */ 
    EXEC SQL PREPARE stmt FROM :sql_stmt; 
    EXEC SQL DESCRIBE BIND VARIABLES FOR stmt INTO binda; 
 
/* Initialize the descriptors. */ 
    binda->V[0] = (char *) numbers; 
    binda->L[0] = (long) sizeof (int); 
    binda->T[0] = 3; 
    binda->I[0] = ind_empno; 
 
    binda->V[1] = (char *) names; 
    binda->L[1] = (long) NAME_SIZE; 
    binda->T[1] = 1; 
    binda->I[1] = (short *)0;
 
    binda->V[2] = (char *) depts; 
    binda->L[2] = (long) sizeof (int); 
    binda->T[2] = 3; 
    binda->I[2] = ind_dept; 
 
/* Initialize the data buffers. */ 
    strcpy(&names[0] [0], "ALLISON"); 
    numbers[0] = 1014; 
    depts[0] = 30; 
 
    strcpy(&names[1] [0], "TRUSDALE"); 
    numbers[1] = 1015; 
    depts[1] = 30; 
 
    strcpy(&names[2] [0], "FRAZIER"); 
    numbers[2] = 1016; 
    depts[2] = 30; 
 
    strcpy(&names[3] [0], "CARUSO"); 
    numbers[3] = 1017; 
    ind_dept[3] = -1;       /* set indicator to -1 to insert NULL */
    depts[3] = 30;          /* value in depts[3] is ignored */ 
 
    strcpy(&names[4] [0], "WESTON"); 
    numbers[4] = 1018;
    depts[4] = 30;
 
/* Do the INSERT. */
    printf("Adding to the Sales force...\n");
    
    EXEC SQL FOR :array_size
    EXECUTE stmt USING DESCRIPTOR binda;
 
/*  Print rows-processed count. */
    printf("%d rows inserted.\n\n", sqlca.sqlerrd[2]);
    EXEC SQL COMMIT RELEASE;
    exit(0);
 
sql_error: 
/* Print Oracle error message. */
    printf("\n%.70s", sqlca.sqlerrm.sqlerrmc);
    EXEC SQL WHENEVER SQLERROR CONTINUE; 
    EXEC SQL ROLLBACK RELEASE; 
    exit(1); 
} 

sample12.pc

配列のフェッチを使用した簡単な動的SQLの例は、demoディレクトリのsample12.pcファイルにあります。