我在数据库1中有模式1。我想将 schema1 的所有功能移至数据库 2 中存在的 schema2。我已将数据库1的备份文件恢复到数据库2中。并更改了架构名称。函数调用的模式名称自动更改。但在函数定义中,模式名称不会更改。例如:
CREATE OR REPLACE FUNCTION schema2.execute(..)
BEGIN
select schema1."VALIDATE_SESSION"(....)
end
如何自动将“schema1”更改为“schema2”?
我尝试将当前模式名称存储在变量中并将其附加到表中。但调用
current_schema()
返回“public”。如何获取用户当前创建的模式?因为每次我需要在生成脚本时更改模式名称。
虚拟函数中缺少的基本细节是函数体周围的单引号(或美元引号,都一样)。意思是,函数体被保存为字符串。参见:
相比之下,请考虑在 FK 约束中引用表(或更详细地说:
schema.table(column)
)。对象名称在创建时解析为表的内部 OID(和列号)。 “早期绑定”。当名称(包括模式名称)稍后更改时,这对 FK 完全没有影响。感觉涉及的名称是动态更改的。但实际上,在创建对象之后,实际名称就不再重要了。因此,您可以整天重命名模式,而不会对 FK 产生副作用。
函数body中的名称存储为字符串并在调用时解释。 “后期绑定”。这些名称不会动态更改。
自 Postgres 14 起,此规则有一个例外,但仅适用于
LANGUAGE sql
函数:“SQL 标准函数体”。它们在创建时进行解析,因此它们会尽早绑定,并跟踪模式的 OID,而不是其名称。参见:
除此之外,您必须实际编辑所有函数体,包括硬编码的架构名称。一种可能的替代方案是依赖
search_path
而不是一开始就在函数体中使用模式名称。有各种各样的。参见:
但这并不总是可以接受的。
你可以破解转储。或者在 Postgres 中使用 sting 操作来更新受影响的函数体。使用元查询查找受影响的函数,例如:
SELECT *
FROM pg_catalog.pg_proc
WHERE prosrc ~ '\mschema1\M'; -- not bullet-proof!
无论哪种方式,如果模式名称可以是其他字符串的一部分或作为列名称等弹出,请警惕错误匹配。动态 SQL 可以以任意方式连接字符串。如果你的函数中有这样的恶作剧,你需要妥善处理。