【问题标题】:How can I remove an enum label from pg_enum table in Google Cloud SQL?如何从 Google Cloud SQL 的 pg_enum 表中删除枚举标签?
【发布时间】:2021-05-02 16:51:18
【问题描述】:

我有一个我最近构建的 Node 应用程序 (Express),它使用 Sequelize 连接到 PostgreSQL 实例。我刚刚将它部署到 GCP 并使用 Cloud SQL 来设置数据库。这工作得很好,应用程序正确连接到数据库实例。

但是,在运行迁移时,我得到了这个错误:permission denied for table pg_enum

这发生在我尝试从数据库中删除枚举值的单个迁移中:

module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.sequelize.query(
      `DELETE FROM pg_enum WHERE enumlabel = 'to' AND enumtypid = (SELECT oid FROM pg_type WHERE typname = 'enum_Subscriptions_emailType')`
    ),

  down: (queryInterface, Sequelize) =>
    queryInterface.sequelize.query(`ALTER TYPE "enum_Subscriptions_emailType" ADD VALUE 'to';`)
}

我读过here,因为 Cloud SQL 是一项托管服务,它不会为像我这样的客户提供超级用户权限。还有其他方法可以让我运行此迁移吗?

我也尝试过运行 Cloud Build 进程,但同样失败并出现以下错误:ERROR: connect ENOENT /cloudsql/<project-id>:<project-region>:<db-instance>/.s.PGSQL.5432。作为参考,我的cloudbuild.yaml 文件如下所示:

steps:
- name: 'gcr.io/cloud-builders/yarn'
  args: ['install']
- name: 'gcr.io/cloud-builders/yarn'
  args: ['migrate']
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['app', 'deploy']

我的 package.json 脚本是:

"scripts": {
    "start": "node index.js",
    "migrate": "npx sequelize-cli db:migrate",
    "dev": "set DEBUG=app:* && nodemon index.js",
    "deploy": "gcloud builds submit --config cloudbuild.yaml ."
  }

我还能做些什么来解决这个问题,以便我跟随这个迁移可以运行并且我的应用可以运行?

【问题讨论】:

  • PostgreSQL 不支持从枚举中删除单个值。 postgresql.org/docs/current/datatype-enum.html如果你真的需要这样做,你可以将所有使用枚举的列中的类型更改为文本,删除类型,重新创建没有值的类型并将列改回来。
  • 感谢 Johannes - 但这是我几个月前所做的更改,它在我本地的 postgres 数据库上运行良好。但这似乎给了我关于 Cloud SQL 的问题——关于我能做什么的任何想法?在这之后,我实际上还有 18 个迁移要运行(巧合的是,这些未来的迁移之一实际上完全删除了枚举)
  • 它在本地工作,但它不受 postgres 官方支持。修改系统目录总是有风险的——这就是为什么需要超级用户权限才能这样做。删除 enaum 值的可能工作流程已经在我的第一条评论中:重新创建类型。一种更短的方法是首先创建一个新类型,而不使用您要删除的值,使用不同的名称,然后更改所有列,然后重命名该类型。
  • 我会比@JohannesH 更进一步。直接修改系统目录,即使是超级用户,也是一种可解雇的罪行。如果系统提供的命令无法完成任务(并且删除枚举条目是没有更改命令的条目),那么您需要很长的路要走。正如建议的那样,只需删除当前类型,是的,您需要更改每个引用。另一种选择是将值留在枚举中,但创建一个不允许该值的触发器。
  • 谢谢 JohannesH。还有Belayer——我不知道修改这些有那么糟糕;会记住这一点。作为约翰内斯H。在他的回答中建议,我将注释掉这个迁移,因为我们会在未来的迁移中删除枚举。

标签: postgresql express enums database-migration google-cloud-sql


【解决方案1】:

PostgreSQL 不支持从枚举中删除值。您只能添加新的或重命名现有的。

虽然通过修改系统目录它可能会在某种程度上可靠地工作,但即使这不受官方支持并且出于某种原因需要超级用户权限 - 所以没有办法做到这一点。

支持的方法是重新创建没有值的类型。

CREATE TYPE new_enum AS ENUM('a','b','c');

ALTER TABLE table_using_old_enum
    ALTER COLUMN colum_using_old_enum
    SET DATA TYPE new_enum
        USING colum_using_old_enum::text::new_enum;

DROP TYPE old_enum;

ALTER TYPE new_enum RENAME TO old_enum;

这显然只有在 table_using_old_type 中没有条目仍设置为您要删除的值时才有效 - 您需要首先确保这一点,否则 USING 子句中的类型转换将针对这些值失败。

--

或者,您也可以只注释掉该查询 - 如果您已经知道几分钟后通过稍后的迁移该类型将被完全删除,如果该值一直保留到那时应该不会导致问题。

【讨论】:

  • 这确实工作可靠。如果删除的枚举值恰好在数据库中的任何位置使用,则最终会导致数据损坏。我会避开任何这样做的“迁移”工具。
  • 谢谢@JohannesH。 - 我最终注释掉了有问题的迁移并返回了一个简单的 Promise(因为 Sequelize,我的 ORM,需要在迁移中返回一个承诺) - 因为我稍后删除了整个枚举并用参考表替换它,所以结果对我来说没有问题:)
  • @LaurenzAlbe 没有解决方案可以处理要删除的值仍在任何地方使用的情况。这就是 PostreSQL 不支持这种删除的原因。但是,有办法在事务中首先检查这种情况,只有在不存在这种情况时才继续。
猜你喜欢
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多