ฉันจะทราบได้อย่างไรว่าตารางมีอยู่ใน search_path ปัจจุบันด้วย PLPGSQL หรือไม่


10

ฉันกำลังเขียนสคริปต์การตั้งค่าสำหรับแอปพลิเคชันที่เป็น addon สำหรับแอปพลิเคชันอื่นดังนั้นฉันต้องการตรวจสอบว่ามีตารางสำหรับแอปพลิเคชันอื่นอยู่หรือไม่ ถ้าไม่ฉันต้องการให้ข้อผิดพลาดที่เป็นประโยชน์แก่ผู้ใช้ อย่างไรก็ตามฉันไม่ทราบว่าสคีมาใดที่จะถือตาราง

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ตามค่าเริ่มต้นซึ่งไม่มีประโยชน์มากนัก

สิ่งเดียวที่ฉันคิดได้ก็คือลองเลือกจากตารางและจับข้อยกเว้น มันจะทำงานได้ แต่ฉันไม่คิดว่ามันดีมากและฉันได้อ่านว่ามันมีราคาแพงที่จะใช้ (แม้ว่าอาจจะใช้ได้ในสถานการณ์นี้

คำตอบ:


18

รวดเร็วและสกปรก

ใน Postgres 9.4+ ให้ใช้

SELECT to_regclass('foo');

ส่งคืนค่า NULL หากไม่พบตัวระบุในพา ธ การค้นหา
ใน Postgres 9.3 หรือเก่ากว่าให้ใช้นักแสดงเพื่อregclass :

SELECT 'foo'::regclass;

สิ่งนี้ทำให้เกิดข้อยกเว้นหากไม่พบวัตถุ!

หาก'foo'พบว่าoidถูกส่งคืนในการtextเป็นตัวแทนของมัน นั่นเป็นเพียงชื่อตาราง schema ที่ผ่านการรับรองตามเส้นทางการค้นหาปัจจุบันและการเสนอราคาซ้ำในกรณีที่จำเป็น

หากไม่พบวัตถุคุณสามารถตรวจสอบให้แน่ใจว่าไม่มีวัตถุใด ๆ อยู่ในเส้นทางการค้นหาหรือไม่ใช้ชื่อที่ผ่านการรับรองจาก schema ( schema.foo)

หากพบว่ามีข้อบกพร่องสองประการ :

  1. การค้นหารวมถึงสคีนัยของSEARCH_PATHคือและpg_catalog pg_tempแต่คุณอาจต้องการยกเว้น temp และตารางระบบเพื่อวัตถุประสงค์ของคุณ (?)

  2. cast เพื่อregclassทำงานกับวัตถุทั้งหมดในแค็ตตาล็อกระบบpg_class: ดัชนีมุมมองลำดับ ฯลฯไม่เพียง แต่ตาราง คุณดูเหมือนจะมองหาตารางปกติโดยเฉพาะ อย่างไรก็ตามคุณอาจมีปัญหากับวัตถุอื่นที่มีชื่อเดียวกันด้วย รายละเอียด:

ช้าและแน่นอน

เรากลับไปที่การสืบค้นของคุณ แต่ไม่ได้ใช้current_setting('search_path')ซึ่งจะคืนการตั้งค่าเปล่า current_schemas()ใช้ฟังก์ชั่นระบบข้อมูลเฉพาะ ตามเอกสาร:

current_schemas(boolean) name[]
ชื่อของสกีมาในเส้นทางการค้นหาทางเลือกรวมถึง schema โดยปริยาย

"$user"ในเส้นทางการค้นหาได้รับการแก้ไขอย่างชาญฉลาด หากไม่มีสคีมาที่มีชื่อSESSION_USERอยู่สคีมาจะไม่ถูกส่งกลับไปเริ่มต้นด้วย นอกจากนี้ขึ้นอยู่กับสิ่งที่คุณต้องการอย่างแน่นอนคุณยังสามารถเพิ่ม schema ที่เป็นนัย ( 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 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.