citextデータベース内で使用する大文字と小文字を区別しない演算子を、他の citext 値とともに提供します。
何が起こっていますか
text推測では、JPA 実装は、パラメーター化されたステートメントを作成するときのように、パラメーターの型を明示的に指定しています。citextは演算子を定義しないため、citext = textPostgreSQL は をキャストcitextしtext、大文字と小文字を区別するtext = text演算子を使用します。実際には、との比較citextでtextは大文字と小文字が区別されます。
これが私が起こっていると思うことです。ダミーデータが与えられた場合:
regress=# CREATE EXTENSION citext;
regress=# CREATE TABLE citest ( x citext );
regress=# INSERT INTO citest(x) VALUES ('FRED'), ('FrEd');
regress=# SELECT * FROM citest;
x
------
FRED
FrEd
(2 rows)
... citext と不明な文字列リテラルの比較は、citext=citext大文字と小文字を区別せずに次のように解釈されます。
regress=# SELECT * FROM citest WHERE x = 'FRED';
x
------
FRED
FrEd
(2 rows)
citext...しかし、 とを明示的にtext型指定されたリテラルと比較すると、citext引数がtextusingcitextの暗黙的なテキストへのキャストに変換され、大文字とtext=text 小文字を区別する比較が行われます。
regress=# SELECT * FROM citest WHERE x = 'FRED'::text;
x
------
FRED
(1 row)
むしろ、Hibernate が行っていることは次のようになります。
regress=# PREPARE blah(text) AS SELECT * FROM citest WHERE x = $1;
PREPARE
regress=# EXECUTE blah('FRED');
x
------
FRED
(1 row)
Hibernatetextは文字列がtext.
つまり、PgJDBC を介して Hibernate を取得し、citextデータ型をクエリのパラメータ型として明示的に指定する必要があります。結果は次のようになります。
regress=# PREPARE blah(citext) AS SELECT * FROM citest WHERE x = $1;
PREPARE
regress=# EXECUTE blah('FRED');
x
------
FRED
FrEd
(2 rows)
citext準備されたステートメントへの明示的な型パラメーターに注意してください。citext特にPgJDBCは型について何も知らないので、それは...興味深い...行うことになります。PgJDBC のsetObject;を使用する Hibernate 用のカスタム データ型ハンドラーを作成する必要があります。それでも、Java と Pg の間で演算子の一貫性の問題が発生します (以下を参照)。
lower()IMOでは、従来の大文字と小文字を区別するタイプや、ILIKEなどを使用した方がはるかに優れています。
また、Hibernate が、列の大文字と小文字の区別について PgJDBC が伝える内容に依存している可能性もあります。少なくとも 9.2-devel の時点では、PgJDBC はcitext型について何も認識していないため、尋ねられると常に「はい、大文字と小文字が区別されます」と表示されます。
トレース
JPA によって実行される実際のクエリを見ずに、それが起こっていることを確認することは困難です。で設定log_statement = 'all'してみてくださいpostgresql.conf。次にSIGHUP、postmaster を使用するpg_ctl reloadか、Pg を再起動して、変更を有効にします。
テストを再実行し、ログを調べます。に表示されているクエリをテストしてpsql、結果を観察します。何が起こっているのかわからない場合は、質問を更新してください。更新する場合は、Hibernate のバージョンと PgJDBC のバージョンも含めてください。
また、Hibernate が、列の大文字と小文字の区別について PgJDBC が伝える内容に依存している可能性もあります。少なくとも 9.2-devel の時点では、PgJDBC はcitext型について何も認識していないため、尋ねられると常に「はい、大文字と小文字が区別されます」と表示されます。
オペレーターの一貫性の問題
警告:citextタイプは、Hibernate がデータベースから出てきたテキストをどのように処理するかに影響を与えることはできません。String.equalsたとえば、メソッドには影響しません。テキストの大文字と小文字を区別しないようにHibernateに指示する必要があります。それ以外の場合、textまたはプライマリ/外部キーがある場合、Hibernate が keyをvarchar要求する状況が発生する可能性があり、返され、DB が (Hibernate によると) 等しくないキーを返したため、かなり混乱します。求められました。エンティティに-backed 文字列と実装を含めると、同様の奇妙なことが発生します。"FRED""FrEd"citextequalshashCode
@Column残念ながら、JPA は、列が大文字と小文字を区別するかどうかについて、マッピングで注釈属性を指定していないようです。いずれにせよ、 Javaには大文字と小文字を区別しない文字列データ型の概念がないため、JPA が指定したとしても、あまり効果がありません。
citextfor キーを使用したり、 andにcitext値を含めたりしない限り、Hibernate の混乱を避けることができるでしょう。equalshashCode