在'A'<'a'的地方调试PostgreSQL

Sor*_*ren 2 c linux postgresql debugging libc

在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
Run Code Online (Sandbox Code Playgroud)

“ A”的ascii值为0x41,“ a”为0x61,因此,直接比较ascii值应意味着“ A”小于“ a”,或者如果某些情况下具有敏感性,那么至少A> b和区域性问题,但是再说一次-但是,使用标准Centos5和Fedora16安装将本地设置为标准us_EN.utf8,结果相同。

将调试器附加到postgres进程中,我已经能够找到问题的根源。

strcoll("A","a") returns 6;
Run Code Online (Sandbox Code Playgroud)

哪里

strcoll("A","b") returns -1;
Run Code Online (Sandbox Code Playgroud)

但是,这只能在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));
}
Run Code Online (Sandbox Code Playgroud)

问题是:是否有人对导致strcoll返回错误值的原因有任何想法,以及关于如何修复它以便我的示例SQL可以正常工作的任何建议。

更新:我尝试将数据库重新创建为initdb --locale=C,并且'A'<'a'在此处给出了预期的结果-但是,这不能解释为什么在创建为UTF-8的数据库中此操作会失败。

Erw*_*ter 5

排序取决于您的数据库语言环境,而不是系统语言环境。(尽管应该注意,PostgreSQL依靠OS提供细节。在Postgres Wiki中有更多信息。
ASCII值仅与非语言环境相关"C"

看一下您当前的设置:

SELECT * FROM pg_settings WHERE name ~~ 'lc%';
Run Code Online (Sandbox Code Playgroud)

特别地,的设置LC_COLLATE是相关的。你也可以:

SHOW lc_collate;
Run Code Online (Sandbox Code Playgroud)

在PostgreSQL 9.1中,您可以更改每个语句适用的排序规则。尝试:

SELECT 1 AS one WHERE 'A' < 'a' COLLATE "C";
Run Code Online (Sandbox Code Playgroud)

在较旧的版本中,(大多数情况下)LC_COLLATE您受制于在创建数据库集群时选择的值。

  • @索伦:不是。美国所说的英语以这种方式定义了排序顺序。大写字母“ A”排在小写字母“ a”之后。这些规则可能因语言而异,甚至同一语言的国家/地区也不同。PostgreSQL没有制定这些规则。 (3认同)