方法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);
}