PostgreSQL 行类型规则导出错误
最近在浏览邮件列表时发现通过 pg_dump 导出带有行类型的规则导出之后无法导入到数据库中,已确认为 bug,目前已被修复。
commit 43c2175121c829c8591fc5117b725f1f22bfb670
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu Jan 13 17:49:25 2022 -0500
Fix ruleutils.c's dumping of whole-row Vars in more contexts.
Commit 7745bc352 intended to ensure that whole-row Vars would be
printed with "::type" decoration in all contexts where plain
"var.*" notation would result in star-expansion, notably in
ROW() and VALUES() constructs. However, it missed the case of
INSERT with a single-row VALUES, as reported by Timur Khanjanov.
Nosing around ruleutils.c, I found a second oversight: the
code for RowCompareExpr generates ROW() notation without benefit
of an actual RowExpr, and naturally it wasn't in sync :-(.
(The code for FieldStore also does this, but we don't expect that
to generate strictly parsable SQL anyway, so I left it alone.)
Back-patch to all supported branches.
Discussion: https://postgr.es/m/efaba6f9-4190-56be-8ff2-7a1674f9194f@intrans.baku.az
现象
首先我们创建两张表和一条规则,如下所示。
1 | CREATE TABLE test(a int); |
当我们向其中插入、删除数据一切正常。
1 | mydb=# INSERT INTO test VALUES (1); |
当我们尝试使用 pg_dump 导出时,一切正常,但是通过 psql 导入时则出现错误了。
1 | $ pg_dump mydb -f mydb.sql |
从 mydb.sql 文件中可以看到错误正好发生在 CREATE RULE
位置处,如下所示:
1 | CREATE RULE del AS |
分析
正如 Tom Lane 在提交日志中所说,提交记录 7745bc352 确保在所有上下文中,当纯 var.*
符号会导致 *
扩展时,尤其是在 row() 和 VALUES() 构造中时,使用 ::type
装饰来打印整行变量。然而,正如 Timur Khanjanov 所报告的那样,它忽略了使用单行值插入的情况。
1 | diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c |
从代码层面来看,主要的修改在于针对 get_rule_expr()
函数进行了封装,当 node
参数仅仅是一个 Var
时,函数 get_variable()
的 istoplevel
参数被设置为 true
,以便其被正确的处理。
笑林广记 - 公子封君
有公子兼封君者,父对之乃欣羡不已。
讶问其故,曰:“你的爷既胜过我的爷,你的儿又胜过我的儿。”