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

EBIHARA, Yuichiro ebihara @ iplocks.co.jp
2008年 7月 22日 (火) 11:48:02 JST


板垣さん

お返事ありがとうございます。

2008/07/18 19:16 ITAGAKI Takahiro <itagaki.takahiro @ oss.ntt.co.jp>:
>> 8.2以前ではこのエラーは発生しないので、8.3のリリースノートに記述されている以下の変更が原因のように見えます。
>> 「文字以外のデータ型がTEXTへの自動キャストが行われないようになりました。(Peter, Tom)」
>> http://www.postgresql.jp/document/current/html/release-8-3.html#AEN86067
>
> はい。これが関係しているでしょう。ただ、自動キャストが発生した場合、条件列の
> インデックスが使えない場合があります。動くことは動くのですが、性能問題の芽を
> 見逃す場合がありました。8.3 ではエラーになるため、ミスに気付けます。
> アプリのバグを減らすためには、まぁ、妥当な仕様変更だと言えるでしょう。
>
> # とはいえ、互換性を保つモードが無いのは、やりすぎだとは思いますが……。

そうですか。

この仕様変更は言ってみれば、いわゆる暗黙の型変換を大幅に制限するものと言えますかね?
それに頼るのは元々良いお行儀とは言えませんが、レガシーコードが使っているライブラリが、恐らく簡便性のために一律でPreparedStatement.setObject()してまして、ちょっと(相当?)困ってしまいます。

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

なるほど、これは知りませんでした。

マニュアルの記述は説明を簡単にするために敢えて触れていないということなのでしょうか。それにしても注記があるとうれしいですが。
http://www.postgresql.jp/document/pg833doc/html/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS

>> 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 と同様のエラーになります。

こちらは二重に勘違いしてました。
以前のJDBCドライバはPreparedStatementを内部的にPREPAREとEXECUTEで実行するオプションがあったので、ドライバの内部動作をシミュレートするつもりでこのケースを持ち出したのですが、今のドライバはネイティブプロトコルに対応していましたね・・・。

とにかく、疑問が全て解決しました。
改めまして、どうもありがとうございました。

--
海老原 雄一郎 / EBIHARA, Yuichiro
 Email: ebihara @ iplocks.co.jp



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