You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL函数中设会话变量为参数值后RLS无法识别的问题

问题分析与解决办法

你遇到的核心问题是:在PL/pgSQL函数里把会话变量"my.user_id"设为固定值时RLS正常工作,但设为函数参数v_user_id就失效。这是因为PostgreSQL在解析RETURN QUERY对应的查询时,会提前绑定会话变量的值,普通SET命令的会话级变量更新不会立即作用于紧接着的查询。

下面给你两个可行的解决方案:

方案1:用SET LOCAL替代SET

SET LOCAL会把变量的作用域限制在当前事务内,而PL/pgSQL函数默认在事务中执行,这样后续的RETURN QUERY查询能获取到刚设置的参数值:

CREATE OR REPLACE FUNCTION sbx.get_expenses_by_ppp_table_2(v_user_id character varying, day character varying)
 RETURNS TABLE(report_id integer, report_row_id character varying, report_row_name character varying, row_level_num integer, fact_amount numeric, plan_amount numeric, execution_percentage numeric, daily_fact_amount numeric)
 LANGUAGE plpgsql
AS $function$
#variable_conflict use_column
declare 
     report_day date;
     report_year int4;
begin
    report_day := day::date;
    report_year := date_part('year', report_day);
   
    SET LOCAL "my.user_id" = v_user_id; -- 替换为SET LOCAL

    return query select 1 as report_id,
                        ex.ppp_code as report_row_id,
                        -- 补充你的剩余查询逻辑
                        ...;
end;
$function$;

方案2:确认RLS策略的变量引用正确

确保你的RLS策略里是用current_setting('my.user_id')来读取变量的,比如:

CREATE POLICY expenses_user_policy ON sbx.expenses
FOR SELECT TO public
USING (user_id = current_setting('my.user_id')::character varying);

如果之前的策略写法有问题,哪怕变量设置对了也不会生效。

补充说明

固定值能生效是因为SET "my.user_id" = '1'是会话级生效,测试时变量值会保留到查询执行阶段。但用参数设置时,普通SET的更新在查询解析后才生效,导致查询用的是旧值。SET LOCAL强制在当前事务内生效,能让后续查询读到最新的参数值。

内容的提问来源于stack exchange,提问作者Иван Размахнин

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 19:49:54