从匿名块中的变量创建带密码的用户

Creating user with password from variables in anonymous block

我想创建一个脚本,其中包含变量 _user_pass 以在 Postgres 数据库中创建用户 如果这样的登录确实存在还不存在。我原以为这会起作用,但我不知道是什么问题:

DO
$DO$
DECLARE
  _user TEXT := 'myuser';
  _pass TEXT := 'user!pass';
BEGIN
   IF NOT EXISTS ( SELECT 1 FROM   pg_catalog.pg_roles WHERE  rolname = _user) THEN
        RAISE NOTICE 'Creating user % ...',_user;
        CREATE USER _user WITH
            LOGIN
            NOSUPERUSER
            CREATEDB
            CREATEROLE
            NOREPLICATION
            PASSWORD _pass;

        RAISE NOTICE 'Created user %',_user;
   ELSE
        RAISE NOTICE 'User % already exists, not creating it',_user;
   END IF;
END
$DO$

如何强制用变量的内容替换变量?

还有$DO$$$有什么区别?

要参数化标识符或语法元素,您通常需要将动态 SQL 与 EXECUTE 结合使用 - 最好结合 format() 以便于使用。

但是实用程序命令(包括所有 SQL DDL 语句)根本不允许传递值或参数替换。您需要在执行之前连接完整的语句。参见:

您的代码将像这样工作:

DO
$do$
DECLARE
  _user text := 'myuser';
  _pass text := 'user!pass';
BEGIN
   IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = _user) THEN
      EXECUTE format(
        'CREATE USER %I WITH
            LOGIN
            NOSUPERUSER
            CREATEDB
            CREATEROLE
            NOREPLICATION
            PASSWORD %L'
         , _user
         , _pass
         );
      RAISE NOTICE 'Created user "%"', _user;
   ELSE
      RAISE NOTICE 'User "%" already exists, not creating it', _user;
   END IF;
END
$do$

但是,尽管 _user_pass 无论如何都是硬编码的,您可以像此处演示的那样进行简化:

  • Create PostgreSQL ROLE (user) if it doesn't exist

Also what is the difference between $DO$ and $$?

参见:

  • What are '$$' used for in PL/pgSQL

ab(使用)自定义选项的另一种方式(引用 Erwin 的旧答案):

又名 bash:

  set -x
  PGPASSWORD="${postgres_db_useradmin_pw:-}" psql -q -t -X \
  -w -U "${postgres_db_useradmin:-}" \
  -h $postgres_db_host -p $postgres_db_port \
  -v ON_ERROR_STOP=1 \
  -v postgres_db_user="${postgres_db_user:-}" \
  -v postgres_db_user_pw="${postgres_db_user_pw:-}" \
  -v postgres_db_name="${postgres_db_name:-}" \
  -f "$sql_script" "${postgres_db_name:-}" > "$tmp_log_file" 2>&1

并在 pgsql

  SET myvars.postgres_db_user TO :'postgres_db_user';
  SET myvars.postgres_db_user_pw TO :'postgres_db_user_pw';

  DO
  $do$
  BEGIN
     EXECUTE format(
        'CREATE ROLE %I WITH PASSWORD %L LOGIN'
           , current_setting('myvars.postgres_db_user', true)::text
           , current_setting('myvars.postgres_db_user_pw', true)::text
     );
     RAISE NOTICE 'Created user "%"', 
  current_setting('myvars.postgres_db_user', true)::text;
  EXCEPTION WHEN OTHERS THEN
     RAISE NOTICE 'User "%" already exists, not creating it',
     current_setting('myvars.postgres_db_user', true)::text;
     EXECUTE format(
        'ALTER ROLE %I WITH PASSWORD %L LOGIN'
           , current_setting('myvars.postgres_db_user', true)::text
           , current_setting('myvars.postgres_db_user_pw', true)::text
     );
  END
  $do$;

值得注意的是,通常通过组合 bash 变量插值和 sql 可以更容易地实现相同的结果,如下所示: https://github.com/YordanGeorgiev/qto/blob/master/src/bash/qto/funcs/provision-db-admin.func.sh