错误:ALTER TYPE ... ADD无法在事务块内运行

时间:2018-11-05 06:39:59

标签: postgresql enums alter

我正在尝试向PostgreSQL中的现有类型添加新的类型值。但出现以下错误

  

错误:ALTER TYPE ... ADD无法在事务块内运行

我用来向类型添加新值的查询是

ALTER TYPE public.request_type ADD VALUE "Check";

我实际上是在使用node-pg-migrate创建的迁移文件中的查询之上运行的

public是我的架构。

知道为什么会失败吗?

编辑:

在pgadmin中执行以下查询时,其执行正常

ALTER TYPE public.request_type ADD VALUE "Check";

但是当我通过node-pg-migrate迁移运行以上命令时,它会失败并抛出错误

5 个答案:

答案 0 :(得分:5)

AlterEnumsrc/backend/commands/typecmds.c的以下注释中给出了原因:

/*
 * Ordinarily we disallow adding values within transaction blocks,
 * because we can't cope with enum OID values getting into indexes and
 * then having their defining pg_enum entries go away.  However, it's
 * okay if the enum type was created in the current transaction, since
 * then there can be no such indexes that wouldn't themselves go away
 * on rollback.  (We support this case because pg_dump
 * --binary-upgrade needs it.)

请注意,此限制已在commit 212fab99中删除;提交消息显示为:

To prevent possibly breaking indexes on enum columns, we must keep
uncommitted enum values from getting stored in tables, unless we
can be sure that any such column is new in the current transaction.

Formerly, we enforced this by disallowing ALTER TYPE ... ADD VALUE
from being executed at all in a transaction block, unless the target
enum type had been created in the current transaction.  This patch
removes that restriction, and instead insists that an uncommitted enum
value can't be referenced unless it belongs to an enum type created
in the same transaction as the value.  Per discussion, this should be
a bit less onerous.  It does require each function that could possibly
return a new enum value to SQL operations to check this restriction,
but there aren't so many of those that this seems unmaintainable.

因此,您可能希望尽快升级到PostgreSQL v12:^)

答案 1 :(得分:1)

PostgreSQL早期版本shown here的解决方法:

请注意,这将需要特殊权限,因为它会更改系统表。

  • iacp替换为所需的值。
  • temp替换为要更改的枚举的'NEW_ENUM_VALUE'。 (使用'type_egais_units'查找要更新的枚举,在我的情况下,它是一个5位数字,例如oid

声明:

SELECT * FROM pg_enum

当然,按照公认的答案建议升级PostgreSQL可能是最好的选择。

有人知道如何从pgAdmin 3.5版运行查询时避免使用事务吗? (即使用 F5 执行时?)

答案 2 :(得分:1)

您可以将查询更改为

COMMIT;
ALTER TYPE public.request_type ADD VALUE "Check";

答案 3 :(得分:0)

如上所述,您不能在事务块内编辑枚举。但是您可以创建新的。步骤如下:

  1. 对于使用此类型的所有列/表,将类型从 request_type 更改为 varchar
ALTER TABLE table_name ALTER COLUMN request_type TYPE VARCHAR(255);
  1. 拖放并重新创建 request_type 枚举:
DROP TYPE IF EXISTS request_type;
CREATE TYPE request_type AS ENUM ('OLD_VALUE_1', 'OLD_VALUE_2', 'NEW_VALUE_1', 'NEW_VALUE_2'); 
  1. 将所有列/表的类型从 varchar 恢复为 request_type (恢复第一步):
ALTER TABLE table_name ALTER COLUMN request_type TYPE request_type USING (request_type::request_type);

答案 4 :(得分:0)

具体如何使用 node-pg-migrate 执行此操作是禁用迁移事务:

exports.up = (pgm) => {
  pgm.noTransaction()
  pgm.addTypeValue('foo', 'BAR', { ifNotExists: true })
}