2008年7月18日

[pgsql-jp: 39504] Re:8.3の"operator does not exist"エラー


"EBIHARA, Yuichiro" <ebihara@xxxxx> wrote:

> String sql = "DELETE FROM test WHERE value = ?";
> PreparedStatement ps = conn.prepareStatement(sql);
> ps.setString(1, "999");

ここを、setInt に変更すれば大丈夫です。

ps.setInt(1, 999);

> 8.2以前ではこのエラーは発生しないので、8.3のリリースノートに記述されている以下の変更が原因のように見えます。
> 「文字以外のデータ型がTEXTへの自動キャストが行われないようになりました。(Peter, Tom)」
> http://www.postgresql.jp/document/current/html/release-8-3.html#AEN86067

はい。これが関係しているでしょう。ただ、自動キャストが発生した場合、条件列の
インデックスが使えない場合があります。動くことは動くのですが、性能問題の芽を
見逃す場合がありました。8.3 ではエラーになるため、ミスに気付けます。
アプリのバグを減らすためには、まぁ、妥当な仕様変更だと言えるでしょう。

# とはいえ、互換性を保つモードが無いのは、やりすぎだとは思いますが……。


> ここでイマイチよく分からないのが、psqlから次のDELETE文を実行してもうまくいく点です。
> DELETE FROM test WHERE value = '999';

誤解が多いのですが、シングルクォートで囲った '999' の型は "UNKNOWN" であり、
"TEXT" ではありません。UNKNOWN は、他の型への変換が必要になった時点で初めて
その型に変換されます。そのため、value = <integer型> と書くのと同じです。
(ただ、型推論ができなかった場合のデフォルトの変換は、TEXT です。)
一方、
DELETE FROM test WHERE value = CAST('999' AS text);
ではエラーが発生することが確認できるかと思います。


> prepare stmt (integer) as DELETE FROM test WHERE value = $1;
> execute stmt ('999');

こちらは、ちゃんと integer と型を明記 & 一致しているからですよね。
ps.setString() ではなく ps.setInt() と書くことと対応しています。
もちろん、
prepare stmt (text) as DELETE FROM test WHERE value = $1;
としてしまうと、JDBC と同様のエラーになります。

------------------------------------------------------------
板垣貴裕 <itagaki.takahiro@xxxxx>

投稿者 xml-rpc : 2008年7月18日 19:16
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/75451
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。