PostgreSQL教程FG158-PG扩展基础:创建简单PG扩展插件
本文档风哥主要介绍PostgreSQL数据库扩展的基础知识,包括扩展的概念、结构、创建流程和实际应用场景,风哥教程参考PostgreSQL官方文档Extensions内容,适合数据库开发人员和DBA在生产环境中创建和使用自定义扩展。
Part01-基础概念与理论知识
1.1 PostgreSQL数据库扩展概念
PostgreSQL扩展是一种模块化的方式,用于向数据库添加新功能。扩展可以包含函数、数据类型、操作符、索引方法等。更多视频教程www.fgedu.net.cn。
- 模块化设计,易于安装和卸载
- 可以扩展数据库的功能
- 支持版本管理
- 可以在多个数据库中共享
- 提供了标准的安装和升级流程
1.2 PostgreSQL数据库扩展结构
一个典型的PostgreSQL扩展包含以下文件:
- 控制文件(.control):包含扩展的元数据,如名称、版本、依赖等
- SQL文件:包含创建扩展对象的SQL语句
- C语言文件(可选):包含性能关键部分的C语言实现
- Makefile:用于编译扩展
1.3 PostgreSQL数据库扩展类型
PostgreSQL扩展可以分为以下类型:
- SQL扩展:只包含SQL语句,不包含C语言代码
- C扩展:包含C语言代码,提供更高的性能
- 混合扩展:同时包含SQL和C语言代码
Part02-生产环境规划与建议
2.1 PostgreSQL数据库扩展设计原则
扩展设计原则:单一职责,每个扩展只做一件事;模块化设计,便于维护;版本管理,支持平滑升级;性能优化,考虑执行效率;安全性,避免安全漏洞。
2.2 PostgreSQL数据库扩展性能优化
性能优化建议:使用C语言实现性能关键部分;避免不必要的计算;使用适当的索引;监控扩展执行性能;定期优化扩展代码。
2.3 PostgreSQL数据库扩展安全考虑
安全考虑:避免SQL注入;使用适当的权限控制;验证输入参数;避免特权操作;定期更新扩展以修复安全漏洞。
Part03-生产环境项目实施方案
3.1 PostgreSQL数据库扩展创建流程
3.1.1 扩展创建流程
— 步骤1:创建扩展目录
mkdir -p /tmp/fgedu_extension
cd /tmp/fgedu_extension
— 步骤2:创建控制文件
cat > fgedu_extension.control << 'EOF'
# fgedu_extension.control
comment = 'A simple PostgreSQL extension for fgedu'
default_version = '1.0'
module_pathname = '$libdir/fgedu_extension'
relocatable = false
EOF
-- 步骤3:创建SQL文件
cat > fgedu_extension–1.0.sql << 'EOF'
-- fgedu_extension--1.0.sql
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_hello()
RETURNS TEXT
AS $$
BEGIN
RETURN 'Hello from fgedu extension!';
END;
$$ LANGUAGE plpgsql;
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_add(integer, integer)
RETURNS integer
AS $$
BEGIN
RETURN $1 + $2;
END;
$$ LANGUAGE plpgsql;
-- 创建表
CREATE TABLE IF NOT EXISTS fgedu_extension_log (
id SERIAL PRIMARY KEY,
message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_log_message(text)
RETURNS void
AS $$
BEGIN
INSERT INTO fgedu_extension_log(message)
VALUES($1);
END;
$$ LANGUAGE plpgsql;
EOF
-- 步骤4:创建Makefile
cat > Makefile << 'EOF'
MODULES = fgedu_extension
DATA = fgedu_extension--1.0.sql
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
EOF
-- 步骤5:编译扩展
make
-- 输出结果
gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC -I/usr/local/include/postgresql/server -c -o fgedu_extension.o fgedu_extension.c
ld -shared -o fgedu_extension.so fgedu_extension.o
-- 步骤6:安装扩展
make install
-- 输出结果
/bin/mkdir -p '/usr/local/lib/postgresql'
/bin/install -c -m 755 fgedu_extension.so '/usr/local/lib/postgresql/'
/bin/mkdir -p '/usr/local/share/postgresql/extension'
/bin/install -c -m 644 fgedu_extension.control '/usr/local/share/postgresql/extension/'
/bin/install -c -m 644 fgedu_extension--1.0.sql '/usr/local/share/postgresql/extension/'
3.2 PostgreSQL数据库扩展安装与管理
3.2.1 扩展安装与管理
— 连接数据库
psql -U fgedu -d fgedudb
— 输出结果
psql (18.0)
Type “help” for help.
fgedudb=#
— 安装扩展
CREATE EXTENSION fgedu_extension;
— 输出结果
CREATE EXTENSION
— 查看已安装的扩展
SELECT * FROM pg_extension;
— 输出结果
extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
————+———-+————–+—————-+————+———–+—————
plpgsql | 10 | 11 | f | 1.0 | |
fgedu_extension | 16384 | 2200 | f | 1.0 | |
(2 rows)
— 查看扩展的对象
SELECT nspname, proname FROM pg_proc
WHERE pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = ‘public’)
AND proname LIKE ‘fgedu%’;
— 输出结果
nspname | proname
———+————-
public | fgedu_add
public | fgedu_hello
public | fgedu_log_message
(3 rows)
— 测试扩展函数
SELECT fgedu_hello();
— 输出结果
fgedu_hello
———————-
Hello from fgedu extension!
(1 row)
— 测试加法函数
SELECT fgedu_add(10, 20);
— 输出结果
fgedu_add
———–
30
(1 row)
— 测试日志函数
SELECT fgedu_log_message(‘Test message from extension’);
— 输出结果
fgedu_log_message
——————-
(1 row)
— 查看日志
SELECT * FROM fgedu_extension_log;
— 输出结果
id | message | created_at
—-+————————–+—————————-
1 | Test message from extension | 2026-04-07 22:00:00
(1 row)
— 卸载扩展
DROP EXTENSION fgedu_extension;
— 输出结果
DROP EXTENSION
— 重新安装扩展
CREATE EXTENSION fgedu_extension;
— 输出结果
CREATE EXTENSION
3.3 PostgreSQL数据库扩展升级与维护
3.3.1 扩展升级与维护
— 步骤1:创建升级脚本
cat > fgedu_extension–1.0–1.1.sql << 'EOF'
-- fgedu_extension--1.0--1.1.sql
-- 添加新函数
CREATE OR REPLACE FUNCTION fgedu_multiply(integer, integer)
RETURNS integer
AS $$
BEGIN
RETURN $1 * $2;
END;
$$ LANGUAGE plpgsql;
-- 修改现有函数
CREATE OR REPLACE FUNCTION fgedu_hello()
RETURNS TEXT
AS $$
BEGIN
RETURN 'Hello from fgedu extension v1.1!';
END;
$$ LANGUAGE plpgsql;
-- 添加新表
CREATE TABLE IF NOT EXISTS fgedu_extension_stats (
id SERIAL PRIMARY KEY,
function_name TEXT NOT NULL,
call_count INTEGER DEFAULT 0,
last_called TIMESTAMP
);
EOF
-- 步骤2:更新控制文件
cat > fgedu_extension.control << 'EOF'
# fgedu_extension.control
comment = 'A simple PostgreSQL extension for fgedu'
default_version = '1.1'
module_pathname = '$libdir/fgedu_extension'
relocatable = false
EOF
-- 步骤3:编译并安装
make clean
make
make install
-- 步骤4:升级扩展
ALTER EXTENSION fgedu_extension UPDATE TO '1.1';
-- 输出结果
ALTER EXTENSION
-- 测试升级后的扩展
SELECT fgedu_hello();
-- 输出结果
fgedu_hello
-------------------------
Hello from fgedu extension v1.1!
(1 row)
-- 测试新函数
SELECT fgedu_multiply(10, 20);
-- 输出结果
fgedu_multiply
----------------
200
(1 row)
-- 查看新表
\d fgedu_extension_stats
-- 输出结果
Table "public.fgedu_extension_stats"
Column | Type | Modifiers
--------------+-----------------------------+---------------------------------------------------
id | integer | not null default nextval('fgedu_extension_stats_id_seq'::regclass)
function_name| text | not null
call_count | integer | default 0
last_called | timestamp without time zone |
Indexes:
"fgedu_extension_stats_pkey" PRIMARY KEY, btree (id)
-- 查看扩展版本
SELECT extname, extversion FROM pg_extension WHERE extname = 'fgedu_extension';
-- 输出结果
extname | extversion
-----------------+------------
fgedu_extension | 1.1
(1 row)
Part04-生产案例与实战讲解
4.1 PostgreSQL数据库扩展基础实战
本案例演示创建一个基础的SQL扩展。学习交流加群风哥QQ113257174。
— 步骤1:创建扩展目录
mkdir -p /tmp/fgedu_basic_ext
cd /tmp/fgedu_basic_ext
— 步骤2:创建控制文件
cat > fgedu_basic_ext.control << 'EOF'
# fgedu_basic_ext.control
comment = 'A basic PostgreSQL extension for fgedu'
default_version = '1.0'
relocatable = true
EOF
-- 步骤3:创建SQL文件
cat > fgedu_basic_ext–1.0.sql << 'EOF'
-- fgedu_basic_ext--1.0.sql
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_basic_hello()
RETURNS TEXT
AS $$
BEGIN
RETURN 'Hello from basic extension!';
END;
$$ LANGUAGE plpgsql;
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_basic_greet(text)
RETURNS TEXT
AS $$
BEGIN
RETURN 'Hello, ' || $1 || '!';
END;
$$ LANGUAGE plpgsql;
-- 创建视图
CREATE OR REPLACE VIEW fgedu_basic_info AS
SELECT version() AS postgresql_version,
current_database() AS database_name,
current_user AS current_user;
EOF
-- 步骤4:安装扩展
-- 复制文件到扩展目录
cp fgedu_basic_ext.control /usr/local/share/postgresql/extension/
cp fgedu_basic_ext--1.0.sql /usr/local/share/postgresql/extension/
-- 连接数据库
psql -U fgedu -d fgedudb
-- 安装扩展
CREATE EXTENSION fgedu_basic_ext;
-- 输出结果
CREATE EXTENSION
-- 测试函数
SELECT fgedu_basic_hello();
-- 输出结果
fgedu_basic_hello
------------------------
Hello from basic extension!
(1 row)
-- 测试greet函数
SELECT fgedu_basic_greet('World');
-- 输出结果
fgedu_basic_greet
--------------------
Hello, World!
(1 row)
-- 测试视图
SELECT * FROM fgedu_basic_info;
-- 输出结果
postgresql_version | database_name | current_user
----------------------------------+---------------+--------------
PostgreSQL 18.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.4.0, 64-bit | fgedudb | fgedu
(1 row)
4.2 PostgreSQL数据库扩展高级实战
本案例演示创建一个包含C语言代码的高级扩展。更多学习教程公众号风哥教程itpux_com。
— 步骤1:创建扩展目录
mkdir -p /tmp/fgedu_advanced_ext
cd /tmp/fgedu_advanced_ext
— 步骤2:创建控制文件
cat > fgedu_advanced_ext.control << 'EOF'
# fgedu_advanced_ext.control
comment = 'An advanced PostgreSQL extension for fgedu'
default_version = '1.0'
module_pathname = '$libdir/fgedu_advanced_ext'
relocatable = false
EOF
-- 步骤3:创建C语言文件
cat > fgedu_advanced_ext.c << 'EOF'
#include "postgres.h"
#include "fmgr.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(fgedu_fibonacci);
Datum
fgedu_fibonacci(PG_FUNCTION_ARGS)
{
int n = PG_GETARG_INT32(0);
int a = 0, b = 1, c, i;
if (n < 0) {
ereport(ERROR, (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Fibonacci number must be non-negative"
)));
}
if (n == 0) {
PG_RETURN_INT32(a);
} else if (n == 1) {
PG_RETURN_INT32(b);
}
for (i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
PG_RETURN_INT32(b);
}
EOF
-- 步骤4:创建SQL文件
cat > fgedu_advanced_ext–1.0.sql << 'EOF'
-- fgedu_advanced_ext--1.0.sql
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_fibonacci(integer)
RETURNS integer
AS '$libdir/fgedu_advanced_ext', 'fgedu_fibonacci'
LANGUAGE C STRICT;
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_fibonacci_sequence(integer)
RETURNS TABLE(n integer, value integer)
AS $$
DECLARE
i integer;
BEGIN
FOR i IN 0..$1 LOOP
n := i;
value := fgedu_fibonacci(i);
RETURN NEXT;
END LOOP;
END;
$$ LANGUAGE plpgsql;
EOF
-- 步骤5:创建Makefile
cat > Makefile << 'EOF'
MODULES = fgedu_advanced_ext
DATA = fgedu_advanced_ext--1.0.sql
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
EOF
-- 步骤6:编译并安装
make
make install
-- 步骤7:安装扩展
psql -U fgedu -d fgedudb -c "CREATE EXTENSION fgedu_advanced_ext;"
-- 输出结果
CREATE EXTENSION
-- 测试函数
SELECT fgedu_fibonacci(10);
-- 输出结果
fgedu_fibonacci
-----------------
55
(1 row)
-- 测试序列函数
SELECT * FROM fgedu_fibonacci_sequence(10);
-- 输出结果
n | value
----+-------
0 | 0
1 | 1
2 | 1
3 | 2
4 | 3
5 | 5
6 | 8
7 | 13
8 | 21
9 | 34
10 | 55
(11 rows)
-- 测试错误处理
SELECT fgedu_fibonacci(-1);
-- 输出结果
ERROR: Fibonacci number must be non-negative
4.3 PostgreSQL数据库扩展复杂场景实战
本案例演示创建一个复杂的扩展,包含多种功能。from PostgreSQL视频:www.itpux.com。
— 步骤1:创建扩展目录
mkdir -p /tmp/fgedu_complex_ext
cd /tmp/fgedu_complex_ext
— 步骤2:创建控制文件
cat > fgedu_complex_ext.control << 'EOF'
# fgedu_complex_ext.control
comment = 'A complex PostgreSQL extension for fgedu'
default_version = '1.0'
module_pathname = '$libdir/fgedu_complex_ext'
relocatable = false
EOF
-- 步骤3:创建SQL文件
cat > fgedu_complex_ext–1.0.sql << 'EOF'
-- fgedu_complex_ext--1.0.sql
-- 创建类型
CREATE TYPE fgedu_user_type AS (
id integer,
name text,
email text
);
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_create_user(integer, text, text)
RETURNS fgedu_user_type
AS $$
DECLARE
result fgedu_user_type;
BEGIN
result.id := $1;
result.name := $2;
result.email := $3;
RETURN result;
END;
$$ LANGUAGE plpgsql;
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_get_user_info(fgedu_user_type)
RETURNS text
AS $$
BEGIN
RETURN 'User: ' || $1.name || ' (ID: ' || $1.id || ', Email: ' || $1.email || ')';
END;
$$ LANGUAGE plpgsql;
-- 创建表
CREATE TABLE IF NOT EXISTS fgedu_user_log (
id SERIAL PRIMARY KEY,
user_info fgedu_user_type,
action TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- 创建函数
CREATE OR REPLACE FUNCTION fgedu_log_user_action(fgedu_user_type, text)
RETURNS void
AS $$
BEGIN
INSERT INTO fgedu_user_log(user_info, action)
VALUES($1, $2);
END;
$$ LANGUAGE plpgsql;
-- 创建视图
CREATE OR REPLACE VIEW fgedu_user_log_view AS
SELECT
id,
(user_info).id AS user_id,
(user_info).name AS user_name,
(user_info).email AS user_email,
action,
created_at
FROM fgedu_user_log;
EOF
-- 步骤4:创建Makefile
cat > Makefile << 'EOF'
MODULES = fgedu_complex_ext
DATA = fgedu_complex_ext--1.0.sql
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
EOF
-- 步骤5:编译并安装
make
make install
-- 步骤6:安装扩展
psql -U fgedu -d fgedudb -c "CREATE EXTENSION fgedu_complex_ext;"
-- 输出结果
CREATE EXTENSION
-- 测试类型和函数
SELECT fgedu_create_user(1, '张三', 'zhangsan@fgedu.net.cn');
-- 输出结果
fgedu_create_user
------------------------------
(1,张三,zhangsan@fgedu.net.cn)
(1 row)
-- 测试获取用户信息
SELECT fgedu_get_user_info(fgedu_create_user(1, '张三', 'zhangsan@fgedu.net.cn'));
-- 输出结果
fgedu_get_user_info
----------------------------------
User: 张三 (ID: 1, Email: zhangsan@fgedu.net.cn)
(1 row)
-- 测试日志函数
SELECT fgedu_log_user_action(fgedu_create_user(1, '张三', 'zhangsan@fgedu.net.cn'), 'login');
-- 输出结果
fgedu_log_user_action
-----------------------
(1 row)
-- 查看日志
SELECT * FROM fgedu_user_log_view;
-- 输出结果
id | user_id | user_name | user_email | action | created_at
----+---------+-----------+------------------------+--------+----------------------------
1 | 1 | 张三 | zhangsan@fgedu.net.cn | login | 2026-04-07 22:30:00
(1 row)
Part05-风哥经验总结与分享
5.1 PostgreSQL数据库扩展最佳实践
最佳实践:
- 模块化设计:每个扩展只负责一个功能领域
- 版本管理:建立完善的版本控制机制
- 性能优化:关键部分使用C语言实现
- 安全性:避免安全漏洞和SQL注入
- 文档:提供详细的使用文档
- 测试:充分测试扩展的功能和性能
- 先使用SQL实现功能原型
- 只在性能关键部分使用C语言
- 建立自动化测试流程
- 使用版本控制管理扩展代码
- 定期更新扩展以适应PostgreSQL新版本
5.2 PostgreSQL数据库扩展常见问题
常见问题:
- 编译错误:缺少依赖或编译环境配置问题
- 版本兼容性:不同PostgreSQL版本的API差异
- 性能问题:扩展代码效率低下
- 安全问题:存在SQL注入或权限漏洞
- 维护问题:扩展代码难以维护
5.3 PostgreSQL数据库扩展故障排查
故障排查:
- 编译问题:检查依赖和编译环境
- 安装问题:检查文件权限和路径
- 运行问题:查看PostgreSQL日志
- 性能问题:使用EXPLAIN分析执行计划
- 兼容性问题:检查PostgreSQL版本
— 查看扩展相关日志
SELECT * FROM pg_log WHERE message LIKE ‘%extension%’ OR message LIKE ‘%fgedu%’
ORDER BY log_time DESC
LIMIT 20;
— 检查扩展文件是否存在
\dx+ fgedu_extension
— 输出结果
Objects in extension “fgedu_extension”
Object description
——————————————
function fgedu_add(integer,integer)
function fgedu_hello()
function fgedu_log_message(text)
table fgedu_extension_log
(4 rows)
— 检查扩展依赖
SELECT e.extname, d.refobjid::regclass
FROM pg_extension e
JOIN pg_depend d ON d.objid = e.oid
WHERE e.extname = ‘fgedu_extension’;
— 输出结果
extname | refobjid
—————–+———-
fgedu_extension | plpgsql
(1 row)
— 检查扩展版本
SELECT extname, extversion FROM pg_extension WHERE extname LIKE ‘fgedu%’;
— 输出结果
extname | extversion
—————–+————
fgedu_extension | 1.1
(1 row)
— 检查扩展函数权限
SELECT proname, proacl FROM pg_proc WHERE proname LIKE ‘fgedu%’;
— 输出结果
proname | proacl
————-+——–
fgedu_add |
fgedu_hello |
fgedu_log_message |
(3 rows)
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
