Отладка postgresql для где 'A' <'a' - PullRequest
       38

Отладка postgresql для где 'A' <'a'

2 голосов
/ 24 февраля 2012

В простом сравнительном тесте в 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>

1 Ответ

4 голосов
/ 24 февраля 2012

Порядок зависит от вашей базы данных языковой стандарт , а не системный языковой стандарт.(Хотя следует заметить, что PostgreSQL полагается на ОС для предоставления подробностей. Подробнее в Postgres Wiki. )
Значение ASCII имеет отношение только к не локали "C".

Посмотрите на ваши текущие настройки:

SELECT * FROM pg_settings WHERE name ~~ 'lc%';

В частности, настройка для LC_COLLATE актуальна.Вы также можете:

SHOW lc_collate;

В PostgreSQL 9.1 вы можете изменять применимые параметры сортировки для каждого оператора.Попробуйте:

SELECT 1 AS one WHERE 'A' < 'a' COLLATE "C";

В старых версиях вы (в основном) застряли со значением LC_COLLATE, которое вы выбрали при создании кластера базы данных.

...