В простом сравнительном тесте в postgres 9.1 и 8.4 получают следующие странные результаты.Отладка postgresql для где 'A' <'a'
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 от «А» является 0x41 и «а» 0x61 так, прямое сравнение значений ASCII должно означать, что «А» меньше, чем «а», или если каким-то случае Инсентив магии затем при как минимум 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 будет работать правильно.
Update: Я пытался воссоздать базу данных, как initdb --locale=C
и «A» < «а» дают ожидаемые результаты там - однако это не объясняет, почему это терпит неудачу в базе данных, созданной в UTF-8.
UTF-8 является * кодировкой * и имеет очень мало сказать о * сопоставлении *. –
Совет. Ваша примерная программа неверна: если вы используете 'setlocale (LC_COLLATE," en_US.UTF-8 "));' он возвращает те же результаты, что и PostgreSQL. Заметьте _both_ измененный локаль (взятый из вашего комментария) _and_ вещь 'LC_COLLATE'. –
Спасибо @ A.H - абсолютно правильно. – Soren