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

PostgreSQL DO块中如何转义$$符号?pg_cron调度pgpartman报错

PostgreSQL中DO块内调用cron.schedule的语法冲突解决

问题场景

尝试通过PostgreSQL的cron扩展调度pgpartman的维护任务,编写了一段可重复执行的DO块代码,但执行时触发语法错误。

原DO块代码:

do $$
declare
   schemaname text := 'mytest';
begin
    execute 'set search_path to ' || schemaname||', public';
    if not exists (select * from cron.job where command like '%call run_maintenance_proc%') then 
        select cron.schedule('@daily',$$call run_maintenance_proc()$$);
        raise notice 'sqltext - %', sqltext;
        execute sqltext;
    end if;
end;
$$;

执行时的报错信息:

postgres=> do $$
postgres$> declare
postgres$>    schemaname text := 'nmtest';
postgres$>    sqltext text;
postgres$> begin
postgres$>     execute 'set search_path to ' || schemaname||', public';
postgres$>     if not exists (select * from cron.job where command like '%call run_maintenance_proc%') then
postgres$> select cron.schedule('@daily',$$call run_maintenance_proc()$$);
postgres$>     raise notice 'sqltext - %', sqltext;
postgres$>     execute sqltext;
postgres$>     end if;
postgres$> end;
postgres$> $$;
ERROR:  syntax error at or near "call"
LINE 8: select cron.schedule('@daily',$$call run_maintenance_proc()$...
                                        ^

单独执行调度语句是正常的:

-- works fine as regular call
postgres=> select cron.schedule('@daily', $$call partman.run_maintenance_proc()$$);
 schedule
----------
        4
(1 row)

错误核心原因:DO块使用$$作为代码块分隔符,内部调用cron.schedule时的$$被PostgreSQL误判为DO块的结束标记,导致语法解析失败。

解决方法

方法1:使用自定义美元引号分隔符

PostgreSQL允许为美元引号添加自定义标签,彻底避免内部分隔符和外部DO块的分隔符冲突。比如将内部的$$替换为$cron_cmd$这类带标签的分隔符:

修正后的完整DO块代码:

do $$
declare
   schemaname text := 'mytest';
   job_id integer;
begin
    execute 'set search_path to ' || schemaname || ', public';
    if not exists (select * from cron.job where command like '%call run_maintenance_proc%') then 
        -- 使用带标签的美元引号分隔符$cron_cmd$
        select cron.schedule('@daily', $cron_cmd$call run_maintenance_proc()$cron_cmd$) into job_id;
        raise notice 'Scheduled maintenance job with ID: %', job_id;
    end if;
end;
$$;

方法2:使用单引号转义

将cron.schedule的第二个参数改用单引号包裹,若参数内部存在单引号,只需用两个单引号转义即可(此场景无内部单引号,直接使用):

do $$
declare
   schemaname text := 'mytest';
   job_id integer;
begin
    execute 'set search_path to ' || schemaname || ', public';
    if not exists (select * from cron.job where command like '%call run_maintenance_proc%') then 
        select cron.schedule('@daily', 'call run_maintenance_proc()') into job_id;
        raise notice 'Scheduled maintenance job with ID: %', job_id;
    end if;
end;
$$;

额外逻辑修正

原代码中sqltext变量未赋值就执行execute sqltext属于逻辑错误,上述修正代码已移除无效的sqltext相关代码,直接将调度任务ID存入变量用于日志输出。

内容的提问来源于stack exchange,提问作者nmakb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:28:20