ECPGでSELECT FOR UPDATE
Windows版のPostgreSQL 8.4に付いてきたECPGでSELECT ... FOR UPDATEをやってみたときの微妙なメモ。まあ、普通に動くので微妙ではないかもしれないですけど。ちなみに開発環境はVisual C++ 2005。
取り敢えず、テスト用に簡単なテーブルを作ってみる。
序でに申し訳程度にレコードも足しておく。
以下のようなECPGに食わせるコードを書いてみる。
別に
日本語だとここ。
ん?動的SQLを使うと
同じように
とすると特にエラーも吐かず実行できました。ちなみに、動的SQLじゃない場合と同様にどちらも正常に意図した通りに動いてはいます。でも、なんだか「
後、最新のPostgreSQL 9.0.2 Documentationでもそうなんですが、ずっと、
と書かれていますが、
取り敢えず、テスト用に簡単なテーブルを作ってみる。
CREATE TABLE T_TEST (
TEST_ID SERIAL NOT NULL PRIMARY KEY,
TEST_STR VARCHAR(8) DEFAULT '' NOT NULL
);
序でに申し訳程度にレコードも足しておく。
INSERT INTO T_TEST (TEST_STR) VALUES ('aaaa');
INSERT INTO T_TEST (TEST_STR) VALUES ('bbbb');
INSERT INTO T_TEST (TEST_STR) VALUES ('cccc');
INSERT INTO T_TEST (TEST_STR) VALUES ('dddd');
以下のようなECPGに食わせるコードを書いてみる。
EXEC SQL
BEGIN;
EXEC SQL
SELECT TEST_ID
FROM T_TEST
WHERE TEST_ID > 0 FOR UPDATE;
...
EXEC SQL
COMMIT WORK;
...
BEGIN;
で明示的にトランザクションを開始してCOMMIT WORK;
しているので、プリプロセッサecpg(1)
に渡すときには-t
オプションを付けます。で、エラーもなくVisual C++ 2005のビルドまで通るのですが、実行するとSQLCODE
が-202
、SQLSATTE
が07002
なエラーを吐きます。INTO
句がないからなのですが、エラーだからといって別にロックに失敗しているわけでもなくそこでトランザクションがROLLBACK
しているわけでもなく正常に動作してたりします。まあ、デフォルトがEXEC SQL WHENEVER SQLERROR CONTINUE;
なので処理を続行するのはわかるんですが、エラーって続行可能な場合を指すのかなと。SQLWARNING
扱いでも良さそうな気が。兎も角、INTO
句を付ければ解消しそうなので付けてみることに。返ってくる行数が事前にわかるわけでもないので、ここはDESCRIPTOR
を使って以下のように書いてみる。EXEC SQL
BEGIN;
EXEC SQL ALLOCATE DESCRIPTOR test_desc;
EXEC SQL
SELECT TEST_ID
INTO DESCRIPTOR test_desc
FROM T_TEST
WHERE TEST_ID > 0 FOR UPDATE;
EXEC SQL DEALLOCATE DESCRIPTOR test_desc;
...
EXEC SQL
COMMIT WORK;
...
別に
descriptor area
から値を取り出すわけでもないので何となくもったいない感はありますが特にエラーも吐かず実行できます。勿論、ちゃんとロックもかかります。で、マニュアルの32.7. Dynamic SQLを読んでみると、こんな記述が。引用:PostgreSQL 8.4.6 Documentation(32.7. Dynamic SQL)
AnEXECUTE
command can have anINTO
clause, aUSING
clause, both, or neither.
日本語だとここ。
引用:PostgreSQL 8.4.4文書(32.7. 動的SQL)
EXECUTE
コマンドはINTO
句、USING
句、この両方を持つことも、どちらも持たないこともできます。
ん?動的SQLを使うと
INTO
句が省略できるのか?とか思って以下のようにやってみましたが、EXEC SQL BEGIN DECLARE SECTION;
...
const char *sfu_stmt
= "SELECT TEST_ID FROM T_TEST WHERE TEST_ID > ? FOR UPDATE;";
...
EXEC SQL END DECLARE SECTION;
...
EXEC SQL
BEGIN;
EXEC SQL
PREPARE test_query FROM :sfu_stmt;
EXEC SQL
EXECUTE test_query USING 0;
EXEC SQL
DEALLOCATE PREPARE test_query;
...
EXEC SQL
COMMIT WORK;
...
同じように
SQLCODE
が-202
、SQLSATTE
が07002
なエラーを吐きました。この場合もINTO
句は要るようで、EXEC SQL BEGIN DECLARE SECTION;
...
const char *sfu_stmt
= "SELECT TEST_ID FROM T_TEST WHERE TEST_ID > ? FOR UPDATE;";
...
EXEC SQL END DECLARE SECTION;
...
EXEC SQL
BEGIN;
EXEC SQL
PREPARE test_query FROM :sfu_stmt;
EXEC SQL ALLOCATE DESCRIPTOR test_desc;
EXEC SQL
EXECUTE test_query
INTO DESCRIPTOR test_desc USING 0;
EXEC SQL DEALLOCATE DESCRIPTOR test_desc;
EXEC SQL
DEALLOCATE PREPARE test_query;
...
EXEC SQL
COMMIT WORK;
...
とすると特にエラーも吐かず実行できました。ちなみに、動的SQLじゃない場合と同様にどちらも正常に意図した通りに動いてはいます。でも、なんだか「
INTO
句やUSING
句は書かなくて良い場合は書かなくてよい。」と言われているようでなんだか「赤く塗られたところは赤いです。」とか「500円のものは500円です。」と同じような感覚があり、そりゃそうだろうと言いたくなるような仕様ではあります。後、最新のPostgreSQL 9.0.2 Documentationでもそうなんですが、ずっと、
引用:PostgreSQL 9.0.2 Documentation(32.7. Dynamic SQL)
EXEC SQL EXECUTE mystmt INTO v1, v2, v3 USING 37;
と書かれていますが、
:v1, :v2, :v3
と書かないと動作しないはず。このあたりからしてECPGってあんまり使われてないんでしょうね。
コメント 0