伪类型
伪类型(pseudo-type)不是可以直接用于表列的数据类型,而是 PostgreSQL 用来描述函数参数、返回值、过程或内部对象的特殊类型。它们让函数能够表达“任意类型”“一行记录”或“无返回值”等接口语义。
常见伪类型
| 伪类型 | 含义或用途 |
|---|---|
anyelement、anyarray | 与调用时具体类型关联的多态接口(旧式多态类型) |
anycompatible、anycompatiblearray | 允许多个参数按兼容类型统一(较新的多态接口) |
record | 任意复合记录,返回结构通常需由调用者提供 |
void | 函数不返回有意义的值 |
trigger | 触发器函数的返回类型 |
event_trigger | 事件触发器函数的返回类型 |
internal | PostgreSQL 内部调用约定,不能作为普通 SQL 数据传入 |
cstring | 内部 C 字符串表示,不是表列文本 |
完整清单和可用位置随 PostgreSQL 版本变化,应以目标版本的 CREATE FUNCTION 文档为准。
多态函数
多态伪类型让一个函数适配多种具体数据类型。例如数组相关函数可以对不同元素类型工作。函数声明中的类型约束会在调用时统一解析:
CREATE FUNCTION first_item(anyarray)
RETURNS anyelement
LANGUAGE sql
AS $$ SELECT $1[1] $$;
SELECT first_item(ARRAY[10, 20, 30]);
SELECT first_item(ARRAY['a', 'b']);
旧式 anyelement 家族要求相关参数推导出同一具体类型;anycompatible 家族允许 PostgreSQL 找到共同兼容类型。设计多态函数时要测试空数组、未知字面量和隐式转换。
record 返回值
返回 record 的函数没有固定的列定义,调用者通常需要提供列清单:
CREATE FUNCTION pair_values()
RETURNS record
LANGUAGE sql
AS $$ SELECT 1, 'ok' $$;
SELECT * FROM pair_values() AS p(number integer, status text);
如果返回结构稳定,优先定义命名组合类型或 RETURNS TABLE,让依赖方获得更好的类型检查和文档。record 适合动态查询结果,但会增加调用复杂度。
trigger、event_trigger 和 void
触发器函数必须声明 RETURNS trigger,返回 NEW、OLD 或 NULL 的规则由触发器类型决定:
CREATE FUNCTION set_updated_at()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at := clock_timestamp();
RETURN NEW;
END;
$$;
void 函数可以执行副作用但不返回值。调用方仍需考虑事务边界、异常和幂等性;void 不意味着操作一定异步或不可失败。
为什么不能建表列
伪类型缺少稳定的存储布局或需要调用上下文才能确定具体类型,因此不能直接用于普通列:
-- 不可行:record 不是可直接存储的列类型
-- CREATE TABLE t (value record);
需要保存任意结构时,根据目标选择 jsonb、bytea、组合类型、数组或专门的表结构,而不是把伪类型当成“万能列类型”。
权限和安全
声明为 internal 的函数通常只供数据库内部或扩展使用,普通用户不应直接调用。多态函数和动态 record 查询也不能绕过权限检查;安全定义、search_path 和动态 SQL 仍需显式设计。
常见误区
- 试图把
record、trigger或anyelement用作表列。 - 返回
record却不提供稳定的列定义,让客户端无法可靠映射。 - 把
anyelement当成运行时反射系统,忽略类型推导和隐式转换规则。 - 直接暴露
internal函数或依赖未公开的内部接口。 - 用伪类型逃避真正的数据建模,而不是选择
jsonb、组合类型或关联表。