この節では、データベース接続の開始、終了、および切り替え方について解説します。
以下のSQL文を使用して、データベースへ接続します。
EXEC SQL CONNECT TOtarget
[ASconnection-name
] [USERuser-name
];
target
は以下の方法で指定されます。
dbname
[@hostname
][:port
]
tcp:postgresql://hostname
[:port
][/dbname
][?options
]
unix:postgresql://localhost[:port
][/dbname
][?options
]
DEFAULT
DEFAULT
接続対象は、デフォルトデータベース、デフォルトのユーザ名で接続を初期化します。
この場合は、ユーザ名と接続名を分けて指定することができません。
接続対象を直接(すなわち、文字列リテラルとしてでも、変数参照でもない形で)指定した場合、対象の要素は通常のSQLとして解析されて渡されます。これは、例えば、hostname
はドットで区切られた一つ以上のSQL識別子のようでなければならなず、識別子が二重引用符で括られていなければ大文字小文字は区別されないということを意味します。
options
の値は、SQL識別子、整数、もしくは変数参照でなければなりません。
もちろん、二重引用符で括ることでSQL識別子の中にほぼ何でも入れることができます。
実際には、おそらく(単一引用符でくくられた)文字列リテラルもしくは変数の参照を使用した方がエラーをより防止できます。
ユーザ名を指定するには、別の方法もあります。
username
username
/password
username
IDENTIFIED BY password
username
USING password
これまで同様、username
とpassword
は、SQL識別子、SQL文字列リテラル、文字型変数への参照を取ることができます。
接続対象にoptions
を含めるのなら、
指定をアンパサンド(keyword
=value
&
)で区切って構成します。
許されるキーワードは、libpqが認識するものと同じです(34.1.2を参照してください)。
keyword
やvalue
の前の空白は無視されますが、中や後の空白は無視されません。
value
の中に&
を書く方法はないことに注意してください。
(unix:
接頭辞で)ソケット接続を指定するときには、ホスト名は厳密にlocalhost
でなければなりません。
デフォルトでないソケットディレクトリを選ぶためには、対象のoptions
部分のhost
オプションの値としてディレクトリのパス名を書いてください。
1つのプログラム内で複数の接続を処理する場合には、connection-name
を使用します。
プログラムで1つしか接続を使わない場合は省略して構いません。
最も最近に開かれた接続が現在の接続になり、SQL文を実行しようとする時にデフォルトでこの接続が使用されます(本章の後で説明します)。
以下にCONNECT
文について、数例を示します。
EXEC SQL CONNECT TO mydb@sql.mydomain.com; EXEC SQL CONNECT TO tcp:postgresql://sql.mydomain.com/mydb AS myconnection USER john; EXEC SQL BEGIN DECLARE SECTION; const char *target = "mydb@sql.mydomain.com"; const char *user = "john"; const char *passwd = "secret"; EXEC SQL END DECLARE SECTION; ... EXEC SQL CONNECT TO :target USER :user USING :passwd; /* もしくは EXEC SQL CONNECT TO :target USER :user/:passwd; */
最後の例では、文字変数参照として上を参照する機能を使用しています。 後の節で、接頭辞にコロンを持つ場合のSQL文内でのC変数の使用方法について説明します。
接続対象の書式は標準SQLでは規定されていないことに注意してください。 そのため、移植可能なアプリケーションを開発したいのであれば、上の例の最後の方法を基にして、接続対象文字列をどこかにカプセル化してください。
信用できないユーザが安全なスキーマ使用パターンを採用していないデータベースにアクセスできる場合、各セッションをsearch_path
から一般のユーザが書き込み可能なスキーマを取り除くことから始めます。
例えば、options=-c search_path=
を
に追加したり、接続後にoptions
EXEC SQL SELECT pg_catalog.set_config('search_path', '', false);
を発行したりします。
この配慮はECPGに特有のものではありません。任意のSQLコマンドを実行するインタフェースすべてに当てはまります。
埋め込みSQLプログラム内のSQL文はデフォルトで現在の接続、つまり、最も最近に開いた接続上で実行されます。 複数の接続を管理する必要があるアプリケーションでは、これを処理する3つの方法があります。
1つ目の選択肢は、各SQL文で明示的に接続を選択することです。 以下に例を示します。
EXEC SQL AT connection-name
SELECT ...;
アプリケーションが複数の接続を不特定な順番で使用する必要がある場合、この選択肢は特に適しています。
アプリケーションの実行に複数スレッドを使用する場合、スレッド間で接続を同時に共有できません。 接続へのアクセスを(ミューテクスを使用して)明示的に制御するか、または各スレッド用の接続を使用するかを行わなければなりません。
2つ目の選択肢は、現在の接続を切り替えるSQL文を実行することです。 以下のSQL文です。
EXEC SQL SET CONNECTION connection-name
;
多くのSQL文を同一接続に対して使用する場合、この選択肢は特に便利です。
以下に複数のデータベースコネクションを管理しているプログラムの例を示します。
#include <stdio.h> EXEC SQL BEGIN DECLARE SECTION; char dbname[1024]; EXEC SQL END DECLARE SECTION; int main() { EXEC SQL CONNECT TO testdb1 AS con1 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL CONNECT TO testdb2 AS con2 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL CONNECT TO testdb3 AS con3 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; /* この問い合わせは最後に開いたデータベース"testdb3"で実行される。 */ EXEC SQL SELECT current_database() INTO :dbname; printf("current=%s (should be testdb3)\n", dbname); /* "testdb2"で問い合わせを実行するには"AT"を使う */ EXEC SQL AT con2 SELECT current_database() INTO :dbname; printf("current=%s (should be testdb2)\n", dbname); /* 現在の接続を"testdb1"に切り替える。 */ EXEC SQL SET CONNECTION con1; EXEC SQL SELECT current_database() INTO :dbname; printf("current=%s (should be testdb1)\n", dbname); EXEC SQL DISCONNECT ALL; return 0; }
この例は、次のような出力を生成します。
current=testdb3 (should be testdb3) current=testdb2 (should be testdb2) current=testdb1 (should be testdb1)
3つ目の選択肢は、接続に結び付いたSQL識別子を宣言することです。
EXEC SQL ATconnection-name
DECLAREstatement-name
STATEMENT; EXEC SQL PREPAREstatement-name
FROM :dyn-string
;
一度SQL識別子を接続に結び付ければ、AT句なしに動的なSQLを実行できます。 この選択肢はプリプロセッサ指示子のように振る舞いますので、結び付けはファイルの中でのみ可能です。
以下にこの選択肢を使用したプログラムの例を示します。
#include <stdio.h> EXEC SQL BEGIN DECLARE SECTION; char dbname[128]; char *dyn_sql = "SELECT current_database()"; EXEC SQL END DECLARE SECTION; int main(){ EXEC SQL CONNECT TO postgres AS con1; EXEC SQL CONNECT TO testdb AS con2; EXEC SQL AT con1 DECLARE stmt STATEMENT; EXEC SQL PREPARE stmt FROM :dyn_sql; EXEC SQL EXECUTE stmt INTO :dbname; printf("%s\n", dbname); EXEC SQL DISCONNECT ALL; return 0; }
この例は、たとえデフォルトの接続がtestdbであったとしても、次のような出力を生成します。
postgres
接続を閉じるには以下のSQL文を使用します。
EXEC SQL DISCONNECT [connection
];
connection
は以下の方法で指定されます。
connection-name
CURRENT
ALL
接続名の指定がなければ、現在の接続が閉じられます。
アプリケーションでは、過去に開いたすべての接続を明示的に閉じることを推奨します。