この項では、高度な接続で使用できるオプションについて説明します。
ネットワーク上の通信ポイントは、ノードと呼ばれます。Oracle Netでは、ネットワーク上のノード間で情報(SQL文、データおよびステータス・コード)を送信できます。
プロトコルは、ネットワークへのアクセスに関する一連の規則です。この規則では、障害後のリカバリ手順、データの転送およびエラー検査のフォーマットなどが規定されます。
ローカル・ドメイン内のデフォルトのデータベースに接続するためにOracle Netの構文で使用するのは、そのデータベースのサービス名のみです。
サービス名がデフォルト(ローカル)・ドメイン内にない場合は、グローバル指定(すべてのドメインの指定)を使用する必要があります。次に例を示します。
HR.US.ORACLE.COM
Pro*C/C++では、Oracle Net経由で分散処理がサポートされます。アプリケーションは、ローカル・データベースおよびリモート・データベースの任意の組合せに同時にアクセスしたり、同じデータベースへの複数の接続を確立できます。図3-1では、アプリケーション・プログラムはOracleの1つのローカル・データベースおよび3つのリモート・データベースと接続しています。ORA2、ORA3およびORA4は、CONNECT文で使用される論理名です。
Oracle Netは、ネットワーク上の異なるマシン間およびオペレーティング・システム間に存在する境界を排除することによって、Oracleのツール製品に分散処理環境を提供します。この項では、Pro*C/C++によりOracle Net経由で分散処理がサポートされる方法について説明します。アプリケーションから可能な操作は、次のとおりです。
他のデータベースへの直接または間接アクセス
ローカルおよびリモート・データベースの任意の組合せへの同時アクセス
同一のデータベースへの複数接続
Oracle Netのインストール方法および使用可能なデータベースの識別方法は、Oracle Database Net Services管理者ガイドおよびシステム固有のOracleドキュメントを参照してください。
各ノードにはデフォルトのデータベースがあります。CONNECT文でデータベース名のみを指定し、ドメインを指定しない場合、指定したローカル・ノードまたはリモート・ノード上のデフォルトのデータベースに接続されます。
デフォルトの接続は、AT句のないCONNECT文によって行われます。ローカルまたはリモートの任意のノード上のデフォルトまたは非デフォルトの任意のデータベースに接続できます。AT句のないSQL文は、デフォルトの接続に対して実行されます。逆に、非デフォルトの接続は、AT句があるCONNECT文により行われます。AT句を持つSQL文は、非デフォルトの接続に対して実行されます。
データベース名は一意にする必要がありますが、2つ以上のデータベース名で同じ接続を指定できます。したがって、任意のノード上のデータベースに対して複数の接続を確立できます。
通常は、Oracleへの接続を次のように確立します。
EXEC SQL CONNECT :username IDENTIFIED BY :password;
また、次の文も使用できます。
EXEC SQL CONNECT :usr_pwd;
usr_pwdには、username/passwordが含まれます。
次のユーザーIDを使用してOracleに自動的に接続できます。
CLUSTER$username
usernameは現行のオペレーティング・システムのユーザー名またはタスク名、CLUSTER$usernameは有効なOracleユーザーIDです。プリコンパイラに渡すのはスラッシュ文字(/)のみです。次に例を示します。
char oracleid = '/'; ... EXEC SQL CONNECT :oracleid;
これにより、ユーザーCLUSTER$usernameで自動的に接続されます。
データベースおよびノードを指定しない場合、現在のノード上のデフォルトのデータベースに接続されます。別のデータベースに接続する場合は、そのデータベースを明示的に指定する必要があります。
明示的接続では、SQL文で参照される接続名を指定して、別のデータベースに直接接続します。同時に複数のデータベースに接続することも、同じデータベースに複数回接続することもできます。
次の例では、リモート・ノードにある単一の非デフォルトのデータベースに接続します。
/* declare needed host variables */ char username[10] = "scott"; char password[10] = "tiger"; char db_string[20] = "NYNON"; /* give the database connection a unique name */ EXEC SQL DECLARE DB_NAME DATABASE; /* connect to the nondefault database */ EXEC SQL CONNECT :username IDENTIFIED BY :password AT DB_NAME USING :db_string;
この例の識別子は、次の目的で使用されています。
ホスト変数usernameおよびpasswordは、有効なユーザーを識別します。
ホスト変数db_stringには、リモート・ノードにある非デフォルトのデータベースに接続するためのOracle Net構文が含まれています。
未宣言の識別子DB_NAMEは、非デフォルト接続の名前を指定します。これは、Oracleで使用される識別子で、ホスト変数でもプログラム変数でもありません。
USING句では、DB_NAMEに対応付けるネットワーク、マシンおよびデータベースを指定します。その後、AT句(DB_NAME付き)を使用しているSQL文は、db_stringに指定したデータベースで実行されます。
もう1つの方法として、次の例に示すように、AT句で文字ホスト変数を使用できます。
/* declare needed host variables */ char username[10] = "scott"; char password[10] = "tiger"; char db_name[10] = "oracle1"; char db_string[20] = "NYNON"; /* connect to the nondefault database using db_name */ EXEC SQL CONNECT :username IDENTIFIED BY :password AT :db_name USING :db_string; ...
db_nameがホスト変数の場合、DECLARE DATABASE文は不要です。DB_NAMEが未宣言の識別子の場合にのみ、CONNECT ... AT DB_NAME文を実行する前にDECLARE DB_NAME DATABASE文を実行する必要があります。
権限を付与されている場合は、非デフォルトの接続で任意のSQL DML文を実行できます。たとえば、次のように入力します。
EXEC SQL AT DB_NAME SELECT ... EXEC SQL AT DB_NAME INSERT ... EXEC SQL AT DB_NAME UPDATE ...
次の例では、db_nameはホスト変数です。
EXEC SQL AT :db_name DELETE ...
db_nameがホスト変数の場合、SQL文で参照されるすべてのデータベース表を、DECLARE TABLE文で定義する必要があります。定義しないと、プリコンパイラで警告が発行されます。
OPEN、FETCHおよびCLOSEなどのカーソルの制御文は例外で、AT句は使用しません。カーソルを明示的に識別されたデータベースに対応付ける場合は、次のようにDECLARE CURSOR文でAT句を使用します。
EXEC SQL AT :db_name DECLARE emp_cursor CURSOR FOR ... EXEC SQL OPEN emp_cursor ... EXEC SQL FETCH emp_cursor ... EXEC SQL CLOSE emp_cursor;
db_nameがホスト変数の場合は、DECLAREされたカーソルを参照するすべてのSQL文の適用範囲内で宣言する必要があります。たとえば、あるサブプログラム内でカーソルをOPENし、別のサブプログラムでそのカーソルからFETCHする場合は、db_nameをグローバルに宣言する必要があります。
カーソルからOPEN、CLOSEおよびFETCHを実行する場合、AT句を使用しません。SQL文は、DECLARE CURSOR文のAT句で名前を付けられたデータベースか、カーソルの宣言でAT句が使用されていない場合はデフォルトのデータベースにおいて実行されます。
AT :host_variable句を使用すると、カーソルに対応付けられた接続を変更できます。ただし、カーソルがオープンされているときは対応付けを変更できません。次の例を考えてみます。
EXEC SQL AT :db_name DECLARE emp_cursor CURSOR FOR ... strcpy(db_name, "oracle1"); EXEC SQL OPEN emp_cursor; EXEC SQL FETCH emp_cursor INTO ... strcpy(db_name, "oracle2"); EXEC SQL OPEN emp_cursor; /* illegal, cursor still open */ EXEC SQL FETCH emp_cursor INTO ...
この例は、2番目のOPEN文を実行するときにemp_cursorがまだオープンされているため、無効となります。異なる接続に対して別々のカーソルが維持されることはありません。emp_cursorは1つのみ存在できます。別の接続のために再オープンするには、その前にクローズする必要があります。最後の例をデバッグするには、次のように、単にカーソルをクローズしてから再オープンします。
... EXEC SQL CLOSE emp_cursor; -- close cursor first strcpy(db_name, "oracle2"); EXEC SQL OPEN emp_cursor; EXEC SQL FETCH emp_cursor INTO ...
動的SQL文は、文中ではAT句が使用されないカーソル制御文に類似しています。
動的SQL方法1では、非デフォルトの接続で文を実行する場合は、AT句を使用する必要があります。次に例を示します。
EXEC SQL AT :db_name EXECUTE IMMEDIATE :sql_stmt;
方法2、3および4で非デフォルトの接続で文を実行する場合は、DECLARE STATEMENT文でのみAT句を使用します。PREPARE、DESCRIBE、OPEN、FETCHおよびCLOSEなど、その他の動的SQL文はAT句を使用しません。次の例に方法2を示します。
EXEC SQL AT :db_name DECLARE sql_stmt STATEMENT; EXEC SQL PREPARE sql_stmt FROM :sql_string; EXEC SQL EXECUTE sql_stmt;
次の例は方法3を示します。
EXEC SQL AT :db_name DECLARE sql_stmt STATEMENT; EXEC SQL PREPARE sql_stmt FROM :sql_string; EXEC SQL DECLARE emp_cursor CURSOR FOR sql_stmt; EXEC SQL OPEN emp_cursor ... EXEC SQL FETCH emp_cursor INTO ... EXEC SQL CLOSE emp_cursor;
単一の明示的接続の場合と同様に、複数の明示的接続にはAT db_name句を使用できます。次の例では、2つの非デフォルトのデータベースに同時に接続しています。
/* declare needed host variables */ char username[10] = "scott"; char password[10] = "tiger"; char db_string1[20] = "NYNON1"; char db_string2[20] = "CHINON"; ... /* give each database connection a unique name */ EXEC SQL DECLARE DB_NAME1 DATABASE; EXEC SQL DECLARE DB_NAME2 DATABASE; /* connect to the two nondefault databases */ EXEC SQL CONNECT :username IDENTIFIED BY :password AT DB_NAME1 USING :db_string1; EXEC SQL CONNECT :username IDENTIFIED BY :password AT DB_NAME2 USING :db_string2;
識別子DB_NAME1およびDB_NAME2を宣言し、2つの非デフォルト・ノードのデフォルトのデータベースの名前を指定します。これにより、SQL文ではデータベースを名前で参照できます。
または、次の例のように、AT句でホスト変数を使用できます。
/* declare needed host variables */ char username[10] = "scott"; char password[10] = "tiger"; char db_name[20]; char db_string[20]; int n_defs = 3; /* number of connections to make */ ... for (i = 0; i < n_defs; i++) { /* get next database name and OracleNet string */ printf("Database name: "); gets(db_name); printf("OracleNet) string: "); gets(db_string); /* do the connect */ EXEC SQL CONNECT :username IDENTIFIED BY :password AT :db_name USING :db_string; }
この方法を使用すれば、次の例のように、同じデータベースに複数の接続を行うこともできます。
strcpy(db_string, "NYNON"); for (i = 0; i < ndefs; i++) { /* connect to the nondefault database */ printf("Database name: "); gets(db_name); EXEC SQL CONNECT :username IDENTIFIED BY :password AT :db_name USING :db_string; } ...
複数の接続に同じOracle Net文字列を使用する場合も、接続ごとに異なるデータベース名を使用する必要があります。ただし、データベース名ではデフォルトおよび非デフォルトのデータベースの両方が識別されるため、1つのデータベース名で同じデータベースに2回接続できます。
アプリケーション・プログラムでは、複数のリモート・データベースにあるデータを操作するトランザクションの整合性を確認する必要があります。つまり、プログラムはトランザクションのすべてのSQL文をコミットまたはロールバックする必要があります。これは、ネットワーク障害が発生した場合や、システムの1つがクラッシュした場合は不可能です。
たとえば、2つの会計データベースで作業しているとします。一方のデータベースで勘定の借方に記帳し、他方のデータベースで勘定の貸方に記帳してから、それぞれのデータベースでCOMMITを発行します。両方のトランザクションがコミットまたはロールバックされたかどうかは、プログラム側で確認する必要があります。
暗黙的接続は、Oracleの分散問合せ機能を通じてサポートされます。この機能には明示的接続は不要ですが、サポートされるのはSELECT文のみです。分散問合せを使用すると、単一のSELECT文で1つ以上の非デフォルトのデータベースにあるデータにアクセスできます。
分散問合せ機能はデータベース・リンクに依存しており、リンクにより接続事態ではなく、CONNECT文に名前が割り当てられます。 実行時には、指定したOracleサーバーにより埋込みSELECT文が実行され、非デフォルトのデータベースに暗黙的に接続されて、必要なデータが取得されます。
次の例では、1つの非デフォルト・データベースに接続します。最初に、プログラムでは次の文が実行され、データベース・リンクが定義されます(通常、データベース・リンクは、DBAまたはユーザーが対話形式で確立します)。
EXEC SQL CREATE DATABASE LINK db_link CONNECT TO username IDENTIFIED BY password USING 'NYNON';
プログラムでは、次のようにデータベース・リンクを使用して非デフォルトのEMP表を問い合せできます。
EXEC SQL SELECT ENAME, JOB INTO :emp_name, :job_title FROM emp@db_link WHERE DEPTNO = :dept_number;
データベース・リンクは、埋込みSQL文のAT句に使用されるデータベース名とは無関係です。単に、非デフォルトのデータベースの位置、データベースへのパス、使用するOracleユーザー名およびパスワードをOracleに対して指示します。データベース・リンクは、明示的に削除されるまで、データベース・ディクショナリに格納されます。
前述の例で、デフォルトのOracleサーバーは、データベース・リンクdb_linkを使用して、Oracle Net経由で非デフォルトのデータベースにログインします。問合せはデフォルトのサーバーに送られますが、非デフォルトのデータベースに転送されて実行されます。
データベース・リンクを簡単に参照できるように、次のようにシノニムを対話形式で作成できます。
EXEC SQL CREATE SYNONYM emp FOR emp@db_link;
その結果、プログラムで、次のように非デフォルトのEMP表に問合せができるようになります。
EXEC SQL SELECT ENAME, JOB INTO :emp_name, :job_title FROM emp WHERE DEPTNO = :dept_number;
次の例では、2つの非デフォルト・データベースに同時に接続します。まず次の一連の文を実行し、2つのデータベース・リンクを定義して2つのシノニムを作成します。
EXEC SQL CREATE DATABASE LINK db_link1 CONNECT TO username1 IDENTIFIED BY password1 USING 'NYNON'; EXEC SQL CREATE DATABASE LINK db_link2 CONNECT TO username2 IDENTIFIED BY password2 USING 'CHINON'; EXEC SQL CREATE SYNONYM emp FOR emp@db_link1; EXEC SQL CREATE SYNONYM dept FOR dept@db_link2;
その結果、プログラムで、次のように非デフォルトのEMP表とDEPT表に問合せができるようになります。
EXEC SQL SELECT ENAME, JOB, SAL, LOC FROM emp, dept WHERE emp.DEPTNO = dept.DEPTNO AND DEPTNO = :dept_number;
Oracleでは、db_link1にある非デフォルトのEMP表とdb_link2にある非デフォルトのDEPT表を結合することにより、問合せが実行されます。