字符集和字符序合并规则

在B兼容模式的数据库下,且系统参数b_format_behavior_compat_options含有enable_multi_charset选项时,可以将不同字符集字符序的表达式按一定优先级处理,来确定字符串比较运算时的使用的字符序和表达式的字符集。

字符序优先级

不同表达式字符序优先级由高到低排列如下:

  • COLLATE语法拥有最高优先级。
  • 含有字符序冲突的表达式(如:两个不同字符序的字符串拼接表达式)。
  • 支持字符序的数据类型的列、用户自定义变量、存储过程参数、CASE表达式等。
  • 特定的系统函数(如:version()和opengauss_version()函数表达式)。
  • 字符串常量和绑定参数。
  • NULL表达式。
  • 一个表达式的数据类型不支持字符序,这个表达式拥有最低优先级。

当两个表达式字符序不同时,使用字符序优先级最高的表达式的字符序。

示例:

openGauss=# CREATE TABLE t_utf8(c1 varchar(16) character set utf8mb4 collate utf8mb4_bin);
openGauss=# INSERT INTO t_utf8 VALUES('STRING');

-- 比较时使用utf8mb4_bin字符序,结果为false。
openGauss=#  SELECT c1 = _utf8mb4'string' AS result FROM t_utf8;
 result
--------
 f
(1 row)

-- 比较时使用utf8mb4_general_ci字符序,结果为true。
openGauss=# SELECT c1 = _utf8mb4'string' COLLATE utf8mb4_general_ci AS result FROM t_utf8;
 result
--------
 t
(1 row)

-- 将绑定参数“$1”的字符序定义为collation_connection。
openGauss=# PREPARE test_collation(text) AS SELECT c1 = $1 AS result FROM t_utf8;

-- 绑定参数字符序与字符串常量同级别,即使传入的表达式含有显式的字符序,比较时仍然采用c1的字符序。值得注意的是,这里传入表达式是GBK字符集,绑定参数定义的字符集为UTF8MB4,在执行之前,'string'会进行一次编码转换。
openGauss=# EXECUTE test_collation(_gbk'string' COLLATE gbk_chinese_ci);
 result
--------
 f
(1 row)

-- CASE表达式与c1列同级别,即使表达式含有显式的字符序,比较时仍然采用c1的字符序,二者不相等,输出“same level”。
openGauss=# SELECT CASE _utf8mb4'string' COLLATE utf8mb4_general_ci WHEN c1 THEN 'different level' ELSE 'same level' END AS result FROM t_utf8;
   result
------------
 same level
(1 row)

-- IN子查询与c1列同级别,即使表达式含有显式的字符序,比较时仍然采用c1的字符序,二者不相等。
openGauss=# SELECT c1 FROM t_utf8 WHERE c1 in (SELECT _utf8mb4'string' COLLATE utf8mb4_general_ci);
 c1
----
(0 rows)

当两个相同优先级的表达式字符序不同时,采用以下方式处理:

  • 如果两者字符集相同,优先使用后缀为_bin的字符序。
  • 如果两者字符集相同,优先不使用default字符序。
  • 如果两者字符集不同,优先使用binary字符序。
  • 如果两者字符集不同,且一个为Unicode字符集,另一个不为Unicode字符集,非Unicode字符集的表达式需要转码为Unicode字符集,最终使用Unicode字符集的表达式的字符序。
  • 如果不符合上述情况,两表达式将被标记为字符序冲突,字符序将被标记为无效。
    • COLLATE语法指定同字符集不同字符序产生的冲突,将抛出异常。
    • 产生冲突的字符集与数据库字符集server_encoding不同时,将抛出异常。
    • 无效字符序如果被用作排序运算时(如:>、<等),将抛出异常。
      • 字符串等值比较时,如果字符序无效,将直接作为二进制比较相等。

示例:

openGauss=# CREATE TABLE t_multi_charset(
    c_utf8_bin varchar(16) character set utf8mb4 collate utf8mb4_bin,
    c_utf8_uni varchar(16) character set utf8mb4 collate utf8mb4_unicode_ci,
    c_utf8_gen varchar(16) character set utf8mb4 collate utf8mb4_general_ci,
    c_gbk_chi varchar(16) character set gbk collate gbk_chinese_ci);
openGauss=# INSERT INTO t_multi_charset VALUES('STRING', 'String', 'string', 'STRING');

-- 优先使用utf8mb4_bin字符序比较,结果为false。
openGauss=# SELECT c_utf8_bin = c_utf8_uni FROM t_multi_charset;

-- 字符序冲突,进行二进制比较,结果为false。
openGauss=# SELECT c_utf8_uni = c_utf8_gen FROM t_multi_charset;

-- 显式指定的字符序冲突,抛出异常。
openGauss=# SELECT c_utf8_uni COLLATE utf8mb4_unicode_ci = c_utf8_gen COLLATE utf8mb4_general_ci FROM t_multi_charset;

-- 优先使用utf8mb4_general_ci字符序比较,结果为true。
openGauss=# SELECT c_utf8_gen = c_gbk_chi FROM t_multi_charset;

说明:

  • 只有字符串类型(不包括"char"nameclob)的对象和表达式的字符集可以不同于数据库的字符集。
  • ARRAYXMLJSONTSVECTOR等数据类型含有文本数据,这些数据类型的对象和表达式中的文本数据的字符集必须是数据库字符集。
  • 在字符集和字符序合并规则中,认为 'C'、'POSIX'、'DEFAULT'字符序对应的字符集为server_encoding。
意见反馈
编组 3备份
    openGauss 2024-05-08 00:42:15
    取消