Làm cách nào để xác định xem một bảng có tồn tại trong search_path hiện tại với PLPGSQL không?


10

Tôi đang viết một tập lệnh thiết lập cho một ứng dụng đó là một addon cho một ứng dụng khác, vì vậy tôi muốn kiểm tra xem các bảng cho ứng dụng kia có tồn tại không. Nếu không, tôi muốn cung cấp cho người dùng một lỗi hữu ích. Tuy nhiên, tôi không biết lược đồ nào sẽ giữ các bảng.

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;
$$;

Tuy nhiên, current_setting('search_path')trả về một tệp chứa "$user",publictheo mặc định, không hữu ích lắm.

Điều khác duy nhất tôi có thể nghĩ đến là thử chọn từ bảng và bắt ngoại lệ. Nó sẽ thực hiện công việc, nhưng tôi không nghĩ nó rất thanh lịch và tôi đã đọc rằng nó rất tốn kém để sử dụng (mặc dù có lẽ điều đó sẽ ổn trong kịch bản này vì tôi chỉ chạy nó một lần?).

Câu trả lời:


18

Nhanh chóng và hèn hạ

Trong Postgres 9,4+ sử dụng

SELECT to_regclass('foo');

Trả về NULL nếu không tìm thấy định danh trong đường dẫn tìm kiếm.
Trong Postgres 9.3 trở lên, sử dụng một biểu tượng đểregclass :

SELECT 'foo'::regclass;

Điều này đặt ra một ngoại lệ , nếu không tìm thấy đối tượng!

Nếu 'foo'được tìm thấy, oidđược trả lại trong textđại diện của nó . Đó chỉ là tên bảng, đủ điều kiện theo lược đồ theo đường dẫn tìm kiếm hiện tại và được trích dẫn hai lần khi cần thiết.

Nếu không tìm thấy đối tượng, bạn có thể chắc chắn rằng nó không tồn tại ở bất kỳ đâu trong đường dẫn tìm kiếm - hoặc hoàn toàn không có tên đủ điều kiện cho lược đồ ( schema.foo).

Nếu nó được tìm thấy có hai thiếu sót :

  1. Tìm kiếm bao gồm các lược đồ ngầm định của search_path , cụ thể là pg_catalogpg_temp . Nhưng bạn có thể muốn loại trừ các bảng tạm thời và hệ thống cho mục đích của bạn. (?)

  2. Một cast để regclasslàm việc cho tất cả các đối tượng trong danh mục hệ thống pg_class: chỉ mục, khung nhìn, trình tự, vv Không chỉ các bảng. Bạn dường như đang tìm kiếm một bảng thông thường độc quyền. Tuy nhiên, có lẽ bạn cũng sẽ gặp vấn đề với các đối tượng khác cùng tên. Chi tiết:

Chậm và chắc chắn

Chúng tôi quay lại truy vấn của bạn, nhưng không sử dụng current_setting('search_path'), sẽ trả về cài đặt trần. Sử dụng chức năng thông tin hệ thống chuyên dụng current_schemas(). Mỗi tài liệu:

current_schemas(boolean) name[]
Tên của các lược đồ trong đường dẫn tìm kiếm, tùy chọn bao gồm các lược đồ ngầm

"$user"trong đường dẫn tìm kiếm được giải quyết thông minh. Nếu không có lược đồ nào có tên SESSION_USERtồn tại, lược đồ không được trả về để bắt đầu. Ngoài ra, tùy thuộc vào chính xác những gì bạn muốn, bạn có thể xuất thêm các lược đồ ngầm ( pg_catalogvà có thể pg_temp) - nhưng tôi giả sử bạn không muốn những lược đồ đó trong tay, vì vậy hãy sử dụng:

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 , thể hiện tất cả ngoại trừDOcâu lệnhcuối cùng.
SQL Fiddle (JDBC) có vấn đề với các DOcâu lệnh chứa các ký tự kết thúc.


1

Bạn có thể chuyển đổi giá trị cấu hình thành một mảng và thay thế $userbằng tên người dùng hiện tại. Mảng sau đó có thể được sử dụng trong điều kiện 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.