发布说明

PostgreSQL 16.5

E.9. 发布版本 16.5 #

发布日期:. 2024-11-14

本次发布包含来自 16.4 的多项修复。 有关 16 主版本新特性的说明,请参见 Section E.14

E.9.1. 迁移到版本 16.5 #

对于运行 16.X 的用户,不需要执行导出/恢复。

但是,如果你曾经从一个具有引用另一个分区表的外键的分区表中分离过分区, 并且没有删除该原分区,那么你可能需要修复目录和/或数据损坏, 详情请参见下面的第五个变更日志条目。

此外,如果你从早于 16.3 的版本升级,请参见 Section E.11

E.9.2. 变更 #

  • 确保当 RLS 应用于非顶层表引用时,缓存的计划被标记为依赖于调用角色 (Nathan Bossart) §

    如果查询中的 CTE、子查询、子链接、安全调用者视图或强制转换投影引用了具有行级安全策略的表, 我们忽略了将结果计划标记为可能依赖于执行它的角色。这可能导致同一会话中后续的查询执行 使用错误的计划,从而返回或隐藏本应被隐藏或返回的行。

    PostgreSQL 项目感谢 Wolfgang Walther 报告此问题。 (CVE-2024-10976)

  • 使 libpq 丢弃在 SSL 或 GSS 协议协商期间收到的错误消息 (Jacob Champion) §

    在加密协商完成之前收到的错误消息可能是由中间人注入的,而非真正的服务器输出。 报告这些消息会带来各种安全隐患;例如,该消息可能伪造查询结果, 粗心的用户可能会将其误认为正确的输出。最好的做法是丢弃此类数据, 仅依赖 libpq 自身的连接失败报告。

    PostgreSQL 项目感谢 Jacob Champion 报告此问题。 (CVE-2024-10977)

  • 修复 SET SESSION AUTHORIZATIONSET ROLE 之间的意外交互 (Tom Lane) § §

    SQL 标准要求 SET SESSION AUTHORIZATION 具有执行 SET ROLE NONE 的副作用。我们对此的实现存在缺陷, 导致这两个设置之间产生了超出预期的交互。值得注意的是,回滚一个已执行 SET SESSION AUTHORIZATION 的事务会将 ROLE 恢复为 NONE,即使之前的状态并非如此, 因此有效用户 ID 可能与事务之前的不同。在函数 SET 子句中临时设置 session_authorization 也有类似的影响。一个相关的错误是,如果并行工作进程检查 current_setting('role'),它会看到 none,即使应该看到其他值。

    PostgreSQL 项目感谢 Tom Lane 报告此问题。 (CVE-2024-10978)

  • 防止受信任的 PL/Perl 代码更改环境变量 (Andrew Dunstan,Noah Misch) § § § § §

    操纵诸如 PATH 之类的进程环境变量的能力给攻击者提供了 执行任意代码的机会。因此,受信任的 PL 不应提供这样做的能力。 为修复 plperl,将 %ENV 替换为一个 绑定哈希,该哈希拒绝任何修改尝试并发出警告。 不受信任的 plperlu 保留更改环境的能力。

    PostgreSQL 项目感谢 Coby Abrams 报告此问题。 (CVE-2024-10979)

  • 修复在附加或分离表分区时外键约束的目录状态更新 (Jehan-Guillaume de Rorthais,Tender Wang,Álvaro Herrera) § §

    如果被引用的表是分区表,则引用表作为独立表与作为分区时需要不同的目录条目。 ATTACH/DETACH PARTITION 命令未能正确执行此转换。特别是,在 DETACH 之后,现在独立的表会缺少外键强制触发器, 这可能导致该表后来包含违反外键约束的行。随后的重新 ATTACH 也可能因令人困惑的错误而失败。

    修复方法是对现在独立的表中的每个有问题的约束执行 ALTER TABLE DROP CONSTRAINT,然后重新添加该约束。如果重新添加约束失败, 则说明已有错误数据存在。你需要手动重建引用表和被引用表之间的一致性, 然后重新添加约束。

    以下查询可用于识别损坏的约束并构建重建它们所需的命令:

    SELECT conrelid::pg_catalog.regclass AS "constrained table",
           conname AS constraint,
           confrelid::pg_catalog.regclass AS "references",
           pg_catalog.format('ALTER TABLE %s DROP CONSTRAINT %I;',
                             conrelid::pg_catalog.regclass, conname) AS "drop",
           pg_catalog.format('ALTER TABLE %s ADD CONSTRAINT %I %s;',
                             conrelid::pg_catalog.regclass, conname,
                             pg_catalog.pg_get_constraintdef(oid)) AS "add"
    FROM pg_catalog.pg_constraint c
    WHERE contype = 'f' AND conparentid = 0 AND
       (SELECT count(*) FROM pg_catalog.pg_constraint c2
        WHERE c2.conparentid = c.oid) <>
       ((SELECT count(*) FROM pg_catalog.pg_inherits i
        WHERE (i.inhparent = c.conrelid OR i.inhparent = c.confrelid) AND
          EXISTS (SELECT 1 FROM pg_catalog.pg_partitioned_table
                  WHERE partrelid = i.inhparent)) +
        CASE WHEN pg_catalog.pg_partition_root(conrelid) = confrelid THEN
                  (SELECT count(*) FROM pg_catalog.pg_partition_tree(confrelid)
                    WHERE level = 1)
             ELSE 0 END);
    

    由于一个或多个 ADD CONSTRAINT 步骤可能会失败,你应该将查询输出保存到文件中, 然后尝试执行每个步骤。

  • 避免在对分区表的查询与 DETACH CONCURRENTLY 及立即删除分区并发执行时 可能出现的崩溃和 could not open relation 错误 (Álvaro Herrera,Kuntal Gosh) § §

  • 当待附加的表具有引用分区表的外键时,禁止执行 ALTER TABLE ATTACH PARTITION (Álvaro Herrera) § §

    不支持这种安排,并且创建它的其他方式已经会失败。

  • 当查询中键列的排序规则与分区键的排序规则不匹配时,不使用按分区的连接或分组 (Jian He,Webbo Han) § §

    此类计划可能产生不正确的结果。

  • 修复当 UNION ALL 成员查询的输出需要排序且排序列为表达式时 可能出现的 could not find pathkey item to sort 错误 (Andrei Lepikhov,Tom Lane) §

  • 修复涉及将外连接下的子查询展平后又将外连接简化为普通连接时的性能回退 (Tom Lane) §

    v16 未能像之前版本那样良好地优化某些查询,原因是查询提升逻辑的过度简化。

  • 允许取消大型哈希索引构建的第二阶段(Pavel Borisov) §

  • 修复 COPY (query) TO ... 中当 queryDO INSTEAD NOTIFY 规则重写时的断言失败或令人困惑的错误消息 (Tender Wang,Tom Lane) §

  • 修复当 json_objectagg() 调用包含 volatile 函数时的服务器崩溃 (Amit Langote) §

  • 修复 JSON 对象构造函数中的键唯一性检查(Junwang Zhao,Tomas Vondra) §

    在构建大于一千字节的对象时,可能会接受包含重复对象键的无效输入, 或者错误地报告存在重复键。

  • 修复并行哈希连接期间倾斜数据的检测(Thomas Munro) §

    在对哈希连接的内侧进行重新分区(因为某个分区累积了太多元组)之后, 我们会检查是否该分区的所有元组都进入了同一个子分区,这表明它们具有相同的哈希值, 进一步的重新分区无法改善情况。此检查在某些情况下出现故障, 允许重复进行无效的重新分区,最终导致资源耗尽错误。

  • 禁止包含非 ASCII 字符的区域设置名称(Thomas Munro) §

    这仅在 Windows 上是一个问题,因为其他平台不使用此类区域设置名称。 它们存在问题是因为完全不清楚此类名称用什么编码表示 (因为区域设置本身定义了要使用的编码)。在最近的 PostgreSQL 版本中,由于对此的混淆, 可能会在 Windows 运行时库中发生中止。

    遇到新错误消息的用户应该使用 Windows Locale Builder 创建一个具有纯 ASCII 名称的 重复区域设置,或者考虑使用符合 BCP 47 的区域设置名称, 如 tr-TR

  • 修复提交可序列化事务时的竞态条件(Heikki Linnakangas) §

    对最近提交的事务的错误处理可能导致断言失败或 could not access status of transaction 错误。

  • 修复 COMMIT PREPARED 中导致孤立 2PC 文件的竞态条件 (wuchengwen) §

    并发的 PREPARE TRANSACTION 可能导致 COMMIT PREPARED 不删除已完成事务的磁盘上两阶段状态文件。 没有立即的不良影响,但随后的崩溃恢复可能因 could not access status of transaction 而失败, 需要手动删除孤立文件以恢复服务。

  • 避免在 VACUUM FULL 过程中跳过无效 toast 索引后发生无效内存访问 (Tender Wang) §

    在此代码路径中,跟踪尚未重建索引的列表未被正确更新, 有可能导致后续的断言失败或崩溃。

  • 修复就地目录更新可能丢失的问题(Noah Misch) § § § § § § §

    正常的行更新会写入行的新版本以保持事务的可回滚性。但是,某些系统目录更新是有意 非事务性的,通过对行进行就地更新来完成。这些补丁修复了可能导致就地更新效果丢失的 竞态条件。例如,可能会忘记已将 pg_class.relhasindex 设置为 true,从而阻止新索引的更新,进而导致索引损坏。

  • 在恢复结束时重置目录缓存(Noah Misch) §

    这可以防止由于使用目录缓存中的过期数据而导致就地目录更新丢失的情况。

  • 避免在持有中断延迟时使用并行查询 (Francesco Degrassi,Noah Misch,Tom Lane) § §

    这种情况在正常情况下不会出现,但可在测试场景中达到,例如将 SQL 语言函数 用作 B-树支持函数(在生产环境中这会非常慢)。如果确实发生, 将导致无限期等待。

  • 在处理 Bind 和 Execute 协议消息开始时,为统计目的报告活跃查询 ID (Sami Imseih) §

    这使得在扩展查询协议中完成的更多工作能够归属于正确的查询。

  • 防止在嵌套过深的 XML 输入中 libxml2 发生栈溢出 (Tom Lane,致谢 Nick Wellnhofer) §

    使用 xmlXPathCtxtCompile() 而非 xmlXPathCompile(),因为后者在 2.13.4 之前的 libxml2 版本中无法保护自身免受递归导致的栈溢出。

  • 修复 XMLSERIALIZE(... INDENT) 结果中的一些空白问题 (Jim Jones) §

    修复对由空白分隔的节点未能缩进的问题,并确保不会添加尾随换行符。

  • 不忽略正在处理带有谓词或表达式的索引的并发 REINDEX CONCURRENTLY (Michail Nikolaev) §

    通常,REINDEX CONCURRENTLY 不需要等待其他表上的 REINDEX CONCURRENTLY 操作。但是,如果另一个 REINDEX CONCURRENTLY 正在处理带有谓词或表达式的索引, 则不应用此优化,因为此类表达式可能包含访问其他表的用户定义代码。 粗心的编码造成了一个竞态条件,使得该规则未被统一应用,可能导致不一致的行为。

  • 修复存在名称冲突时 ORDER BY 列表的错误反解析(Tom Lane) §

    如果 SELECT 中的 ORDER BY 项是一个裸标识符, 解析器首先将其作为 SELECT 的输出列名查找,以兼容 SQL92。 但是,ruleutils.c 期望 SQL99 的解释,即此类名称是输入列名。因此在 (相当不建议的)情况下,当其他列在 SELECT 输出列表中被重命名 以匹配 ORDER BY 中使用的输入列名时,可能会产生视图的不正确显示。 通过在导出的视图文本中对此类名称添加表限定来修复。

  • 修复 EXPLAIN 中的 failed to find plan for subquery/CTE 错误 (Richard Guo,Tom Lane) § §

    当子查询已从计划中完全优化掉(至少在具有常量 false 的 WHERE 条件时是可能的)的情况下, 尝试打印对子查询 RECORD 类型输出字段的引用时会出现此问题。 计划中已经没有可以标识原始字段名的内容,因此回退到为第 N 个记录列打印 fN。 (如果记录输出来自 ROW() 构造函数, 这实际上是正确的做法。)

  • 在更改生成列的类型时禁止使用 USING 子句(Peter Eisentraut) §

    生成列已经有一个指定列内容的表达式,因此包含 USING 没有意义。

  • pg_cursors 视图中忽略尚未定义的 Portal(Tom Lane) §

    在新游标正在设置过程中,用户定义的检查此视图的代码可能会被调用, 如果发生这种情况,将导致空指针解引用。通过将视图定义为排除不完整设置的游标来避免此问题。

  • 修复 32 位机器上 pg_stat_io 视图的不正确输出 (Bertrand Drouvot) §

    stats_reset 时间戳列在此类硬件上包含垃圾值。

  • 防止 trailing junk after numeric literal 错误消息的编码错误(Karina Litskevich) §

    我们不允许标识符直接出现在数字文本之后(两者之间必须有空白)。如果一个多字节字符 紧跟在数字文本之后,关于它的语法错误消息只包含该字符的第一个字节, 导致向客户端报告和 postmaster 日志文件中的编码问题。

  • 避免在解码涉及插入列默认值的事务时出现 unexpected table_index_fetch_tuple call during logical decoding 错误(Takeshi Ideriha,Hou Zhijie) § §

  • 减少逻辑解码的内存消耗(Masahiko Sawada) §

    使用更小的默认块大小来存储逻辑复制期间接收的元组数据。这减少了内存浪费, 据报告在处理长时间运行的事务时该问题非常严重,甚至导致内存不足错误。

  • 在逻辑复制应用工作进程中,确保在错误或应用工作进程关闭期间不推进源进度 (Hayato Kuroda,Shveta Malik) §

    这可以避免事务丢失的可能性,因为一旦源进度点被推进, 源服务器就不会再次发送该数据。

  • 重新禁用发送无状态(TLSv1.2)会话票据(Daniel Gustafsson) §

    之前为防止发送有状态(TLSv1.3)会话票据的更改意外地重新启用了无状态票据的发送。 因此,虽然我们旨在防止客户端认为支持 TLS 会话恢复,但有些客户端仍然这样认为。

  • 避免在删除具有大量 ACL(权限)条目的数据库时出现 wrong tuple length 错误(Ayush Tiwari) § §

  • 允许在并行工作进程中调整 session_authorizationrole 设置(Tom Lane) §

    我们的代码旨在允许通过函数 SET 子句设置可修改的服务器设置, 但在并行工作进程中不允许其他方式。然而这两个设置的 SET 子句会失败。

  • 修复当 CALL 位于 PL/pgSQL 的 EXCEPTION 块内时,从 CALL 语句的参数列表中调用稳定函数的行为(Tom Lane) §

    与之前季度发布中的类似修复一样,此情况允许这些函数被传入错误的快照, 导致它们看到自外部事务开始以来已修改的行的过期值。

  • 修复 PL/pgSQL 的 CALL 边缘情况中的 cache lookup failed for function 错误(Tom Lane) §

  • 修复我们的备用(非 OpenSSL)MD5 实现在大端硬件上的线程安全性 (Heikki Linnakangas) §

    线程安全性目前在服务器中不是问题,但对 libpq 而言是一个问题。

  • 以与其他整数值选项相同的方式解析 libpqkeepalives 连接选项(Yuto Sasaki) §

    此处使用的编码会拒绝选项值中的尾随空白,这与其他情况不同。 例如,这在 ecpg 的用法中会造成问题。

  • 避免在 ecpglib 中使用 pnstrdup() (Jacob Champion) §

    该函数在内存不足时会调用 exit(),这在库中是不可取的。 调用代码已经正确地处理了分配失败。

  • 修复 ecpglib 中解析不正确的日期时间输入时的越界读取 (Bruce Momjian,Pavel Nekrasov) §

    可能会尝试读取常量数组起始位置之前的位置。但实际影响似乎很小。

  • 修复 psql 中重复使用 \bind 时的内存泄漏 (Michael Paquier) §

  • 避免在 psql\watch 命令中指定小于 1ms 的间隔时挂起 (Andrey Borodin,Michael Paquier) §

    改为将其视为零间隔(执行之间不等待)。

  • 修复 pg_dump 对持久性与其所属表不同的标识序列的处理 (Tom Lane) §

    从 v15 开始,可以将标识序列设置为 LOGGED,而其所属表为 UNLOGGED,反之亦然。 但是,pg_dump 用于重建这种情况的方法在二进制升级模式下失败, 导致当存在此类序列时 pg_upgrade 失败。 通过为 ADD/ALTER COLUMN GENERATED AS IDENTITY 引入新选项来修复, 允许在创建时正确设置序列的持久性。请注意,这意味着从包含此类序列的数据库导出的转储 只能加载到此小版本或更新版本的服务器中。

  • pg_rewind 的调试输出中包含源时间线历史 (Heikki Linnakangas) §

    这原本就是设计意图,但一个编码错误导致源历史始终打印为空。

  • 避免在 vacuumdb 和并行 reindexdb 中尝试对临时表和索引重建索引 (VaibhaveS,Michael Paquier,Fujii Masao,Nathan Bossart) § § §

    对其他会话的临时表重建索引是行不通的,但在某些代码路径中缺少跳过它们的检查, 导致不必要的失败。

  • 允许在 contrib/pageinspectcontrib/pgstattuple 的相关函数中检查序列关系 (Nathan Bossart,Ayush Vatsa) § §

    这在过去是允许的,但在引入表的非默认访问方法时被破坏了。

  • 修复 ARM64 平台上不正确的 LLVM 生成代码(Thomas Munro,Anthonin Bonnefoy) §

    在 ARM 平台上使用 JIT 编译时,生成的代码无法支持超过 32 位的重定位距离, 在大内存系统上不幸的代码放置位置可能导致服务器崩溃。

  • 修复几处假设进程启动时间(表示为 time_t)可以放入 long 值的地方(Max Johnson,Nathan Bossart) §

    long 为 32 位的平台上(尤其是 Windows), 此编码在 Y2038 之后会失败。大多数失败仅表现为外观问题, 但值得注意的是 pg_ctl start 会挂起。

  • 修复在 Windows 上使用 Strawberry Perl 构建的问题(Andrew Dunstan) §

  • 将时区数据文件更新至 tzdata 2024b 版本(Tom Lane) § §

    tzdata 版本将旧的 System-V 兼容区域名称更改为 与对应地理区域的副本;例如 PST8PDT 现在是 America/Los_Angeles 的别名。主要可见的变化是, 对于标准化时区引入之前的时间戳,该区域被视为代表所命名位置的 当地平均太阳时。例如,在 PST8PDT 中, timestamptz 输入如 1801-01-01 00:00 之前会被渲染为 1801-01-01 00:00:00-08,但现在会被渲染为 1801-01-01 00:00:00-07:52:58

    此外,还有墨西哥、蒙古和葡萄牙的历史修正。值得注意的是, Asia/Choibalsan 现在是 Asia/Ulaanbaatar 的别名,而不再是一个独立的区域, 主要是因为这两个区域之间的差异被发现基于不可靠的数据。