ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

postgres_lsp 的 changingColumnType 规则:用 ALTER COLUMN TYPE 改列类型前的表重写与锁表风险检查

postgres_lsp 的 changingColumnType 规则:用 ALTER COLUMN TYPE 改列类型前的表重写与锁表风险检查 postgres_lsp 的 changingColumnType 规则用 ALTER COLUMN TYPE 改列类型前的表重写与锁表风险检查【免费下载链接】postgres_lspA Language Server for Postgres项目地址: https://gitcode.com/GitHub_Trending/po/postgres_lsp本文以 postgres_lspPostgres Language Server的lint/safety/changingColumnType规则为线索讲解 ALTER TABLE 修改列类型在 PostgreSQL 中可能引发的整表重写table rewrite、ACCESS EXCLUSIVE锁阻塞读写等问题并给出该规则在postgres-language-server.jsonc中的启用配置、安全类型变更白名单以及规则源码级判定逻辑与测试用例帮助你写出可安全上线的迁移脚本。规则速览属性值诊断类别Diagnostic Categorylint/safety/changingColumnType版本Sincevnext默认严重级别Warning警告默认是否推荐recommendedfalse需手动启用灵感来源Sourcessquawk/changing-column-type所属分组safety安全该规则的元信息定义在 crates/pgls_analyser/src/lint/safety/changing_column_type.rs 的declare_lint_rule!宏中pub ChangingColumnType { version: next, name: changingColumnType, severity: Severity::Warning, recommended: false, sources: [RuleSource::Squawk(changing-column-type)], }规则注册于safetylint 组见生成文件 crates/pgls_analyser/src/lint/safety.rs该组包含banDropColumn、banDropTable、avoidWideLockWindow、requireConcurrentIndexCreation等 45 条围绕 DDL 安全性的规则changingColumnType与它们共同构成迁移脚本的“安全护栏”。为什么修改列类型是危险的核心结论修改列类型通常要求整表重写并在此期间持有排他锁阻塞读写。大多数列类型变更需要先获取表上的排他锁exclusive lock随后将整张表重写为新格式对于大表而言重写可能耗时很长期间所有读操作与写操作都会被阻塞即使单条语句执行成功重写也会打破线上客户端的既有假设例如返回结果类型、驱动层面的类型映射从而“破坏现有客户端”。因此changingColumnType规则的触发消息为Changing a column type requires a table rewrite and blocks reads and writes.并附带修复建议Consider creating a new column with the desired type, migrating data, and then dropping the old column.哪些类型变更是安全的并非所有类型变更都需要重写表。规则将以下三类“放宽型”变更视为安全不会触发诊断改为texttext与varchar/char系列类型二进制兼容改为不带长度限制的varchar即去掉长度约束例如varchar(50)→varchar去掉numeric精度约束例如numeric(10,2)→numericdecimal同理。规则给出的合法示例ALTER TABLE core_recipe ALTER COLUMN edits TYPE text;以上三类白名单在规则源码的is_safe_type_widening函数中逐一判定见 crates/pgls_analyser/src/lint/safety/changing_column_type.rsfn is_safe_type_widening(col_def: pgls_query::protobuf::ColumnDef) - bool { // ... 提取目标类型名与 typmods类型修饰符... let has_type_modifier !type_name.typmods.is_empty(); match target_type.to_lowercase().as_str() { // text is always safe — binary compatible with varchar/char text true, // varchar without length is safe (dropping a length constraint) varchar if !has_type_modifier true, // numeric without precision is safe (dropping precision constraint) numeric | decimal if !has_type_modifier true, _ false, } }从源码可以推断出两个判定细节判定依据是“目标类型 是否携带类型修饰符typmods”varchar只有在其后没有长度参数时才安全numeric/decimal只有在其后没有精度参数时才安全。因此ALTER COLUMN ... TYPE varchar(100)依然会被判定为不安全类型名比较不区分大小写目标类型会先经to_lowercase()归一化再参与匹配。触发示例与诊断输出不安全示例触发诊断ALTER TABLE core_recipe ALTER COLUMN count TYPE bigint;运行 lint 后的 CLI 输出如下code-block.sql:1:1 lint/safety/changingColumnType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Changing a column type requires a table rewrite and blocks reads and writes. 1 │ ALTER TABLE core_recipe ALTER COLUMN count TYPE bigint; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 │ i Consider creating a new column with the desired type, migrating data, and then dropping the old column.安全的替代方案对于不安全的类型变更推荐的迁移流程是“新建列 → 迁移数据 → 删除旧列”三步走避免直接ALTER COLUMN TYPE引发长时间锁表-- 1. 新建目标类型列ADD COLUMN 默认不重写已有行所需锁更轻 ALTER TABLE core_recipe ADD COLUMN count_new bigint; -- 2. 分批迁移数据可结合批量 UPDATE 索引控制单次事务时长 UPDATE core_recipe SET count_new count::bigint WHERE count_new IS NULL; -- 3. 删除旧列并重命名新列 ALTER TABLE core_recipe DROP COLUMN count; ALTER TABLE core_recipe RENAME COLUMN count_new TO count;规则如何工作源码级实现规则的执行入口是LinterRule的run方法见 crates/pgls_analyser/src/lint/safety/changing_column_type.rs其判定链路如下将语句解析为pgls_queryAST仅当根节点是AlterTableStmt时继续遍历stmt.cmds中的每条AlterTableCmd只关注subtype() AtAlterColumnType即ALTER COLUMN ... TYPE的命令从命令的def中取出ColumnDef调用is_safe_type_widening判断是否为白名单内的安全放宽若不属于安全放宽则生成一条LinterDiagnostic消息为“Changing a column type requires a table rewrite and blocks reads and writes.”并附带“新建列、迁移数据、删除旧列”的 detail 建议。该规则类型为type Options ()即不接收额外配置参数其行为完全由源码中的白名单逻辑决定。整体分析流程由 crates/pgls_analyser/src/lib.rs 的Analyser::run驱动每个语句依次经过已启用规则的flat_map过滤诊断会附带语句的文本区间span。测试用例验证仓库中提供了对应的快照测试文件位于输入 SQLcrates/pgls_analyser/tests/specs/safety/changingColumnType/basic.sql期望输出crates/pgls_analyser/tests/specs/safety/changingColumnType/basic.sql.snapbasic.sql通过-- expect_lint/safety/changingColumnType注释声明期望触发的规则内容正是文档中的“不安全”示例-- expect_lint/safety/changingColumnType ALTER TABLE core_recipe ALTER COLUMN count TYPE bigint;对应的快照断言诊断输出包含× Changing a column type requires a table rewrite and blocks reads and writes.与i Consider creating a new column with the desired type, migrating data, and then dropping the old column.。该测试由 crates/pgls_analyser/tests/rules_tests.rs 驱动是“文档示例即测试用例”的典型体现可直接作为本地验证规则行为的入口。如何配置该规则默认不随推荐集启用recommended: false需要在配置文件中显式开启。postgres_lsp 使用postgres-language-server.jsonc作为配置文件仓库根目录即有一份示例postgres-language-server.jsonc其中顶层linter.enabled控制 linter 总开关linter.rules控制各规则。将changingColumnType设为error的完整配置{ linter: { rules: { safety: { changingColumnType: error } } } }配置值可为error作为错误阻断或warn作为警告提示也可设为off关闭该规则。由于规则位于safety分组也可以先通过safety: { recommended: true }开启该组推荐规则再单独补充此条。配置文件的解析与规则选项传递链路为配置 →LinterOptions见 crates/pgls_analyser/src/linter_options.rs 中的LinterRules结构→ 经Analyser::new构建规则注册表 → 每次run时按规则过滤执行。完整的 linter 配置结构可参考 crates/pgls_configuration/src/linter/rules.rs。适用场景与使用建议迁移脚本审查CI 集成将 linter 接入 CI仓库提供pgls_cli的check命令相关实现见 crates/pgls_cli/src/commands/check.rs在合并前拦截ALTER COLUMN TYPE类高风险 DDL编辑器内实时提示在 VSCode 等编辑器中使用 postgres_lsp 时开启该规则可在编写 SQL 时即时获得警告替代方案的落地对确实需要改类型的场景优先采用“新建列 → 分批迁移数据 → 删除旧列”并配合lock_timeout、批量化更新等手段缩短锁窗口——仓库中avoidWideLockWindow、requireStatementTimeout等safety组规则可进一步约束锁的持有范围注意规则的“安全白名单”只覆盖了text、无长度varchar、无精度numeric/decimal三类放宽场景其余类型变更一律视为不安全即使某些变更在特定 PostgreSQL 版本中实际可原地完成。因此在严格场景下还应结合目标库版本与具体类型做人工复核。【免费下载链接】postgres_lspA Language Server for Postgres项目地址: https://gitcode.com/GitHub_Trending/po/postgres_lsp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表