postgresql 错误:ALTER TYPE ... ADD不能在事务块内运行

uajslkp6  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(6)|浏览(221)

我试图在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迁移运行上述命令时,它失败并抛出上述错误

vm0i2vca

vm0i2vca1#

如前所述,您不能在事务块中编辑枚举,但可以创建新的枚举,步骤如下:
1.对于使用此类型的所有列/表,将类型从request_type更改为varchar

ALTER TABLE table_name
    ALTER COLUMN column_name 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(恢复步骤1):

ALTER TABLE table_name
    ALTER COLUMN column_name TYPE request_type
    USING (column_name::request_type);
mo49yndu

mo49yndu2#

原因在src/backend/commands/typecmds.c中的AlterEnum中的以下注解中给出:

/*
 * 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:^)

xqkwcwgp

xqkwcwgp3#

PostgreSQL shown here早期版本的解决方法:
请注意,这将需要特殊权限,因为它会更改系统表。

  • 'NEW_ENUM_VALUE'替换为所需的值。
  • 'type_egais_units'替换为要更改的枚举的oid。(使用SELECT * FROM pg_enum查找要更新的枚举,在我的示例中,它是一个5位数,如'19969'

声明:

INSERT INTO pg_enum (
    enumtypid, 
    enumlabel, 
    enumsortorder
)
SELECT 
    'type_egais_units'::regtype::oid, 
    'NEW_ENUM_VALUE', 
    (SELECT MAX(enumsortorder) + 1 FROM pg_enum WHERE enumtypid = 'type_egais_units'::regtype)

当然,按照公认答案中的建议升级PostgreSQL可能是最好的。
有人知道如何在从pgAdmin Version 3.5运行查询时避免使用事务吗?(即,使用F5执行时)

tpgth1q7

tpgth1q74#

您可以将查询更改为

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

7ajki6be5#

具体地说,如何使用node-pg-migrate来实现这一点是禁用迁移的事务:

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

wn9m85ua6#

如果更改xml格式日志,请使用<changeSet id="name" author="author" runInTransaction="false">

相关问题