如何使用PLPGSQL确定当前search_path中是否存在表?


10

我正在为一个应用程序编写安装脚本,该脚本是另一个应用程序的附件,因此我想检查另一个应用程序的表是否存在。如果没有,我想给用户一个有用的错误。但是,我不知道哪种模式将保存表格。

DO LANGUAGE plpgsql $$
BEGIN
    PERFORM 1
    FROM
        pg_catalog.pg_class c
        JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
    WHERE
        n.nspname = current_setting('search_path')
        AND c.relname = 'foo'
        AND c.relkind = 'r'; -- not sure if I actually need this or not...

    IF NOT FOUND THEN
        RAISE 'This application depends on tables created by another application';
    END IF;
END;
$$;

但是,默认情况下current_setting('search_path')返回一个包含TEXT的文本"$user",public,它并不是非常有用。

我唯一想到的另一件事就是尝试从表中进行选择并捕获异常。它将完成这项工作,但是我认为它不是非常优雅,并且我已经读到它使用起来很昂贵(尽管在这种情况下这可能还可以,因为我只运行了一次?)。

Answers:


18

又快又脏

在Postgres 9.4+中使用

SELECT to_regclass('foo');

如果在搜索路径中找不到标识符,则返回NULL。
在Postgres 9.3或更早的版本中,使用强制转换为regclass

SELECT 'foo'::regclass;

引发了一个异常,如果没有找到的对象!

如果'foo'找到,oid则以其text表示形式返回。那只是表名,根据当前搜索路径进行模式限定,并在必要时用双引号引起来。

如果找不到该对象,则可以确保该对象在搜索路径中不存在-或完全不包含模式限定名称(schema.foo)。

如果找到,则有两个缺点

  1. 搜索包括search_path的隐式架构,即pg_catalogpg_temp。但是您可能想要排除临时表和系统表。(?)

  2. 强制转换regclass适用于系统目录中的所有对象pg_class:索引,视图,序列等。不仅限于表。您似乎只在寻找常规表。但是,其他同名对象也可能会遇到问题。细节:

慢而确定

我们返回您的查询,但不要使用current_setting('search_path'),它会返回原始设置。使用专用的系统信息功能current_schemas()。每个文档:

current_schemas(boolean) name[]
搜索路径中模式的名称,可以选择包括隐式模式

"$user"搜索路径中的问题得到了很好的解决。如果不SESSION_USER存在名称为的架构,则不返回该架构开头。另外,根据您确切想要的是,您还可以输出隐式模式(pg_catalog可能还可以pg_temp)-但我假设您不希望出现这种情况,因此请使用:

DO 
$do$
BEGIN
   IF EXISTS (
      SELECT  -- list can be empty
      FROM   pg_catalog.pg_class c
      JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
      WHERE  n.nspname = ANY(current_schemas(FALSE))
      AND    n.nspname NOT LIKE 'pg_%'  -- exclude system schemas!
      AND    c.relname = 'foo'
      AND    c.relkind = 'r')           -- you probably need this
   THEN
      RAISE 'This application depends on tables created by another application';
   END IF;
END
$do$;

SQL Fiddle,演示除最后一条DO语句外的所有内容。
SQL Fiddle(JDBC)DO包含终止字符的语句存在问题。


1

您可以将config值转换为数组,并用$user当前用户名替换。然后可以在where条件中使用该数组:

where n.nspname = any(string_to_array(replace(current_setting('search_path'), '$user', current_user), ','))

0
./sshi.sh vb20deployment controller <<'HERE'
export PGPASSWORD="postgres"
cd logu/postgresql/bin
row=1
tableArray=(table1 table2 table3 table4 table5 table6)

for (( x=0 ; x<=5 ; x++)) ; do        

./psql.bin --port=5432 --username=postgres --host=hostname.rds.amazonaws.com --dbname=mydb -c "SELECT * FROM information_schema.tables WHERE '${tableArray[$x]}' = table_name" | while read -a Record ; do
  row=$((row + 1))
  if [[ $row -gt 3 ]]; then

     echo ${Record[4]}

   fi
done

done


HERE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.