pg_savior
概览
| 扩展包名 | 版本 | 分类 | 许可证 | 语言 |
|---|---|---|---|---|
pg_savior | 0.1.0 | ADMIN | Apache-2.0 | C |
| ID | 扩展名 | Bin | Lib | Load | Create | Trust | Reloc | 模式 |
|---|---|---|---|---|---|---|---|---|
| 5810 | pg_savior | 否 | 是 | 否 | 是 | 否 | 是 | - |
| 相关扩展 | pg_upless safeupdate pg_drop_events pg_cheat_funcs table_log pg_snakeoil pg_auditor temporal_tables |
|---|
-tuplestore_donestoring , breaks on pg18 @ el
版本
| 类型 | 仓库 | 版本 | PG 大版本 | 包名 | 依赖 |
|---|---|---|---|---|---|
| EXT | PIGSTY | 0.1.0 | 1817161514 | pg_savior | - |
| RPM | PIGSTY | 0.1.0 | 1817161514 | pg_savior_$v | - |
| DEB | PIGSTY | 0.1.0 | 1817161514 | postgresql-$v-pg-savior | - |
构建
您可以使用 pig build 命令构建 pg_savior 扩展的 RPM / DEB 包:
pig build pkg pg_savior # 构建 RPM / DEB 包
安装
您可以直接安装 pg_savior 扩展包的预置二进制包,首先确保 PGDG 和 PIGSTY 仓库已经添加并启用:
pig repo add pgsql -u # 添加仓库并更新缓存
使用 pig 或者是 apt/yum/dnf 安装扩展:
pig install pg_savior; # 当前活跃 PG 版本安装
pig ext install -y pg_savior -v 18 # PG 18
pig ext install -y pg_savior -v 17 # PG 17
pig ext install -y pg_savior -v 16 # PG 16
pig ext install -y pg_savior -v 15 # PG 15
pig ext install -y pg_savior -v 14 # PG 14
dnf install -y pg_savior_18 # PG 18
dnf install -y pg_savior_17 # PG 17
dnf install -y pg_savior_16 # PG 16
dnf install -y pg_savior_15 # PG 15
dnf install -y pg_savior_14 # PG 14
apt install -y postgresql-18-pg-savior # PG 18
apt install -y postgresql-17-pg-savior # PG 17
apt install -y postgresql-16-pg-savior # PG 16
apt install -y postgresql-15-pg-savior # PG 15
apt install -y postgresql-14-pg-savior # PG 14
创建扩展:
CREATE EXTENSION pg_savior;
用法
来源:README, release 0.1.0, PGXN 0.1.0, SQL file, C source, pg_savior.control
pg_savior 是一个 PostgreSQL 安全扩展,用于在执行前阻止特定高风险 DML 和 DDL 语句。版本 0.1.0 是有意发布到 PGXN 的版本,并且相对 0.0.1 进行了重大重写;README 仍将其标记为 pre-1.0,且未准备好用于生产。
激活
仅执行 CREATE EXTENSION 不会激活检查。SQL 文件只说明保护逻辑位于已加载的 shared library 中,因此每个 backend 都必须通过一种上游支持的路径加载 pg_savior:
集群级激活使用 shared_preload_libraries,并需要重启 PostgreSQL:
shared_preload_libraries = 'pg_savior'
新连接的会话级激活可以在 config reload 后使用 session_preload_libraries:
session_preload_libraries = 'pg_savior'
开发或测试会话可以手动加载 library:
LOAD 'pg_savior';
CREATE EXTENSION pg_savior;
library 加载后,_PG_init 会为该 backend 安装 post_parse_analyze_hook、ExecutorStart_hook 和 ProcessUtility_hook。
DML 保护
pg_savior 会阻止没有 WHERE 子句的 DELETE 和 UPDATE 语句。parser hook 检查分析后的 Query tree 并抛出 ERROR,因此事务会中止,应用会看到失败。
CREATE TABLE emp (id int);
INSERT INTO emp VALUES (1), (2), (3);
DELETE FROM emp;
-- ERROR: pg_savior: DELETE without WHERE clause is blocked
UPDATE emp SET id = id + 1;
-- ERROR: pg_savior: UPDATE without WHERE clause is blocked
DELETE FROM emp WHERE id = 1;
-- allowed
可选的行数保护适用于 planner estimate 超过 pg_savior.max_rows_affected 的 DELETE 和 UPDATE 语句。它从 ExecutorStart_hook 运行,在规划之后、触碰 tuple 之前生效。
SET pg_savior.max_rows_affected = 100;
DELETE FROM emp WHERE id > 0;
-- blocked if the planner estimate is greater than 100 rows
DDL 保护
ProcessUtility_hook 只保护上游列出的 DDL 操作:
- 没有
CONCURRENTLY的CREATE INDEX总是被阻止。 DROP DATABASE总是被阻止。- 当目标表大于
pg_savior.large_table_threshold_rows时,ALTER TABLE ADD COLUMN ... DEFAULT被阻止。 - 大表上的
ALTER TABLE ALTER COLUMN TYPE被阻止。 - 当任一目标表是大表时,
TRUNCATE被阻止。 - 当任一目标表是大表时,
DROP TABLE被阻止。
大表检查使用 pg_class.reltuples > pg_savior.large_table_threshold_rows。
CREATE INDEX emp_idx ON emp (id);
-- ERROR: pg_savior: CREATE INDEX without CONCURRENTLY is blocked
CREATE INDEX CONCURRENTLY emp_idx ON emp (id);
-- allowed by this guard
ALTER TABLE big_emp ADD COLUMN status text DEFAULT 'active';
-- blocked when big_emp is over pg_savior.large_table_threshold_rows
TRUNCATE big_emp;
-- blocked when big_emp is over pg_savior.large_table_threshold_rows
配置
所有已文档化的 GUC 都是 session-scoped USERSET 变量:
| GUC | Default | Effect |
|---|---|---|
pg_savior.enabled | on | 总开关;为 off 时不运行检查。 |
pg_savior.bypass | off | 允许当前 session 跳过保护。 |
pg_savior.max_rows_affected | 0 | 当估计的 DELETE/UPDATE 行数高于该值时阻止;0 禁用该检查。 |
pg_savior.large_table_threshold_rows | 1000000 | 为受保护的大表 DDL 操作定义 “large”。 |
有意绕过一个事务时使用 SET LOCAL:
BEGIN;
SET LOCAL pg_savior.bypass = on;
DELETE FROM staging_table;
COMMIT;
注意事项
- 保护生效前,library 必须先在 backend 中加载;
CREATE EXTENSION pg_savior只注册扩展元数据。 - 行数保护和大表保护依赖 planner/catalog estimate。近期变更导致 estimate 过期时,应运行
ANALYZE。 UPDATE覆盖范围限于无保护的UPDATE和可选 planner-estimate 阈值;README 未声称会语义审查每个WHEREpredicate。- DDL 覆盖范围限于列出的
ProcessUtility_hookcase。不要假设其他 schema 变更会被阻止。 ADD COLUMN ... DEFAULT保护较保守,会阻止大表上的任何 default,包括较新 PostgreSQL 版本可能无需 full table rewrite 处理的 non-volatile default。