SSブログ

ECPGでSELECT FOR UPDATE

Windows版のPostgreSQL 8.4に付いてきたECPGでSELECT ... FOR UPDATEをやってみたときの微妙なメモ。まあ、普通に動くので微妙ではないかもしれないですけど。ちなみに開発環境はVisual C++ 2005。

取り敢えず、テスト用に簡単なテーブルを作ってみる。

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-202SQLSATTE07002なエラーを吐きます。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)

An EXECUTE command can have an INTO clause, a USING 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-202SQLSATTE07002なエラーを吐きました。この場合も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ってあんまり使われてないんでしょうね。
nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:日記・雑感

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。