【发布时间】:2016-11-05 13:59:48
【问题描述】:
我有一个脚本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"
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
$$;
现在我知道SET 发生了,因为我可以在命令行输出中看到它。然而脚本的其余部分死掉了(优雅地,如预期的那样),因为它似乎认为current_schema 是public:脚本产生
psql: NewSchemaSafe.sql:39: NOTICE: SCHEMA IS public SO PARAMETER WAS NOT PASSED OR DID NOT STICK
我最初尝试将:v1 传递给DO 循环的DECLARE 块,如下所示:
DECLARE
this_schema text := :v1 ;
this_date text := replace(current_date::text,'-','');
save_schema text := this_schema||this_date;
[snip]
但这只会死在葡萄藤上:它会引发语法错误 -
psql:NewSchemaSafe.sql:40: ERROR: syntax error at or near ":"
LINE 4: this_schema text := :v1 ;
%this% 是否用引号括在批处理文件中没有区别。
和往常一样,两个问题:
-
set search path语句为什么不“坚持”,当我可以的时候 看到它执行了吗?更新:不相关,请忽略。 - 如何将
:v1参数传递给DO脚本本身?
环境:PostgreSQL 9.3.5 64位(Win);
奇怪之处:我确信这个脚本在两天前可以工作,唯一的变化是删除了 geany 插入的字节顺序标记(UTF BOM 使 psql gag)。
UPDATE:前几天它工作的原因是它在考虑中的架构确实存在的情况下运行。如果模式名称以:v1 的形式传递不存在,则更改search_path(尝试从current_schema 中找到所需的模式)将无济于事 - 这使得@ 更重要987654342@ 被传递给DO,因此可以更直接地使用。
【问题讨论】:
-
回答“如何将 :v1 参数传递给 DO 脚本本身?”这是诀窍:在
DO之外执行prepare foo as select :'v1';,然后在DO块内... execute 'execute foo' into this_schema;。要删除准备好的语句,请执行deallocate foo; -
另一种方式:会话变量。在
DO之外:set foo.bar to :v1;(名称中的点是必需的)和在DO块内this_schema := current_setting('foo.bar'); -
@Abelisto 能否请您将此作为答案,以便将其标记为答案?我没有让
prepare版本工作,但没有花太多时间:另外,set版本更简洁,如果变量类型声明是,可以包含在DECLARE块中添加,即this_schema TEXT := current_setting('foo.bar');。谢谢,GT。
标签: postgresql command-line parameter-passing plpgsql psql