【问题标题】:error: ALTER TYPE ... ADD cannot run inside a transaction block错误:ALTER TYPE ... ADD 不能在事务块内运行
【发布时间】:2019-04-08 12:32:56
【问题描述】:

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

【问题讨论】:

标签: postgresql enums alter


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    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(恢复第一步):
    ALTER TABLE table_name
        ALTER COLUMN column_name TYPE request_type
        USING (column_name::request_type);
    

    【讨论】:

    • 这实际上很好地规避了事务问题,另外您可以使用类似的方法来删除枚举值(postgres 不直接支持)。谢谢!
    • 杀手级解决方案。喜欢 PG 的施法能力!
    • 这是一个不错的解决方案; request_type 被用作列名和类型;也许重命名它们以消除歧义。
    • 完美!我还发现我必须临时更改列的默认值及其类型,因为它还引用了旧的 ENUM 类型,因此阻止了 DROP。
    • 对于 COLUMN 和 TYPE 都使用 request_type 有点令人困惑。在第 3 步中,哪些代表列,哪些代表类型? request_type 在同一行被提及 4 次
    【解决方案3】:

    您可以将查询更改为

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

    【讨论】:

    • 我想它会起作用,但这听起来不是一个好习惯。在我的情况下(以及在问题的情况下),我们正处于迁移脚本的中间。迁移是一个免费的事务——这就是它在没有我们启动事务的情况下工作的方式,它有一个原因:在失败的情况下回滚。如果我们承诺,我们可以做出真正糟糕的问题......
    【解决方案4】:

    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 版本 3.5 运行查询时如何避免使用事务? (即使用 F5 执行时?)

    【讨论】:

      【解决方案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 :^)

      【讨论】:

      • 您好 很抱歉我的回复晚了,感谢您的详细解释。我有什么办法可以在不将其迁移到 v12 的情况下克服这个问题?
      • 您好,我已经更新了我的问题。能否请你帮忙。该问题仅在我运行迁移时发生,但是当我在 pgadmin 中手动执行该查询时,它工作正常
      • node.js 函数可能在事务中运行。不知道如何改变它。也许最好避免使用枚举。如果值可以改变,它们不是一个好主意。
      • Aurora AWS 不支持 PostgreSQL v12 :(
      • @Yitzchak 现在可以了! aws.amazon.com/about-aws/whats-new/2021/01/…
      猜你喜欢
      • 2021-10-21
      • 2021-05-31
      • 2020-12-03
      • 2017-12-11
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多