埋め込みSQLの使用¶
次の各セクションは、コードサンプルで始まり、コードサンプル内の各セクションの説明が続きます。
例-簡単なクエリ¶
最初のコードサンプルは、 SELECT ステートメント(1行を返す)を実行して、ホスト変数のグループに結果を保存する方法を示しています。ホスト変数を宣言した後、ハードコードされたロール名と関連付けられたパスワードを使用して edb サンプルデータベースに接続し、 emp テーブルを照会します。クエリは、宣言されたホスト変数に値を返します。 NULL インジケータ変数の値を確認した後、簡単な結果セットを画面に出力し、接続を閉じます。
/************************************************************
* print_emp.pgc
*
*/
#include <stdio.h>
int main(void)
{
EXEC SQL BEGIN DECLARE SECTION;
int v_empno;
char v_ename[40];
double v_sal;
double v_comm;
short v_comm_ind;
EXEC SQL END DECLARE SECTION;
EXEC SQL WHENEVER SQLERROR sqlprint;
EXEC SQL CONNECT TO edb
USER 'alice' IDENTIFIED BY '1safepwd';
EXEC SQL
SELECT
empno, ename, sal, comm
INTO
:v_empno, :v_ename, :v_sal, :v_comm INDICATOR:v_comm_ind
FROM
emp
WHERE
empno = 7369;
if (v_comm_ind)
printf("empno(%d), ename(%s), sal(%.2f) comm(NULL)\n",
v_empno, v_ename, v_sal);
else
printf("empno(%d), ename(%s), sal(%.2f) comm(%.2f)\n",
v_empno, v_ename, v_sal, v_comm);
EXEC SQL DISCONNECT;
}
/***********************************************************\*
コードサンプルは、Cの stdio ライブラリのプロトタイプと型定義を含めることから始まり、 main 関数を宣言します。
#include <stdio.h>
int main(void)
{
次に、アプリケーションは、データベースサーバーとの対話に使用されるホスト変数のセットを宣言します。
EXEC SQL BEGIN DECLARE SECTION;
int v_empno;
char v_ename[40];
double v_sal;
double v_comm;
short v_comm_ind;
EXEC SQL END DECLARE SECTION;
PROC モードでコードをプリコンパイルする予定がある場合は、 BEGIN DECLARE…END DECLARE セクションを省略できます。ホスト変数の宣言の詳細については、 ホスト変数の宣言 を参照してください。
宣言セクション内の各変数に関連付けられているデータ型は、Cデータ型です。サーバーとクライアントアプリケーションの間で渡されるデータは、互換性のあるデータ型を共有する必要があります。データ型の詳細については、 サポートされているCデータ型 を参照してください。
次のステートメントは、エラーの処理方法をサーバーに指示します。
EXEC SQL WHENEVER SQLERROR sqlprint;
クライアントアプリケーションがSQLコードでエラーを検出すると、サーバーは ecpglib で提供される sqlprint() 関数を使用して、 stderr (標準エラー)にエラーメッセージを出力します。次の EXEC SQL ステートメントは、AdvancedServerとの接続を確立します。
EXEC SQL CONNECT TO edb
USER 'alice' IDENTIFIED BY '1safepwd';
この例では、クライアントアプリケーションは edb データベースに接続し、 alice という名前のロールと 1safepwd というパスワードを使用します。
次に、コードは emp テーブルに対してクエリを実行します。
EXEC SQL
SELECT
empno, ename, sal, comm
INTO
:v_empno, :v_ename, :v_sal, :v_comm INDICATOR :v_comm_ind
FROM
emp
WHERE
empno = 7369;
クエリは、従業員番号 7369 に関する情報を返します。
SELECT ステートメントは「11」句を使用して、取得した値( empno 、 ename 、 sal 、 comm 列から)を :v_empno 、 :v_ename 、 :v_sal 、 :v_comm ホスト変数(および「10」ヌルインジケータ)。取得された最初の値は「11」句にリストされている最初の変数に割り当てられ、2番目の値は2番目の変数に割り当てられます。
comm 列には従業員が獲得したコミッション値が含まれ、潜在的に NULL 値が含まれる場合があります。このステートメントには、 INDICATOR キーワードと、ヌルインジケータを保持するホスト変数が含まれています。
コードはnullインジケータをチェックし、適切な画面上の結果を表示します。
if (v_comm_ind)
printf("empno(%d), ename(%s), sal(%.2f) comm(NULL)\n",
v_empno, v_ename, v_sal);
else
printf("empno(%d), ename(%s), sal(%.2f) comm(%.2f)\n",
v_empno, v_ename, v_sal, v_comm);
ヌルインジケータが 0 (つまり false )の場合、 comm 列には意味のある値が含まれ、 printf 関数は手数料を表示します。nullインジケータにゼロ以外の値が含まれる場合、 comm は NULL であり、 printf は NULL の値を表示します。そのホスト変数に NULL をフェッチすると、ホスト変数(nullインジケータ以外)には意味のある値が含まれないことに注意してください。nullインジケータを使用して、 NULL の値を識別する必要があります。
コードサンプルの最後のステートメントは、サーバーへの接続を閉じます。
EXEC SQL DISCONNECT;
}
インジケータ変数の使用¶
前の例には、 comm 列の値(サーバーから返されたとき)が NULL である行を識別する*インジケーター**変数* が含まれていました。インジケータ変数は、前の変数の内容が NULL または切り捨てられているかどうかを示す追加のホスト変数です。インジケータ変数は、行の内容が保存されるときに入力されます。インジケータ変数には、次の値が含まれる場合があります。
指標値 |
意味する |
|---|---|
標識変数が0より小さい場合。 |
サーバーから返された値はNULLでした。 |
標識変数が0に等しい場合。 |
サーバーから返された値はNULLではなく、切り捨てられませんでした。 |
標識変数が0より大きい場合。 |
サーバーから返された値は、ホスト変数に格納されたときに切り捨てられました。 |
INTO 句にインジケータ変数を含める場合、オプションの INDICATOR キーワードを含める必要はありません。
クエリが NULL 値を対応するホスト変数に決して返さないことが確実な場合は、インジケータ変数を省略できます。インジケータ変数を省略し、クエリが NULL 値を返す場合、 ecpglib は実行時エラーを発生させます。
ホスト変数の宣言¶
SQLステートメント内で値が表示される可能性のある任意の時点で、そのステートメント内で*ホスト変数* を使用できます。ホスト変数は、クライアントアプリケーションからサーバーにデータ値を渡し、サーバーからクライアントアプリケーションにデータを返すために使用できるC変数です。ホスト変数には次のものがあります。
配列
typedefポインター
struct任意のスカラーCデータ型
以下のコードフラグメントは、 PROC モードおよび非 PROC モードでコンパイルされたコードでホスト変数を使用する方法を示しています。SQLステートメントは、 dept テーブルに行を追加し、変数 v_deptno 、 v_dname 、 v_loc によって返される値を deptno 列、 dname 列、 loc 列に挿入します。それぞれ。
PROC モードでコンパイルする場合、 EXEC SQL BEGIN DECLARE SECTION および EXEC SQL END DECLARE SECTION ディレクティブを省略できます。 PROC モードでは、C関数パラメーターをホスト変数として使用できます。
void addDept(int v_deptno, char v_dname, char v_loc)
{
EXEC SQL INSERT INTO dept VALUES( :v_deptno, :v_dname, :v_loc);
}
PROC モードでコンパイルしていない場合は、以下に示すように、埋め込み変数宣言を EXEC SQL BEGIN DECLARE SECTION および EXEC SQL END DECLARE SECTION ディレクティブでラップする必要があります。
void addDept(int v_deptno, char v_dname, char v_loc)
{
EXEC SQL BEGIN DECLARE SECTION;
int v_deptno_copy = v_deptno;
char v_dname_copy[14+1] = v_dname;
char v_loc_copy[13+1] = v_loc;
EXEC SQL END DECLARE SECTION;
EXEC SQL INSERT INTO dept VALUES( :v_deptno, :v_dname, :v_loc);
}
ホスト変数を使用して情報を取得するために、 SELECT ステートメントに INTO 句を含めることもできます。
EXEC SQL SELECT deptno, dname, loc
INTO :v_deptno, :v_dname, v_loc FROM dept;
SELECT ステートメントによって返される各列には、 INTO 句にタイプ互換のターゲット変数が必要です。これは、単一の行を取得する簡単な例です。複数の行を取得するには、次の例に示すように、カーソルを定義する必要があります。
例-カーソルを使用して結果セットを処理する¶
次のコードサンプルは、カーソルを使用して結果セットを処理する方法を示しています。カーソルの作成と使用には、4つの基本的な手順が含まれます。
DECLARE CURSORステートメントを使用して、カーソルを定義します。OPEN CURSORステートメントを使用して、カーソルを開きます。FETCHステートメントを使用して、カーソルからデータを取得します。CLOSE CURSORステートメントを使用して、カーソルを閉じます。
ホスト変数を宣言した後、この例では、ユーザーが指定したロール名とパスワードを使用して edb データベースに接続し、 emp テーブルを照会します。クエリは、値を employees という名前のカーソルに返します。次に、サンプルコードはカーソルを開き、結果セットを一度に1行ずつループして結果セットを出力します。サンプルが結果セットの終わりを検出すると、接続を閉じます。
/************************************************************
* print_emps.pgc
*
*/
#include <stdio.h>
int main(int argc, char *argv[])
{
EXEC SQL BEGIN DECLARE SECTION;
char *username = argv[1];
char *password = argv[2];
int v_empno;
char v_ename[40];
double v_sal;
double v_comm;
short v_comm_ind;
EXEC SQL END DECLARE SECTION;
EXEC SQL WHENEVER SQLERROR sqlprint;
EXEC SQL CONNECT TO edb USER :username IDENTIFIED BY :password;
EXEC SQL DECLARE employees CURSOR FOR
SELECT
empno, ename, sal, comm
FROM
emp;
EXEC SQL OPEN employees;
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH NEXT FROM employees
INTO
:v_empno, :v_ename, :v_sal, :v_comm INDICATOR :v_comm_ind;
if (v_comm_ind)
printf("empno(%d), ename(%s), sal(%.2f) comm(NULL)\n",
v_empno, v_ename, v_sal);
else
printf("empno(%d), ename(%s), sal(%.2f) comm(%.2f)\n",
v_empno, v_ename, v_sal, v_comm);
}
EXEC SQL CLOSE employees;
EXEC SQL DISCONNECT;
}
/************************************************************
コードサンプルは、Cの stdio ライブラリのプロトタイプと型定義を含めることから始まり、 main 関数を宣言します。
#include <stdio.h>
int main(int argc, char *argv[])
{
次に、アプリケーションは、データベースサーバーとの対話に使用されるホスト変数のセットを宣言します。
EXEC SQL BEGIN DECLARE SECTION;
char *username = argv[1];
char *password = argv[2];
int v_empno;
char v_ename[40];
double v_sal;
double v_comm;
short v_comm_ind;
EXEC SQL END DECLARE SECTION;
argv[] は、ユーザーがクライアントアプリケーションを実行するときに入力したコマンドライン引数を含む配列です。 argv[1] には最初のコマンドライン引数(この場合は username )が含まれ、 argv[2] には2番目のコマンドライン引数( password )が含まれます。通常、実際のアプリケーションに含めるエラーチェックコードは省略していることに注意してください。宣言は、 username と password の値を初期化し、ユーザーがクライアントアプリケーションを呼び出したときに入力した値に設定します。
(各変数の個別のコピーを作成する代わりに)SQLステートメントで argv[1] と argv[2] を参照できると考えているかもしれません。それは機能しません。すべてのホスト変数は、 BEGIN/END DECLARE SECTION 内で宣言する必要があります( PROC モードでコンパイルしている場合を除く)。 argv は関数*パラメーター*(自動変数ではない)であるため、 BEGIN/END DECLARE SECTION 内で宣言することはできません。 PROC モードでコンパイルしている場合は、SQLステートメント内で*任意* のC変数を参照できます。
次のステートメントは、ECPGPlusまたはデータベースサーバーから返されたエラーメッセージのテキストを出力することにより、SQLエラーに応答するようサーバーに指示します。
EXEC SQL WHENEVER SQLERROR sqlprint;
次に、クライアントアプリケーションはAdvancedServerとの接続を確立します。
EXEC SQL CONNECT TO edb USER :username IDENTIFIED BY :password;
CONNECT ステートメントは、 :username および :password ホスト変数にある値を使用して edb データベースへの接続を作成し、接続時にサーバーに対してアプリケーションを認証します。
次のステートメントは、 employees という名前のカーソルを宣言しています。
EXEC SQL DECLARE employees CURSOR FOR
SELECT
empno, ename, sal, comm
FROM
emp;
employees には、 emp テーブルの SELECT ステートメントの結果セットが含まれます。クエリは、 empno 、 ename 、 sal 、 comm の列から従業員情報を返します。カーソルを宣言するとき、 INTO 節が含まれないことに注意してください。代わりに、カーソルから FETCH を指定するときにターゲット変数(または記述子)を指定します。
カーソルから行をフェッチする前に、クライアントアプリケーションはカーソルを OPEN にする必要があります。
EXEC SQL OPEN employees;
後続の FETCH セクションでは、クライアントアプリケーションはカーソルの内容をループします。クライアントアプリケーションには、カーソルの最後に到達したときにサーバーに break (つまり、ループを終了する)を指示する WHENEVER ステートメントが含まれています。
EXEC SQL WHENEVER NOT FOUND DO break;
クライアントアプリケーションは、 FETCH ステートメントを使用して、カーソルから INTO 以前に宣言されたホスト変数の各行を取得します。
for (;;)
{
EXEC SQL FETCH NEXT FROM employees
INTO
:v_empno, :v_ename, :v_sal, :v_comm INDICATOR :v_comm_ind;
FETCH ステートメントは INTO 句を使用して、取得した値を :v_empno 、 :v_ename 、 :v_sal 、 :v_comm ホスト変数(および :v_comm_ind ヌルインジケーター)に割り当てます。カーソルの最初の値は INTO 句にリストされている最初の変数に割り当てられ、2番目の値は2番目の変数に割り当てられます。
FETCH ステートメントには、 INDICATOR キーワードとヌルインジケータを保持するホスト変数も含まれます。取得したレコードの comm 列に NULL 値が含まれる場合、 v_comm_ind はゼロ以外の値に設定され、列が NULL であることを示します。
次に、コードはヌルインジケータをチェックし、適切な画面上の結果を表示します。
if (v_comm_ind)
printf("empno(%d), ename(%s), sal(%.2f) comm(NULL)\n",
v_empno, v_ename, v_sal);
else
printf("empno(%d), ename(%s), sal(%.2f) comm(%.2f)\n",
v_empno, v_ename, v_sal, v_comm);
}
ヌルインジケータが 0 (つまり false )の場合、 v_comm には意味のある値が含まれ、 printf 関数は手数料を表示します。nullインジケータにゼロ以外の値が含まれる場合、 comm は NULL であり、 printf は文字列 'NULL' を表示します。そのホスト変数に NULL をフェッチすると、ホスト変数(nullインジケータ以外)には意味のある値が含まれないことに注意してください。 NULL になる可能性のある値にはヌルインジケータを使用する必要があります。
コードサンプルの最後のステートメントはカーソル (employees) を閉じ、サーバーへの接続を閉じます。
EXEC SQL CLOSE employees;
EXEC SQL DISCONNECT;