pg_restore 没有禁用触发器

Posted

技术标签:

【中文标题】pg_restore 没有禁用触发器【英文标题】:pg_restore is not disabling triggers 【发布时间】:2016-04-30 19:57:12 【问题描述】:

使用 PostgreSQL 9.2.8,我试图将我的数据从一个数据库恢复到另一个数据库,但触发器似乎仍在运行。我已经编写了如下所示的脚本来进行复制。

基本上我有dts 作为我的生产数据库,我有DigitalTrafficSystem 作为我的开发数据库。表结构是相同的,但开发者的存储过程非常不同。

当恢复运行时,DigitalTrafficSystem 数据库以一堆在dts 数据库中不存在的额外表行结束,所以我假设这些是由触发器创建的。

对于每个表,我收到的与触发器相关的消息如下所示:

pg_restore: [archiver (db)] could not execute query: ERROR:  permission denied: "RI_ConstraintTrigger_c_136691" is a system trigger
Command was: ALTER TABLE usage ENABLE TRIGGER ALL;

我假设(错误地?)触发器已关闭,但系统级触发器无法被禁用。

这是我的脚本:

#!/bin/sh

PGUSER=dts
FILE=/tmp/.dts.db.$$

# Dump the schema of the DB as we want this to keep
pg_dump -s DigitalTrafficSystem -f $FILE

dropdb -U _postgres DigitalTrafficSystem
if [ $? -ne 0 ]; then
    exit;
fi

createdb -U _postgres -O dts DigitalTrafficSystem
if [ $? -ne 0 ]; then
    exit;
fi

# Restore the schema
psql -d DigitalTrafficSystem -f $FILE

# Dump the data of the real production database
pg_dump -Fc -a dts -f $FILE > /dev/null
if [ $? -ne 0 ]; then
    exit;
fi

# Restore only the data from the real database to our development one
pg_restore -a -d DigitalTrafficSystem --disable-triggers -S dts $FILE

rm $FILE

【问题讨论】:

这绝对是触发器。我运行了除最后一个 pg_restore 之外的所有内容,打开了数据库,并手动删除了所有触发器,然后运行了 pg_restore 命令,我没有出现无效数据。显然,每次我想重写数据库时,我都无法手动执行此操作。 看起来您正在尝试将 --data-only 还原到一个空数据库(新创建,并且不包含表)您的目标数据库中也需要表定义,您不能插入到不存在的表中。 不知何故,我错过了在创建数据库后运行的 psql -d DigitalTrafficSystem -f $FILE 中的复制,该数据库基于转储的架构进行恢复。 【参考方案1】:

我假设(错误地?)触发器已关闭,但仅此而已 无法禁用系统级触发器。

不,因为 SQL 命令的成功与否是全有或全无的问题。失败的命令大概是这样的:

ALTER TABLE usage DISABLE TRIGGER ALL;

如果失败,它将完全失败,而不是完成一半的工作,即禁用用户级触发器并启用 RI 约束触发器。

pg_restore 医生说:

      Presently, the commands emitted for --disable-triggers must be done
      as superuser. So you should also specify a superuser name with -S
      or, preferably, run pg_restore as a PostgreSQL superuser.

   -S username, --superuser=username
       Specify the superuser user name to use when disabling triggers.
       This is relevant only if --disable-triggers is used.

但是您的dts 不是超级用户。根据脚本的其余部分,_postgres 似乎是一个超级用户。既然如此,何不把它传给-S呢?

另一点是,就像 cmets 中的 @wildplasser 注释一样,被全新数据库中的触发器所困扰有点奇怪,因为您的脚本会创建一个数据库并立即运行仅数据导入。我们可以假设是template1 数据库包含这些对象和这些触发器吗? 但是,请注意来自template1 的表中的数据也被导入到新创建的数据库中,因此在转储源和目标中的最终结果之间发现的任何其他行也必须考虑到它们数据库。

【讨论】:

为 -S 参数传递 _postgres 失败说权限被拒绝设置会话授权。 @Gargoyle:我想听从文档的建议:最好以 PostgreSQL 超级用户身份运行 pg_restore 好的,我发现如果我运行psql -U _postgres DigitalTrafficSystem,我可以运行alter user dts SUPERUSER,现在它运行没有错误。谢谢!【参考方案2】:

需要的是 pg_restore 上的一个选项,以仅禁用用户触发器,而不是所有触发器。

pg_restore 问题:ALTER TABLE <table> DISABLE TRIGGER ALL

pg_restore 需要发出这个:ALTER TABLE <table> DISABLE TRIGGER USER

【讨论】:

以上是关于pg_restore 没有禁用触发器的主要内容,如果未能解决你的问题,请参考以下文章

如何仅在一个事务中禁用 PostgreSQL 触发器?

SQL Server 禁用所有触发器 - 找不到对象“XXXX”,因为它不存在或您没有权限

mysql临时禁用触发器

禁用 CICD 构建自动触发,但保持打开以供手动触发

禁用游戏对象时检测 OnTriggerExit

jQuery 不会在禁用按钮上触发悬停事件吗?