DO 脚本中的 PSQL 命令行参数

GT.*_*GT. 2 postgresql command-line plpgsql parameter-passing psql

我有一个NewSchemaSafe.sql基于项目目录创建新模式的脚本;它是从 Windows 命令行调用的,如下所示:

for %%a in (.) do set this=%%~na
-- other stuff here
psql -U postgres -d SLSM -e -v v1=%this% -f "NewSchemaSafe.sql"
Run Code Online (Sandbox Code Playgroud)

NewSchemaSafe.sql 如下:

-- NewSchemaSafe.sql
-- NEW SCHEMA SETUP 
--    - checks if schema exists
--    - if yes, renames existing with current monthyear as suffix
-- NOTE: will always delete any schema with the 'rename' name (save_schema)
--       since any schema thus named must have resulted from this script 
--       on this date - so, y'know, no loss.
SET search_path TO :v1, public; -- kludge coz can't pass :v1 to DO
DO
$$
DECLARE
       this_schema TEXT:= current_schema()::TEXT;
       this_date TEXT:= replace(current_date::TEXT,'-','');
       save_schema TEXT:= this_schema||this_date;
BEGIN
    IF this_schema <> 'public'
    THEN
        RAISE NOTICE 'Working in schema %', this_schema;
        IF EXISTS(
            SELECT schema_name
              FROM information_schema.schemata
              WHERE schema_name = save_schema)
        THEN
           EXECUTE 'DROP SCHEMA '||save_schema||' CASCADE;';
        END IF;
        IF NOT EXISTS(
            SELECT schema_name
              FROM information_schema.schemata
              WHERE schema_name = this_schema
          )
        THEN
          EXECUTE 'CREATE SCHEMA '||this_schema||';';
        ELSE
          EXECUTE 'ALTER SCHEMA '||this_schema|| ' RENAME TO '|| save_schema ||';';
          EXECUTE 'COMMENT ON SCHEMA '|| save_schema ||' IS ''schema renamed by SLSM creation on '|| this_date ||'''';
          EXECUTE 'CREATE SCHEMA '||this_schema||';';
        END IF;
    ELSE
        RAISE NOTICE 'SCHEMA IS % SO PARAMETER WAS NOT PASSED OR DID NOT STICK', this_schema;
    END IF;
END
$$;
Run Code Online (Sandbox Code Playgroud)

现在我知道SET会发生这种情况,因为我可以在命令行输出中看到它。然而脚本的其余部分(优雅地,如预期的那样)因为它似乎认为current_schemapublic:脚本产生

psql: NewSchemaSafe.sql:39: NOTICE:  SCHEMA IS public SO PARAMETER WAS NOT PASSED OR DID NOT STICK
Run Code Online (Sandbox Code Playgroud)

我最初尝试按如下方式传递:v1到循环DECLAREDO

 DECLARE
       this_schema text := :v1 ;
       this_date text := replace(current_date::text,'-','');
       save_schema text := this_schema||this_date;
  [snip]
Run Code Online (Sandbox Code Playgroud)

但这只是死在藤蔓上:它会引发语法错误-

psql:NewSchemaSafe.sql:40: ERROR:  syntax error at or near ":"
LINE 4:        this_schema text := :v1 ;
Run Code Online (Sandbox Code Playgroud)

%this%用引号括起来与不在批处理文件中没有区别。

所以像往常一样,两个问题:

  1. set search path当我看到它正在执行时,该语句怎么不“粘住” ?更新:不相关,请忽略。
  2. 如何将:v1参数传递给DO脚本本身?

环境:PostgreSQL 9.3.5 64位(Win);

奇怪之处:我确定这个脚本在两天前起作用了,唯一的变化是删除了 geany 插入的字节顺序标记(UTF BOM 使psql堵嘴)。

更新:前几天它工作的原因是它正在考虑的模式确实存在的情况下运行。如果传递的模式名称不存在,更改search_path(尝试从 中找到所需的模式current_schema)将无济于事- 这使得传递给更重要,因此可以更直接地使用它。:v1 :v1DO

Abe*_*sto 5

因为 PL 块实际上是代码中的文本常量,所以内部变量不会以通常的方式在它们内部进行替换。幸运的是,可以使用会话变量在不同的 SQL/PL 块之间共享数据:

set foo.bar to :v1; -- Name should contains the dot, don't ask me why 
show foo.bar; -- Check that the value was assigned 
do $$
declare
  myvar text := current_setting('foo.bar');
begin
  raise info '%', myvar; -- Output variable value
end $$;
Run Code Online (Sandbox Code Playgroud)