在AWS RDS PostgreSQL 16.3中创建函数失败,美元符号引发语法错误
问题
在运行PostgreSQL 16.3的AWS RDS实例及本地PostgreSQL实例中,创建函数时持续触发由$$符号引发的语法错误,即使使用PostgreSQL官网标注的规范语法也无法解决。相关代码及错误信息如下:
代码:
CREATE OR REPLACE FUNCTION public.get_current_user_id() RETURNS uuid LANGUAGE plpgsql AS $$ SELECT current_setting('app.current_user_id', true)::uuid; $$; CREATE OR REPLACE FUNCTION public.user_has_role(p_role_names text[]) RETURNS boolean LANGUAGE plpgsql AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM public.um_user_roles ur JOIN public.um_roles r ON ur.role_id = r.id WHERE ur.user_id = public.get_current_user_id() AND r.role_name = ANY(p_role_names) AND ur.status = 'active' AND (ur.valid_until IS NULL OR ur.valid_until > CURRENT_TIMESTAMP) ); END; $$ LANGUAGE plpgsql SECURITY DEFINER;
错误信息:
Error at line 37: Statement: CREATE OR REPLACE FUNCTION public.get_current_user_id() RETURNS uuid LANGUAGE plpgsql AS $$ DECLARE BEGIN RETURN current_setting('app.current_user_id', true)::uuid; Error message: unterminated dollar-quoted string at or near "$$ DECLARE BEGIN RETURN current_setting('app.current_user_id', true)::uuid;" LINE 1: ...urrent_user_id() RETURNS uuid LANGUAGE plpgsql AS $$ DECLARE... ^
解决方案
1. 修复第一个函数的PL/pgSQL语法
get_current_user_id指定了LANGUAGE plpgsql,但函数体直接写了SELECT语句,未遵循PL/pgSQL必须用BEGIN...END包裹逻辑的规范。有两种修复方式:
方式一:保留PL/pgSQL语言,补充BEGIN...END块
CREATE OR REPLACE FUNCTION public.get_current_user_id() RETURNS uuid LANGUAGE plpgsql AS $$ BEGIN RETURN current_setting('app.current_user_id', true)::uuid; END; $$;
方式二:改用SQL语言(无需BEGIN...END)
如果不需要PL/pgSQL的流程控制等特性,直接用SQL语言更简洁:
CREATE OR REPLACE FUNCTION public.get_current_user_id() RETURNS uuid LANGUAGE sql AS $$ SELECT current_setting('app.current_user_id', true)::uuid; $$;
2. 删除第二个函数的冗余语言声明
user_has_role函数末尾重复写了LANGUAGE plpgsql,函数开头已指定语言,需删除该冗余内容:
CREATE OR REPLACE FUNCTION public.user_has_role(p_role_names text[]) RETURNS boolean LANGUAGE plpgsql AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM public.um_user_roles ur JOIN public.um_roles r ON ur.role_id = r.id WHERE ur.user_id = public.get_current_user_id() AND r.role_name = ANY(p_role_names) AND ur.status = 'active' AND (ur.valid_until IS NULL OR ur.valid_until > CURRENT_TIMESTAMP) ); END; $$ SECURITY DEFINER;
3. 关于$$错误的说明
错误提示中的unterminated dollar-quoted string并非$$本身的问题,而是语法错误导致解析器无法正确识别结束标记。修复上述语法问题后,$$的使用会恢复正常。
内容的提问来源于stack exchange,提问作者Raphael Heard
相关产品推荐
相关产品推荐

