Basic transactional DDL script in PostgreSQL

use*_*783 6 postgresql transaction ddl plpgsql

PostgreSQL newbie here trying to put together a transactional DDL script to atomically create a database and its schema in Postgres 9.3: in a transaction, create a few tables; if any errors, roll the whole thing back; otherwise commit. I'm having a hard time getting the syntax right, and I suspect my problems might stem from conflating SQL DDL with PL/pgSQL and/or not grokking the transaction semantics.

Long story short, what's the PL/pgSQL boilerplate for a script to do something like this?

My attempts have gone something like schema.sql here:

BEGIN;

CREATE TABLE IF NOT EXISTS blah ( ... ); -- much DDL

EXCEPTION WHEN OTHERS THEN ROLLBACK; -- this, I gather, is PL/pgSQL

COMMIT;
Run Code Online (Sandbox Code Playgroud)

\i schema.sql at the psql prompt produces a syntax error at or near EXCEPTION. OK, so EXCEPTION must be PL/pgSQL, and all this needs to go in a PL/pgSQL declaration. Let's try again:

Per the grammar at http://www.postgresql.org/docs/9.3/static/plpgsql-structure.html, this looks like:

[ <<label>> ]
[ DECLARE
    declarations ]
BEGIN
    statements
END [ label ];
Run Code Online (Sandbox Code Playgroud)

I don't need to name this, it's a one-off provisioning script, not declaring a function I'm going to use again. So skip the declarations and expand statements to what I had before:

BEGIN

    BEGIN;

    CREATE TABLE IF NOT EXISTS blah ( ... ); -- much DDL

    EXCEPTION WHEN OTHERS THEN ROLLBACK; 

    COMMIT;

END;
Run Code Online (Sandbox Code Playgroud)

This blows up in even worse fashion, with syntax errors on BEGIN, EXCEPTION, and then it keeps running the rest of the script anyways, complaining about not being in a transaction.

What's the misunderstanding I have here?

Erw*_*ter 7

如果有任何错误,请回滚整个内容;

它比你想象的要简单。事务中的任何异常(未以某种方式捕获)都会自动触发ROLLBACK整个事务的a 。你不需要做任何额外的事情

BEGIN;
CREATE TABLE IF NOT EXISTS blah ( ... );
-- much more DDL
COMMIT;
Run Code Online (Sandbox Code Playgroud)

你不能启动,提交或回滚事务里面PLPGSQL可言,因为PLPGSQL块总是在外部事务的情况下自动运行。

不要将事务管理的 SQL 命令plpgsql 代码块的元素混淆。BEGIN两者都用作关键字,这是唯一的共同点。这绝不是模棱两可的,因为 SQL 命令在 plpgsql 代码中不可用,并且在 plpgsql 代码块之外没有 plpgsql 命令。

EXCEPTIONplpgsql 块中子句仅用于捕获错误并在ROLLBACK. 当然,只有一些ROLLBACK不会撤销的事情才有意义——比如提出一条永远不会回滚的消息
您的演示代码不需要任何这些。