PostgreSQL 存储过程依赖分析终极指南:plpgsql_check 如何自动发现函数间的调用关系 [特殊字符]
PostgreSQL 存储过程依赖分析终极指南plpgsql_check 如何自动发现函数间的调用关系 【免费下载链接】plpgsql_checkplpgsql_check is a linter tool (does source code static analyze) for the PostgreSQL language plpgsql (the native language for PostgreSQL store procedures).项目地址: https://gitcode.com/gh_mirrors/pl/plpgsql_checkPostgreSQL 存储过程是现代数据库应用开发中不可或缺的部分但随着业务逻辑的复杂化函数间的调用关系也变得错综复杂。你是否曾遇到过这样的困扰修改一个函数后不知道影响了哪些其他函数或者想要重构代码却无法理清函数间的依赖关系 今天我将为你介绍一个强大的工具——plpgsql_check它不仅能进行静态代码检查还能自动分析 PostgreSQL 存储过程的依赖关系什么是 plpgsql_checkplpgsql_check是 PostgreSQL 的一个扩展工具专门用于对 PL/pgSQL 存储过程进行静态代码分析。它不仅能在编译时发现潜在的错误还能分析函数间的调用关系帮助开发者更好地理解和管理数据库中的存储过程逻辑。这个工具的核心功能包括静态代码检查在函数创建时发现语法和语义错误依赖关系分析自动发现函数间的调用关系性能警告识别可能导致性能问题的代码模式安全检测发现潜在的 SQL 注入漏洞为什么需要存储过程依赖分析在复杂的数据库应用中存储过程之间往往会形成复杂的调用链。一个函数可能调用多个其他函数而这些被调用的函数又可能调用更多的函数。这种依赖关系如果不加管理会导致维护困难修改一个函数可能意外破坏其他依赖它的函数重构风险不知道哪些函数会受到影响不敢轻易重构调试复杂错误传播路径不清晰难以定位问题根源文档缺失缺乏自动化的依赖关系文档plpgsql_check 的依赖分析功能正是为了解决这些问题而生plpgsql_check 依赖分析实战 安装与启用首先你需要安装 plpgsql_check 扩展。如果你使用的是 PostgreSQL 14 或更高版本安装非常简单-- 创建扩展 CREATE EXTENSION IF NOT EXISTS plpgsql_check;基本依赖分析让我们从一个简单的例子开始。假设我们有以下三个函数-- 创建基础函数 CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, discount_rate NUMERIC) RETURNS NUMERIC AS $$ BEGIN RETURN price * (1 - discount_rate); END; $$ LANGUAGE plpgsql; -- 创建调用函数 CREATE OR REPLACE FUNCTION process_order(order_id INT) RETURNS NUMERIC AS $$ DECLARE total_price NUMERIC; final_price NUMERIC; BEGIN -- 获取订单总价假设有相关表 SELECT amount INTO total_price FROM orders WHERE id order_id; -- 调用折扣计算函数 final_price : calculate_discount(total_price, 0.1); RETURN final_price; END; $$ LANGUAGE plpgsql; -- 创建顶层业务函数 CREATE OR REPLACE FUNCTION complete_order(order_id INT) RETURNS VOID AS $$ DECLARE price NUMERIC; BEGIN price : process_order(order_id); -- 执行其他业务逻辑 RAISE NOTICE 订单 % 处理完成最终价格%, order_id, price; END; $$ LANGUAGE plpgsql;现在让我们使用 plpgsql_check 来分析这些函数的依赖关系-- 分析 complete_order 函数的依赖 SELECT * FROM plpgsql_show_dependency_tb(complete_order(int));执行结果会显示类似这样的输出┌──────────┬───────┬────────┬─────────────────┬────────────────────────────┐ │ type │ oid │ schema │ name │ params │ ╞══════════╪═══════╪════════╪═════════════════╪════════════════════════════╡ │ FUNCTION │ 16401 │ public │ process_order │ (integer) │ │ RELATION │ 16399 │ public │ orders │ │ └──────────┴───────┴────────┴─────────────────┴────────────────────────────┘深入分析依赖链plpgsql_check 不仅能显示直接依赖还能通过递归分析展示完整的依赖链。让我们分析process_order函数-- 分析 process_order 函数的完整依赖链 SELECT * FROM plpgsql_show_dependency_tb(process_order(int));结果会显示┌──────────┬───────┬────────┬─────────────────────┬────────────────────────────┐ │ type │ oid │ schema │ name │ params │ ╞══════════╪═══════╪════════╪═════════════════════╪════════════════════════════╡ │ FUNCTION │ 16400 │ public │ calculate_discount │ (numeric,numeric) │ │ RELATION │ 16399 │ public │ orders │ │ └──────────┴───────┴────────┴─────────────────────┴────────────────────────────┘高级依赖分析技巧 ️1. 批量分析所有函数如果你想一次性分析数据库中所有 PL/pgSQL 函数的依赖关系可以使用以下查询-- 分析所有非触发器 PL/pgSQL 函数的依赖关系 SELECT p.proname AS function_name, d.type AS dependency_type, d.schema AS dependency_schema, d.name AS dependency_name, d.params AS dependency_params FROM pg_catalog.pg_proc p CROSS JOIN LATERAL plpgsql_show_dependency_tb(p.oid) d WHERE p.prolang (SELECT oid FROM pg_language WHERE lanname plpgsql) ORDER BY p.proname;2. 触发器函数依赖分析对于触发器函数需要指定关联的表-- 创建示例表和触发器 CREATE TABLE audit_log ( id SERIAL PRIMARY KEY, table_name TEXT, operation TEXT, changed_at TIMESTAMP DEFAULT NOW() ); CREATE OR REPLACE FUNCTION audit_trigger_function() RETURNS TRIGGER AS $$ BEGIN INSERT INTO audit_log (table_name, operation) VALUES (TG_TABLE_NAME, TG_OP); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER users_audit_trigger AFTER INSERT OR UPDATE OR DELETE ON users FOR EACH ROW EXECUTE FUNCTION audit_trigger_function(); -- 分析触发器函数的依赖需要指定关联的表 SELECT * FROM plpgsql_show_dependency_tb(audit_trigger_function(), users);3. 可视化依赖关系虽然 plpgsql_check 本身不提供图形化界面但你可以将结果导出并使用其他工具进行可视化-- 导出依赖关系为 JSON 格式 SELECT jsonb_build_object( function, p.proname, dependencies, ( SELECT jsonb_agg( jsonb_build_object( type, d.type, schema, d.schema, name, d.name, params, d.params ) ) FROM plpgsql_show_dependency_tb(p.oid) d ) ) AS dependency_graph FROM pg_catalog.pg_proc p WHERE p.prolang (SELECT oid FROM pg_language WHERE lanname plpgsql) LIMIT 10;实际应用场景 场景一安全审计在进行安全审计时了解函数间的依赖关系至关重要。假设你需要审计一个涉及敏感数据处理的函数-- 审计敏感数据处理函数的依赖链 WITH RECURSIVE dependency_tree AS ( -- 起始函数 SELECT process_payment::text AS function_name, d.type, d.schema, d.name, d.params, 1 AS depth FROM plpgsql_show_dependency_tb(process_payment(bigint,numeric)) d UNION ALL -- 递归查找依赖 SELECT dt.name AS function_name, d.type, d.schema, d.name, d.params, dt.depth 1 FROM dependency_tree dt JOIN pg_proc p ON p.proname dt.name CROSS JOIN LATERAL plpgsql_show_dependency_tb(p.oid) d WHERE dt.type FUNCTION AND dt.depth 5 -- 限制递归深度 ) SELECT * FROM dependency_tree ORDER BY depth, function_name;场景二影响分析在修改函数前分析可能受影响的函数-- 查找所有依赖特定函数的存储过程 SELECT p.proname AS dependent_function, pg_get_function_identity_arguments(p.oid) AS function_signature FROM pg_catalog.pg_proc p WHERE p.prolang (SELECT oid FROM pg_language WHERE lanname plpgsql) AND EXISTS ( SELECT 1 FROM plpgsql_show_dependency_tb(p.oid) d WHERE d.type FUNCTION AND d.name calculate_discount -- 要修改的函数名 ) ORDER BY p.proname;场景三代码重构在进行大规模代码重构时识别可以独立修改的函数模块-- 识别低耦合的函数模块 SELECT p.proname AS function_name, COUNT(DISTINCT d.name) AS dependency_count, ARRAY_AGG(DISTINCT d.type || : || d.schema || . || d.name) AS dependencies FROM pg_catalog.pg_proc p CROSS JOIN LATERAL plpgsql_show_dependency_tb(p.oid) d WHERE p.prolang (SELECT oid FROM pg_language WHERE lanname plpgsql) GROUP BY p.proname, p.oid HAVING COUNT(DISTINCT d.name) 3 -- 依赖较少的函数 ORDER BY dependency_count ASC;最佳实践与技巧 1. 定期进行依赖分析建议将依赖分析纳入你的 CI/CD 流程中-- 创建依赖分析报告 CREATE OR REPLACE FUNCTION generate_dependency_report() RETURNS TABLE( function_name TEXT, dependency_type TEXT, dependency_name TEXT, dependency_details TEXT ) AS $$ BEGIN RETURN QUERY SELECT p.proname::TEXT, d.type::TEXT, d.name::TEXT, COALESCE(d.params, )::TEXT FROM pg_catalog.pg_proc p CROSS JOIN LATERAL plpgsql_show_dependency_tb(p.oid) d WHERE p.prolang (SELECT oid FROM pg_language WHERE lanname plpgsql) AND p.pronamespace::regnamespace::text NOT IN (pg_catalog, information_schema) ORDER BY p.proname, d.type, d.name; END; $$ LANGUAGE plpgsql;2. 结合代码审查在代码审查过程中使用依赖分析来评估变更的影响范围-- 在代码审查中使用的依赖检查函数 CREATE OR REPLACE FUNCTION check_dependency_impact( target_function REGPROCEDURE ) RETURNS TABLE( impact_level TEXT, dependent_function TEXT, dependency_path TEXT[] ) AS $$ DECLARE func_oid OID; BEGIN func_oid : target_function::OID; RETURN QUERY WITH RECURSIVE impact_path AS ( SELECT p.proname AS current_function, ARRAY[p.proname] AS path, 1 AS depth FROM pg_proc p WHERE p.oid func_oid UNION ALL SELECT p2.proname, ip.path || p2.proname, ip.depth 1 FROM impact_path ip JOIN pg_proc p1 ON p1.proname ip.current_function CROSS JOIN LATERAL plpgsql_show_dependency_tb(p1.oid) d JOIN pg_proc p2 ON p2.proname d.name WHERE d.type FUNCTION AND ip.depth 10 ) SELECT CASE WHEN depth 1 THEN DIRECT ELSE INDIRECT END AS impact_level, current_function AS dependent_function, path AS dependency_path FROM impact_path ORDER BY depth, current_function; END; $$ LANGUAGE plpgsql;3. 监控依赖变化创建监控机制来跟踪依赖关系的变化-- 创建依赖关系历史表 CREATE TABLE IF NOT EXISTS function_dependency_history ( id SERIAL PRIMARY KEY, check_time TIMESTAMP DEFAULT NOW(), function_name TEXT NOT NULL, dependency_count INTEGER NOT NULL, dependencies JSONB NOT NULL ); -- 定期记录依赖关系快照 CREATE OR REPLACE FUNCTION snapshot_dependencies() RETURNS VOID AS $$ BEGIN INSERT INTO function_dependency_history (function_name, dependency_count, dependencies) SELECT p.proname, COUNT(DISTINCT d.name), jsonb_agg( jsonb_build_object( type, d.type, schema, d.schema, name, d.name, params, d.params ) ) FROM pg_catalog.pg_proc p CROSS JOIN LATERAL plpgsql_show_dependency_tb(p.oid) d WHERE p.prolang (SELECT oid FROM pg_language WHERE lanname plpgsql) GROUP BY p.proname, p.oid; END; $$ LANGUAGE plpgsql; -- 设置定时任务使用 pg_cron 或其他调度工具 -- SELECT cron.schedule(0 2 * * *, SELECT snapshot_dependencies());常见问题与解决方案 ❓Q1: plpgsql_check 能分析动态 SQL 的依赖吗A:有限支持。plpgsql_check 主要分析静态 SQL 语句中的依赖关系。对于动态 SQL使用 EXECUTE 语句由于 SQL 语句在运行时才确定静态分析无法完全识别其依赖关系。Q2: 如何处理递归函数调用A:plpgsql_check 能够检测到递归调用但需要小心处理以避免无限递归。建议在分析递归函数时设置合理的递归深度限制。Q3: 依赖分析会影响性能吗A:plpgsql_check 的依赖分析是在静态检查阶段进行的不会影响运行时性能。分析过程本身很快但对于大型数据库建议在非高峰时段进行批量分析。Q4: 如何分析跨 schema 的函数依赖A:plpgsql_check 会自动处理跨 schema 的依赖关系。结果中的schema字段会显示函数或表所属的模式。总结 plpgsql_check 的依赖分析功能为 PostgreSQL 存储过程管理提供了强大的工具支持。通过自动发现函数间的调用关系它帮助开发者提高代码可维护性清晰了解函数间的依赖关系降低重构风险在修改前评估影响范围加速问题排查快速定位错误传播路径优化架构设计识别高耦合模块进行优化无论你是数据库管理员、后端开发人员还是系统架构师掌握 plpgsql_check 的依赖分析功能都将显著提升你的工作效率和代码质量。现在就开始使用这个强大的工具让你的 PostgreSQL 存储过程管理变得更加轻松和高效提示plpgsql_check 还提供了许多其他有用的功能如性能分析、安全检查和代码覆盖率统计。建议探索完整的 官方文档 来发现更多可能性【免费下载链接】plpgsql_checkplpgsql_check is a linter tool (does source code static analyze) for the PostgreSQL language plpgsql (the native language for PostgreSQL store procedures).项目地址: https://gitcode.com/gh_mirrors/pl/plpgsql_check创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

周一上线|OpenAI 开卖 Agent 指挥台,DeepSeek 被曝筹备 IPO,开放模型迈入 3T 时代

周一上线|OpenAI 开卖 Agent 指挥台,DeepSeek 被曝筹备 IPO,开放模型迈入 3T 时代

这期的「周一上线」,一边是开发者继续整活,一边是模型、工具和开源项目密集上新。有人把 Codex 做成了实体「Agent 指挥台」,有人用世界杯四强球员的名字织出四面国旗,还有人只用 5 个 prompt 搭出了一个 3D 球场选座原型&#xf…

2026/10/12 14:10:11 阅读更多 →
fine-tune-mistral性能对比:3090s vs A100s vs H100s训练效率实测

fine-tune-mistral性能对比:3090s vs A100s vs H100s训练效率实测

fine-tune-mistral性能对比:3090s vs A100s vs H100s训练效率实测 【免费下载链接】fine-tune-mistral Fine-tune mistral-7B on 3090s, a100s, h100s 项目地址: https://gitcode.com/gh_mirrors/fi/fine-tune-mistral fine-tune-mistral是一个专为在不同GPU…

2026/10/9 8:10:46 阅读更多 →
如何用OpenCore Legacy Patcher让旧Mac焕发新生:完整升级指南

如何用OpenCore Legacy Patcher让旧Mac焕发新生:完整升级指南

如何用OpenCore Legacy Patcher让旧Mac焕发新生:完整升级指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为苹果官方停止支持的旧款Mac电…

2026/10/11 20:45:21 阅读更多 →

最新新闻

幼儿园国际象棋比赛全攻略:从赛事设计到教学实操的完整指南

幼儿园国际象棋比赛全攻略:从赛事设计到教学实操的完整指南

1. 一场幼儿园棋赛背后,藏着多少被低估的教育设计第一次看到“幼儿园办国际象棋比赛”这个事,我脑子里冒出来的第一个念头是:三四岁的孩子坐得住吗?棋子会不会被当成积木搭着玩?但仔细看完整个活动的组织逻辑之后&…

2026/10/15 8:22:31 阅读更多 →
OpenLayers地图开发避坑指南:坐标系、图层栈与离线部署

OpenLayers地图开发避坑指南:坐标系、图层栈与离线部署

简介:本资源为 OpenLayers 地图开发必备的前端基础文件包,面向 WebGIS 初学者、前端开发者及地理信息相关课程学习者,解决快速集成开源地图能力时缺少核心依赖的问题。压缩包共 3 个文件(152KB),含核心 Jav…

2026/10/15 8:22:31 阅读更多 →
幼儿园国际象棋比赛怎么搞?从赛制设计到现场实操的完整复盘

幼儿园国际象棋比赛怎么搞?从赛制设计到现场实操的完整复盘

1. 一场幼儿园棋赛背后的教育设计逻辑1.1 为什么选国际象棋而不是其他棋类接到这个项目标题的时候,我第一反应是:幼儿园搞国际象棋比赛,这个选型挺有意思。干了这么多年一线教育项目,我见过太多幼儿园做活动是"什么热闹做什么…

2026/10/15 8:22:31 阅读更多 →
可靠评估对抗鲁棒性:免调参多样性攻击集成方法

可靠评估对抗鲁棒性:免调参多样性攻击集成方法

1. 项目概述:为什么“可靠评估对抗鲁棒性”这件事比想象中更难你有没有遇到过这种情况:模型在标准测试集上准确率98%,可只要加一丁点人眼根本看不出的扰动——比如把某张猫图的像素值整体调高0.002,它就坚定地把猫判成烤面包机&am…

2026/10/15 8:22:31 阅读更多 →
前端导出Excel/CSV实战:方案选型、编码陷阱与性能优化

前端导出Excel/CSV实战:方案选型、编码陷阱与性能优化

1. 为什么前端导出这件事值得认真对待但凡做过管理后台、数据看板或者报表类项目的同行,大概率都碰到过同一个需求:页面上辛辛苦苦渲染出来的表格,业务方一句话——“能不能加个导出按钮,我要Excel”。听起来简单,真动…

2026/10/15 8:22:31 阅读更多 →
七层封装引发的支付回调事故:过度设计如何安全拆解?

七层封装引发的支付回调事故:过度设计如何安全拆解?

1. 凌晨两点的报警:一次由"优雅设计"引发的线上事故先交代一下背景,免得大家以为我要讲什么架子上的空道理。前阵子公司某个核心支付项目出了一个线上事故,直接触发告警群炸锅的那种。当时我人在家里,正准备关灯睡觉&am…

2026/10/15 8:21:31 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →