Как определить, существует ли таблица в текущем пути поиска с PLPGSQL?

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')возвращает текст, содержащий "$user",publicпо умолчанию, что не очень полезно.

Единственное, о чем я могу думать, это попытаться выбрать из таблицы и поймать исключение. Это бы сработало, но я не думаю, что это очень элегантно, и я читал, что это дорого в использовании (хотя, может быть, в этом сценарии это будет нормально, поскольку я запускаю его только один раз?).

cimmanon
источник

Ответы:

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_catalogиpg_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

Вы можете преобразовать значение конфигурации в массив и заменить $userтекущее имя пользователя. Затем массив можно использовать в условии where:

where n.nspname = any(string_to_array(replace(current_setting('search_path'), '$user', current_user), ','))
a_horse_with_no_name
источник
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
Вишал Бендре
источник