方法1では1ステップで実行し、方法2では2ステップに分けて実行します。動的SQL文(問合せは不可)は、まずPREPARE(名前の指定と解析)され、次にEXECUTEされます。
方法2では、SQL文には入力ホスト変数と標識変数のプレースホルダを指定できます。このSQL文は一度PREPAREすると、ホスト変数に別の値を指定して繰り返しEXECUTEできます。したがって、(ログアウトして再接続しないかぎり)COMMITまたはROLLBACKの後に再度SQL文をPREPAREする必要はありません。
方法4では、非問合せにEXECUTEを使用できます。
PREPARE文の構文は次のとおりです。
EXEC SQL PREPARE statement_name FROM { :host_string | string_literal };
PREPAREは、このSQL文を解析して名前を指定します。
statement_nameは、ホスト変数やプログラム変数ではなく、プリコンパイラで使用される識別子であり、宣言部で宣言されません。これはEXECUTEの対象としてPREPARE済の文を示しているにすぎません。
EXECUTE文の構文は次のとおりです。
EXEC SQL EXECUTE statement_name [USING host_variable_list];
host_variable_listは、次の構文を表しています。
:host_variable1[:indicator1] [, host_variable2[:indicator2], ...]
解析したSQL文は、それぞれの入力ホスト変数に指定済の値を使用してEXECUTEによって実行されます。
次の例では、入力されたSQL文に、プレースホルダnが含まれています。
... int emp_number INTEGER; char delete_stmt[120], search_cond[40];; ... strcpy(delete_stmt, "DELETE FROM EMP WHERE EMPNO = :n AND "); printf("Complete the following statement's search condition--\n"); printf("%s\n", delete_stmt); gets(search_cond); strcat(delete_stmt, search_cond); EXEC SQL PREPARE sql_stmt FROM :delete_stmt; for (;;) { printf("Enter employee number: "); gets(temp); emp_number = atoi(temp); if (emp_number == 0) break; EXEC SQL EXECUTE sql_stmt USING :emp_number; } ...
方法2では、プリコンパイル時に入力ホスト変数のデータ型がわかっている必要があります。最後の例では、emp_numberがintとして宣言されています。Oracleでは、floatやcharなど、全データ型のOracle内部NUMBERデータ型への変換がサポートされるため、これをfloatまたはcharとして宣言することも可能です。
SQL文がEXECUTEされると、USING句の入力ホスト変数は、PREPAREされた動的SQL文内の該当するプレースホルダに置換されます。
PREPAREされた動的SQL文のプレースホルダは、それぞれが必ずUSING句の個別のホスト変数に対応している必要があります。つまり、PREPAREされた文に同じプレースホルダが2回以上現れるときは、それぞれがUSING句のホスト変数に対応している必要があります。
プレースホルダの名前は、ホスト変数の名前と一致する必要はありません。ただし、PREPARE済動的SQL文のプレースホルダの順序は、USING句の対応するホスト変数の順序と一致する必要があります。
USING句のホスト変数のうち1つでも配列がある場合は、すべてのホスト変数が配列であることが必要です。
NULLを指定するために、標識変数をUSING句のホスト変数と対応付けることができます。
関連項目:
次のプログラムでは、動的SQL方法2を使用して2つの行をEMP表に挿入し、その後でそれらの行を削除しています。このプログラムはdemoディレクトリのsample7.pc
ファイルにあり、オンラインで利用できます。
/* * sample7.pc: Dynamic SQL Method 2 * * This program uses dynamic SQL Method 2 to insert two rows into * the EMP table, then delete them. */ #include <stdio.h> #include <string.h> #define USERNAME "SCOTT" #define PASSWORD "TIGER" /* Include the SQL Communications Area, a structure through * which ORACLE makes runtime status information such as error * codes, warning flags, and diagnostic text available to the * program. */ #include <sqlca.h> /* Include the ORACLE Communications Area, a structure through * which ORACLE makes additional runtime status information * available to the program. */ #include <oraca.h> /* The ORACA=YES option must be specified to enable use of * the ORACA. */ EXEC ORACLE OPTION (ORACA=YES); char *username = USERNAME; char *password = PASSWORD; VARCHAR dynstmt[80]; int empno = 1234; int deptno1 = 97; int deptno2 = 99; /* Handle SQL runtime errors. */ void dyn_error(); main() { /* Call dyn_error() whenever an error occurs * processing an embedded SQL statement. */ EXEC SQL WHENEVER SQLERROR DO dyn_error("Oracle error"); /* Save text of current SQL statement in the ORACA if an * error occurs. */ oraca.orastxtf = ORASTFERR; /* Connect to Oracle. */ EXEC SQL CONNECT :username IDENTIFIED BY :password; puts("\nConnected to Oracle.\n"); /* Assign a SQL statement to the VARCHAR dynstmt. Both * the array and the length parts must be set properly. * Note that the statement contains two host-variable * placeholders, v1 and v2, for which actual input * host variables must be supplied at EXECUTE time. */ strcpy(dynstmt.arr, "INSERT INTO EMP (EMPNO, DEPTNO) VALUES (:v1, :v2)"); dynstmt.len = strlen(dynstmt.arr); /* Display the SQL statement and its current input host * variables. */ puts((char *) dynstmt.arr); printf(" v1 = %d, v2 = %d\n", empno, deptno1); /* The PREPARE statement associates a statement name with * a string containing a SQL statement. The statement name * is a SQL identifier, not a host variable, and therefore * does not appear in the Declare Section. * A single statement name can be PREPAREd more than once, * optionally FROM a different string variable. */ EXEC SQL PREPARE S FROM :dynstmt; /* The EXECUTE statement executes a PREPAREd SQL statement * USING the specified input host variables, which are * substituted positionally for placeholders in the * PREPAREd statement. For each occurrence of a * placeholder in the statement there must be a variable * in the USING clause. That is, if a placeholder occurs * multiple times in the statement, the corresponding * variable must appear multiple times in the USING clause. * The USING clause can be omitted only if the statement * contains no placeholders. * * A single PREPAREd statement can be EXECUTEd more * than once, optionally USING different input host * variables. */ EXEC SQL EXECUTE S USING :empno, :deptno1; /* Increment empno and display new input host variables. */ empno++; printf(" v1 = %d, v2 = %d\n", empno, deptno2); /* ReEXECUTE S to insert the new value of empno and a * different input host variable, deptno2. * A rePREPARE is unnecessary. */ EXEC SQL EXECUTE S USING :empno, :deptno2; /* Assign a new value to dynstmt. */ strcpy(dynstmt.arr, "DELETE FROM EMP WHERE DEPTNO = :v1 OR DEPTNO = :v2"); dynstmt.len = strlen(dynstmt.arr); /* Display the new SQL statement and its current input host * variables. */ puts((char *) dynstmt.arr); printf(" v1 = %d, v2 = %d\n", deptno1, deptno2); /* RePREPARE S FROM the new dynstmt. */ EXEC SQL PREPARE S FROM :dynstmt; /* EXECUTE the new S to delete the two rows previously * inserted. */ EXEC SQL EXECUTE S USING :deptno1, :deptno2; /* Commit any pending changes and disconnect from Oracle. */ EXEC SQL COMMIT RELEASE; puts("\nHave a good day!\n"); exit(0); } void dyn_error(msg) char *msg; { /* This is the ORACLE error handler. * Print diagnostic text containing error message, * current SQL statement, and location of error. */ printf("\n%s", msg); printf("\n%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); printf("in \"%.*s...\"\n", oraca.orastxt.orastxtl, oraca.orastxt.orastxtc); printf("on line %d of %.*s.\n\n", oraca.oraslnr, oraca.orasfnm.orasfnml, oraca.orasfnm.orasfnmc); /* Disable ORACLE error checking to avoid an infinite loop * should another error occur within this routine. */ EXEC SQL WHENEVER SQLERROR CONTINUE; /* Roll back any pending changes and * disconnect from Oracle. */ EXEC SQL ROLLBACK RELEASE; exit(1); }