2012-02-24 5 views
2

postgres 9.1 및 8.4의 간단한 비교 테스트에서 다음과 같은 이상한 결과가 나타납니다.'A'< 'a'에 대한 postgresql 디버깅

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 

'A'의 ASCII 값 0x41을이고 A는이 0x61 너무 ASCII 값의 직선 비교 'A'가 'A'보다 작은 경우, 또는 다음 몇몇 경우 경우 insentive 마법에 있다는 것을 의미한다 있습니다 최소한 A> b 및 Alocale 문제이지만, 다시 한번 - 내 로컬은 같은 결과를 갖는 표준 Centos5 및 Fedora16 설치를 사용하여 표준 us_EN.utf8 설정으로 설정됩니다.

postgres 프로세스에 디버거를 연결하면 문제가 발생했다는 것을 알 수있었습니다.

strcoll("A","b") returns -1; 

가 그러나 이것은 단지 POSTGRES 프로세스 내에서 입증 할 수

strcoll("A","a") returns 6; 

하나 아래에 완벽하게 합리적인 결과를 제공 같은 외부 프로그램 (예 GDB를 부착하는 경우 등). 아무도 strcoll 나쁜 값을 반환하는 원인이 무엇인지에 관해서는 어떤 생각을 가지고 않으며, 그것을 해결하는 방법 같은 제안은 나의 샘플 SQL이 제대로 작동합니다

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)); 
} 

질문입니다.

업데이트 : 나는 initdb --locale=C로 데이터베이스를 다시 시도하고, 'A'< 'A'가 예상 결과를 얻을 수 -이 UTF-8로 작성된 데이터베이스에 실패하는 이유를 설명하지 그러나.

+1

UTF-8은 * 인코딩 *이며 * 데이터 정렬에 대해서는 거의 언급하지 않았습니다. –

+0

팁 : 예제 프로그램이 잘못되었습니다 :'setlocale (LC_COLLATE, "en_US.UTF-8"));을 사용하면 PostgreSQL과 같은 결과를 반환합니다. 메모 _both_ 변경된 로케일 (귀하의 의견에서 가져온 것) _ 및 _ 'LC_COLLATE'것. –

+0

감사합니다. @ A.H - 절대적으로 맞습니다. – Soren

답변

4

주문은 시스템 로캘이 아닌 locale 데이터베이스에 따라 다릅니다. (비록 PostgreSQL은 OS를 사용하여 구체적인 정보를 제공합니다.)
ASCII 값은 비 로케일 "C"에만 관련이 있습니다.

현재 설정에서보세요 :

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

는 특히, LC_COLLATE에 대한 설정이 관련이있다. 또한 할 수 있습니다 :

SHOW lc_collate; 

PostgreSQL 9.1에서는 명령문별로 적용 가능한 조합을 변경할 수 있습니다. 보십시오 : 당신은 (대부분) 데이터베이스 클러스터를 만들 때 선택한 LC_COLLATE의 값으로 붙어있는 이전 버전에서

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

합니다.

+0

감사하지만, 'A'< 'a'가 거짓으로 평가되는 이유는 'A'< 'b'가 참으로 평가되는 이유에 대해서는 대답하지 않습니다. – Soren

+0

@Soren : 그렇습니다. 선택한 로케일의 조합 규칙이 그런 식으로 정의합니다. 'SHOW lc_collate; '는 무엇을 반환합니까? –

+0

'show lc_collate'는 기본 설정으로 생성 된 데이터베이스에 대해'en_US.UTF-8'을줍니다. 그러나 'A'< 'a'가 UTF-8에서 실패하는 이유를 모르겠습니다. – Soren