В простом сравнительном тесте в postgres 9.1 и 8.4 получаются следующие странные результаты.
postgres=# select 1 one where 'A' < 'a';
one
-----
(0 rows) // ..... I would have expected 1 row
postgres=# select 1 one where 'A' < 'b';
one
-----
1
(1 row) // ...... this looks OK
postgres=# select 1 one where 'A' = 'a';
one
-----
(0 rows) // ...... This also looks OK
postgres=# select 1 one where 'A' > 'a';
one
-----
1
(1 row) // ...... This is inconsistent with the above results
Значение ascii для «A» равно 0x41, а «a» равно 0x61, поэтому прямое сравнение значений ascii должно означать, что «A» меньше, чем «a», или, если какая-то магия нечувствительна к регистру, то по крайней мере A> b и проблема Alocale, но опять же - однако мой локальный установлен на стандартную настройку us_EN.utf8 с использованием стандартных установок Centos5 и Fedora16 с теми же результатами.
Подключив отладчик к процессу postgres, я смог отследить, что проблема в этом;
strcoll("A","a") returns 6;
, где
strcoll("A","b") returns -1;
Однако это можно продемонстрировать только изнутри процесса postgres (например, при подключении gdb), и внешняя программа, подобная приведенной ниже, дает вполне приемлемые результаты.
main()
{
char *a="a";
char *b="b";
char *A="A";
printf("%s\n",setlocale(2,"us_ENG.utf8"));
printf("%d\n",strcoll(A,a));
printf("%d\n",strcoll(A,b));
printf("%d\n",strcoll(a,a));
printf("%d\n",strcoll(b,b));
printf("%d\n",strcoll(a,A));
printf("%d\n",strcoll(b,A));
printf("%d\n",strcoll(b,a));
printf("%d\n",strcoll(A,A));
}
Вопрос в том: Кто-нибудь имеет представление о том, что может заставить strcoll возвращать неверные значения, а также о том, как исправить это, чтобы мой пример SQL работал правильно.
Обновление : я пытался воссоздать базу данных как initdb --locale=C
, и 'A' <'a' дает ожидаемые результаты там - однако это не объясняет, почему это не удается в базе данных, созданной как UTF-8. </p>