PSQL Command Line Arguments in DO script

前端 未结 2 757
囚心锁ツ
囚心锁ツ 2020-12-11 11:25

I\'ve got a script NewSchemaSafe.sql that creates a new schema based on the project directory; it\'s called from the Windows command line as follows:

         


        
相关标签:
2条回答
  • 2020-12-11 11:44

    Because the PL blocks is actually text constants in the code the internal variables is not substituted inside them in the usual way. Fortunately it is possible to use a session variables for sharing data between different SQL/PL blocks:

    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 $$;
    
    0 讨论(0)
  • 2020-12-11 11:51

    Create a temporary function instead of using a DO statement. That's the solution if you need to pass parameters.

    CREATE FUNCTION pg_temp.f_create_schema(_schema text)  -- note function schema "pg_temp"
      RETURNS void AS 
    $func$
    DECLARE
       _date        text := to_char(current_date, 'YYYYMMDD');
       _save_schema text := _schema || _date;  -- unescaped identifier
    BEGIN
       IF EXISTS (SELECT 1 FROM information_schema.schemata
                  WHERE  schema_name = _save_schema) THEN  -- unescaped identifier
          EXECUTE format('DROP SCHEMA %I CASCADE', _save_schema);  -- escaped identifier!
       END IF;
    
       IF EXISTS (SELECT 1 FROM information_schema.schemata
                  WHERE  schema_name = _schema) THEN
          EXECUTE format(
            'ALTER SCHEMA %1$I RENAME TO %2$I;
             COMMENT ON SCHEMA %2$I IS $c$Schema renamed by SLSM creation on %3$s.$c$'
           , _schema, _save_schema, _date);
       END IF;
    
       EXECUTE 'CREATE SCHEMA ' || quote_ident(_schema);
    END
    $func$ LANGUAGE plpgsql;
    

    Call:

    SELECT pg_temp.f_create_schema('Foo');  -- function name must be schema-qualified
    

    From psql with SQL interpolation using a variable v1:

    SELECT pg_temp.f_create_schema(:'v1');
    

    The schema name you pass for _schema is case sensitive and unquoted.

    pg_temp is a pseudo name that translates to the temporary schema of the current session internally automatically. All objects in the temporary schema die at the end of the session.

    "Temporary" functions are not documented explicitly in the manual, but safe to use.

    • Is there such thing as a "temp function"?

    It makes sense if you need to the function once (or a few times) in the same session for varying databases. For repeated use in the same database, create a plain function instead.

    Of course you need the TEMPORARY privilege for the database - which users have by default.

    While being at it, I improved a couple of things:

    • Escape identifiers to defend against SQL injection and ordinary syntax errors. Use quote_ident() or format() for anything more complex.

    • You don't need to concatenate a semicolon to the end of a single SQL command.

    • You can EXECUTE multiple SQL statements at once. (Now you need a semicolon between statements.)

    • Use nested dollar quotes to avoid quoting hell.

    There are all kinds of workarounds, too:

    • Use variable set by psql meta-command inside of DO block
    • CREATE SEQUENCE using expressions with psql variables for parameters

    BTW, customized options ("session variables") require a two-part name (of the form extension.variable) for historic reasons. It proved to be useful in avoiding naming conflicts as much as possible.

    0 讨论(0)
提交回复
热议问题