citext
предоставляет операторы без учета регистра для использования в базе данных с другими значениями citext.
Что происходит
Предположительно, ваша реализация JPA явно указывает тип параметра как text
при создании параметризованного оператора. citext
не определяет оператор citext = text
, поэтому PostgreSQL преобразует 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
в text
с использованием неявного преобразования citext
в текст, а затем выполнит сравнение 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)
где тип указывается как text
при привязке параметра, поскольку Hibernate «знает», что строки - это text
.
Другими словами, вам нужно, чтобы Hibernate через PgJDBC явно указывал тип данных citext
в качестве типа параметра для вашего запроса, в результате получалось что-то вроде:
regress=# PREPARE blah(citext) AS SELECT * FROM citest WHERE x = $1;
PREPARE
regress=# EXECUTE blah('FRED');
x
------
FRED
FrEd
(2 rows)
Обратите внимание на явный параметр типа citext
для подготовленного оператора. Это будет ... интересно ... сделать, тем более что PgJDBC ничего не знает о типе citext
. Вам нужно будет написать обработчик пользовательского типа данных для Hibernate, который использует setObject
PgJDBC; даже тогда у вас будут проблемы с согласованностью операторов между Java и Pg (см. ниже).
ИМО, вам будет намного лучше использовать традиционные типы с учетом регистра и lower()
, ILIKE
и т. Д.
Также возможно, что Hibernate полагается на то, что PgJDBC сообщает ему о чувствительности к регистру столбцов. По крайней мере, начиная с версии 9.2, PgJDBC ничего не знает о типе citext
, поэтому всегда будет отвечать «да, это чувствительно к регистру», когда его спросят.
Отслеживание
Трудно быть уверенным в том, что происходит, не видя фактических запросов, выполняемых JPA. Попробуйте установить log_statement = 'all'
в postgresql.conf
. Затем SIGHUP
почтмейстер, используйте pg_ctl reload
или перезапустите Pg, чтобы изменения вступили в силу.
Повторно запустите тест и изучите журналы. Протестируйте запросы, которые вы видите в psql
, чтобы увидеть результаты. Если вы не уверены в том, что происходит, обновите свой вопрос, указав им. При обновлении также укажите версию Hibernate и версию PgJDBC.
Также возможно, что Hibernate полагается на то, что PgJDBC сообщает ему о чувствительности к регистру столбцов. По крайней мере, начиная с версии 9.2 PgJDBC ничего не знает о типе citext
, поэтому всегда будет отвечать «да, это чувствительно к регистру», когда его спросят.
Трудности с согласованностью оператора
ПРЕДУПРЕЖДЕНИЕ: тип citext
не может повлиять на работу Hibernate с текстом после его извлечения из базы данных. Например, это не повлияет на метод String.equals
. Вам нужно будет указать Hibernate, чтобы он обрабатывал текст как нечувствительный к регистру. В противном случае, если у вас есть text
или varchar
первичный / внешний ключ, вы можете получить ситуации, когда Hibernate запрашивает ключ "FRED"
, он возвращает "FrEd"
обратно, и это довольно сбивает с толку, потому что БД вернула ключ, который не равен - согласно Hibernate - к тому, о котором его просили. Аналогичные странности возникнут, если вы включите строки с citext
поддержкой в реализации equals
и hashCode
в своих сущностях.
К сожалению, JPA, похоже, не указывает атрибуты аннотации в сопоставлении @Column
для того, чувствителен ли столбец к регистру или нет. Java не поддерживает в любом случае имеют концепцию строкового типа данных без учета регистра, поэтому он не принесет много пользы, даже если JPA определит его.
Вероятно, вы избежите слишком большой путаницы с Hibernate, если не будете использовать citext
для ключей и не включать citext
значения в equals
и hashCode
.
person
Craig Ringer
schedule
20.08.2012