4. 扩展SQL接口与控制文件
一个 PostgreSQL 扩展能否被 CREATE EXTENSION 正确安装、被 ALTER EXTENSION ... UPDATE 平滑升级,取决于三份核心文件的配合:.control 控制文件、安装 SQL 脚本、升级 SQL 脚本。控制文件是扩展的“身份证与元数据”,SQL 脚本是扩展的“安装说明书”,升级脚本则是“版本迁移路线图”。本节围绕这三者的编写规范展开,并给出一个可实际打包的完整示例。
一、.control 文件:扩展的元数据入口
控制文件必须与扩展同名,放在 SHAREDIR/extension/ 下,例如 pg_stat_kcache.control。它由若干 key = 'value' 形式的参数组成,PostgreSQL 在解析时对未知参数会直接报错,因此不能随意添加字段。常用参数如下:
| 参数 | 是否必需 | 作用 |
|---|---|---|
comment | 必需 | 扩展的一句话描述,出现在 \dx 输出中 |
default_version | 必需 | 未指定 VERSION 时安装的版本号 |
module_pathname | 可选 | 替换 SQL 脚本中的 MODULE_PATHNAME 占位符 |
relocatable | 可选 | 是否允许 ALTER EXTENSION ... SET SCHEMA,默认 false |
schema | 可选 | 强制安装到指定 schema,与 relocatable 互斥 |
requires | 可选 | 依赖的其他扩展名,逗号分隔 |
superuser | 可选 | 是否仅超级用户可安装,默认 true |
trusted | 可选 | 是否可由有 CREATE 权限的普通用户安装 |
一个典型控制文件示例:
# pg_stat_kcache.control
comment = 'Kernel statistics gathering for PostgreSQL'
default_version = '2.2.0'
module_pathname = '$libdir/pg_stat_kcache'
relocatable = false
schema = 'public'
requires = 'pg_stat_statements'
superuser = true
trusted = false
注意 module_pathname 通常写成 $libdir/扩展名,PostgreSQL 会将其展开为实际的库目录。SQL 脚本中所有引用共享库函数的地方都应使用 MODULE_PATHNAME 占位符,而不是硬编码路径,这样打包后在不同平台上都能正确加载。
二、安装 SQL 脚本:扩展名--版本.sql
安装脚本命名规则为 扩展名--版本.sql,例如 pg_stat_kcache--2.2.0.sql。当用户执行 CREATE EXTENSION pg_stat_kcache; 时,PostgreSQL 会查找 default_version 对应的安装脚本并整体执行。脚本中通常包含:
- 创建 schema 对象(表、视图、函数、类型、操作符);
- 用
CREATE FUNCTION ... AS 'MODULE_PATHNAME', 'c_symbol' LANGUAGE C绑定 C 函数; - 用
GRANT控制权限; - 用
COMMENT ON补充对象说明。
安装脚本必须满足一个关键约束:脚本执行完毕后,扩展对象集合必须与 pg_extension 中记录的版本一致。因此脚本中不要出现 CREATE EXTENSION、DROP EXTENSION 或事务控制语句,PostgreSQL 会在一个事务中执行整个脚本,失败则整体回滚。
三、升级脚本:扩展名--旧版本--新版本.sql
升级脚本命名规则为 扩展名--源版本--目标版本.sql,例如 pg_stat_kcache--2.1.0--2.2.0.sql。当用户执行 ALTER EXTENSION pg_stat_kcache UPDATE TO '2.2.0'; 时,PostgreSQL 会从当前版本出发,寻找一条由若干升级脚本组成的路径,依次执行。升级脚本中只写“从旧版本到新版本需要做的增量变更”,例如:
-- pg_stat_kcache--2.1.0--2.2.0.sql
ALTER FUNCTION pg_stat_kcache() SET search_path = public;
CREATE FUNCTION pg_stat_kcache_reset() RETURNS void
AS 'MODULE_PATHNAME', 'pg_stat_kcache_reset'
LANGUAGE C STRICT;
COMMENT ON FUNCTION pg_stat_kcache_reset() IS 'Reset kernel statistics counters';
升级脚本同样不能包含事务控制语句,且必须保证执行后对象状态与目标版本一致。如果跨越多个版本,可以只提供相邻版本脚本,让 PostgreSQL 自动串联;也可以提供 2.0.0--2.2.0.sql 这样的跳跃脚本,但要注意路径唯一性,避免出现多条可达路径导致歧义。
四、版本迁移路径与打包结构
下图展示了一个扩展从 2.0.0 到 2.2.0 的版本迁移关系,以及控制文件、安装脚本、升级脚本在打包目录中的位置关系。图中同时标出了 CREATE EXTENSION 与 ALTER EXTENSION ... UPDATE 两条入口路径。
五、打包与验证要点
完成三份文件后,打包通常遵循 PostgreSQL 的 PGXS 构建体系:Makefile 中通过 EXTENSION = pg_stat_kcache、DATA = pg_stat_kcache--2.2.0.sql pg_stat_kcache--2.0.0--2.1.0.sql pg_stat_kcache--2.1.0--2.2.0.sql 声明文件,MODULE_big 或 MODULES 声明共享库,PG_CONFIG 指向目标 PostgreSQL 安装。执行 make install 后,文件会被复制到 SHAREDIR/extension/ 与 PKGLIBDIR。
验证时建议按以下顺序检查:
- 用
pg_config --sharedir确认扩展目录,检查三份文件是否齐全; - 在测试库执行
CREATE EXTENSION pg_stat_kcache VERSION '2.0.0';,确认安装脚本可执行; - 执行
ALTER EXTENSION pg_stat_kcache UPDATE TO '2.2.0';,观察是否按 2.0.0→2.1.0→2.2.0 顺序执行; - 查询
SELECT extname, extversion FROM pg_extension WHERE extname='pg_stat_kcache';,确认版本已变为 2.2.0; - 用
\dx+ pg_stat_kcache查看对象清单,确认新增函数、视图均已注册。
default_version 必须与安装脚本文件名中的版本号严格一致,且该版本必须存在对应的 扩展名--版本.sql。若 default_version 指向一个不存在的脚本,CREATE EXTENSION 会直接报 “could not open extension control file” 或 “extension ... has no installation script” 错误。
把控制文件、安装脚本、升级脚本三者视为一个整体来设计,是扩展可维护性的基础。控制文件决定“能不能装、装到哪、依赖谁”,安装脚本决定“装完是什么样”,升级脚本决定“旧实例如何安全走到新版本”。三者版本号对齐、路径唯一、脚本幂等,扩展才能在不同 PostgreSQL 实例之间稳定分发与演进。