postgresql中call仅能调用create procedure定义的存储过程,不能调用create function定义的函数;若误用call调用函数,会报“procedure does not exist”错误,因系统表pg_proc中函数prokind为'f'、过程为'p'。

PostgreSQL 中 CALL 只能用于调用存储过程,不能调用函数
这是最容易混淆的点:如果你写 CALL my_func() 却报错 ERROR: procedure "my_func" does not exist,大概率是因为 my_func 是用 CREATE FUNCTION 定义的函数,不是 CREATE PROCEDURE 定义的存储过程。PostgreSQL 严格区分二者——CALL 语句只认 PROCEDURE。
验证方式很简单:
- 查系统表:
SELECT proname, prokind FROM pg_proc WHERE proname = 'my_func';—— 若prokind = 'f'表示是函数,'p'才是存储过程 - 建过程时必须显式用
CREATE PROCEDURE,且不能有RETURNS子句(函数才有) - 过程体中可以写
COMMIT或ROLLBACK;函数里写会直接报错
CALL 在存储过程内部调用其他存储过程的写法
在 PL/pgSQL 过程体内,CALL 和在外部 SQL 中一样使用,但要注意事务上下文和错误传播。
- 必须确保被调用的过程已存在,且当前用户有
EXECUTE权限 - 不支持用
PERFORM替代CALL——PERFORM只对函数有效,对过程无效 - 若被调用过程抛出异常(如
RAISE EXCEPTION),默认会向上冒泡,除非你用BEGIN ... EXCEPTION捕获 - 参数传递方式一致:位置传参或命名传参都支持,例如:
CALL log_event('user_login', user_id => 101);
命名参数传参时,参数名必须与 CREATE PROCEDURE 声明完全一致
PostgreSQL 对参数名大小写敏感,且不自动补全或模糊匹配。写错一个字母就会报 Unknown argument name。
- 声明过程时用了
IN p_user_id INTEGER,调用就必须写p_user_id => 123,不能写user_id => 123或P_USER_ID => 123 - 参数名含下划线、大小写混合时尤其容易手误,建议统一用小写下划线风格并保持全程一致
- 可选参数(带默认值)可以省略,但一旦指定某个可选参数,其后所有参数都必须显式写出(不能跳过中间参数)
从外部 SQL 调用过程时,事务行为要特别注意
存储过程本身可含 COMMIT/ROLLBACK,但外部调用者可能没意识到自己已不在单个事务中。
- 如果在显式事务块里执行
CALL,而过程内又执行了COMMIT,会导致ERROR: COMMIT cannot be used when there is no transaction或更隐蔽的“事务已结束”错误 - 推荐做法:让存储过程自己管理事务边界(即它内部以
BEGIN开头、以COMMIT结尾),外部调用时不包额外事务 - 调试时可用
SHOW transaction_isolation;和SELECT txid_current();辅助判断当前是否在活跃事务中











