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

ITAGAKI Takahiro itagaki.takahiro @ oss.ntt.co.jp
2008年 7月 18日 (金) 18:47:01 JST


"EBIHARA, Yuichiro" <ebihara @ iplocks.co.jp> 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 @ oss.ntt.co.jp>





pgsql-jp メーリングリストの案内