ผลลัพธ์ที่น่าแปลกใจสำหรับประเภทข้อมูลที่มีตัวแก้ไขประเภท


11

ในขณะที่พูดคุยโซลูชัน CTE แบบเรียกซ้ำสำหรับคำถามนี้:

@ypercubeพบข้อผิดพลาดที่น่าแปลกใจซึ่งทำให้เราตรวจสอบการจัดการกับตัวดัดแปลงประเภท เราพบพฤติกรรมที่น่าประหลาดใจ

1. Type cast ยังคงประเภทโมดิฟายเออร์ในบางบริบท

แม้เมื่อสั่งไม่ให้ ตัวอย่างพื้นฐานที่สุด:

SELECT 'vc8'::varchar(8)::varchar

หนึ่งอาจคาดหวังvarchar(ไม่มีตัวดัดแปลง) อย่างน้อยฉันจะ แต่ผลลัพธ์คือvarchar(8)(พร้อมตัวดัดแปลง) กรณีที่เกี่ยวข้องจำนวนมากในซอด้านล่าง

2. การต่อข้อมูล Array สูญเสียโมดิฟายเออร์ในบริบทบางอย่าง

โดยไม่จำเป็นต้องใช้ดังนั้นข้อผิดพลาดนี้อยู่ฝั่งตรงข้าม:

SELECT ARRAY['vc8']::varchar(8)[]
     , ARRAY['vc8']::varchar(8)[] || 'vc8'::varchar(8)

นิพจน์แรกให้ผลvarchar(8)[]ตามที่คาดไว้
แต่ข้อที่ 2 หลังจากการต่อข้อมูลอื่นvarchar(8)จะถูกรดน้ำลงไปเพียงvarchar[](ไม่มีตัวปรับแต่ง) พฤติกรรมที่คล้ายกันจากarray_append()ตัวอย่างในซอด้านล่าง

ทั้งหมดนี้ไม่สำคัญในบริบทส่วนใหญ่ Postgres จะไม่สูญเสียข้อมูลและเมื่อกำหนดให้กับคอลัมน์ค่าจะถูกบังคับให้เป็นประเภทที่ถูกต้องอย่างไรก็ตาม อย่างไรก็ตามการทำผิดในทิศทางตรงกันข้ามจะทำให้เกิดข้อยกเว้นที่น่าประหลาดใจ:

3. Recursive CTE ต้องการประเภทข้อมูลให้ตรงกัน

รับตารางง่ายนี้

CREATE TABLE a (
  vc8  varchar(8)  -- with modifier
, vc   varchar     -- without  
);
INSERT INTO a VALUES  ('a',  'a'), ('bb', 'bb');

ขณะที่ rCTE นี้ใช้งานได้กับvarcharคอลัมน์vcแต่ล้มเหลวสำหรับvarchar(8)คอลัมน์vc8:

WITH RECURSIVE cte AS (
   (
   SELECT ARRAY[vc8] AS arr  -- produces varchar(8)[]
   FROM   a
   ORDER  BY vc8
   LIMIT 1
   )

   UNION ALL
   (
   SELECT a.vc8 || c.arr  -- produces varchar[] !!
   FROM   cte c
   JOIN   a ON a.vc8 > c.arr[1]
   ORDER  BY vc8
   LIMIT 1
   )
   )
TABLE  cte;
ข้อผิดพลาด: ข้อความค้นหาแบบเรียกซ้ำ "cte" คอลัมน์ 1 มีประเภทอักขระที่หลากหลาย (8) [] ในระยะที่ไม่ใช่แบบเรียกซ้ำ แต่เป็นประเภทอักขระที่หลากหลาย [] โดยรวม  
คำแนะนำ: ส่งเอาต์พุตของคำที่ไม่เกิดซ้ำไปเป็นชนิดที่ถูกต้อง ตำแหน่ง: 103

textหนึ่งวิธีแก้ปัญหาอย่างรวดเร็วจะโยน

UNIONแบบสอบถามธรรมดาไม่แสดงปัญหาเดียวกัน: มันจะตัดสินสำหรับชนิดที่ไม่มีตัวแก้ไขซึ่งรับประกันว่าจะรักษาข้อมูลทั้งหมด แต่ rCTE นั้นพิถีพิถันมากกว่า

นอกจากนี้คุณจะไม่ประสบปัญหากับการใช้งานที่บ่อยขึ้นmax(vc8)แทนORDER BY/ LIMIT 1, เพราะmax()และเพื่อน ๆ จะตกลงtextกันทันที (หรือประเภทฐานที่เกี่ยวข้องโดยไม่มีการแก้ไข)

SQL Fiddleแสดง 3 สิ่ง:

  1. ช่วงของนิพจน์ตัวอย่างรวมถึงผลลัพธ์ที่น่าประหลาดใจ
  2. rCTE ง่าย ๆ ที่ทำงานกับvarchar(ไม่มีตัวแก้ไข)
  3. rCTE เดียวกันกำลังเพิ่มข้อยกเว้นสำหรับvarchar(n)(พร้อมตัวดัดแปลง)

ซอเป็นสำหรับ pg 9.3 ฉันได้รับผลลัพธ์เดียวกันในเครื่องสำหรับ pg 9.4.4

ฉันสร้างตารางจากนิพจน์การสาธิตเพื่อให้สามารถแสดงชนิดข้อมูลที่แน่นอนรวมถึงตัวแก้ไข ในขณะที่ pgAdmin แสดงข้อมูลนี้นอกกรอบมันไม่สามารถใช้งานได้จาก sqlfiddle ที่น่าทึ่งก็ยังไม่สามารถใช้ได้ในpsql(!) สิ่งนี้เป็นที่รู้จักกันดีใน psql และมีการพูดถึงวิธีแก้ปัญหาที่เป็นไปได้ใน pgsql-hackers มาก่อนแต่ยังไม่ได้นำมาใช้ นี่อาจเป็นหนึ่งในสาเหตุที่ยังไม่ได้ตรวจพบและแก้ไขปัญหา

ในระดับ SQL คุณสามารถใช้pg_typeof()เพื่อรับชนิด (แต่ไม่ใช่ตัวดัดแปลง)

คำถาม

เมื่อรวมกันแล้วทั้งสามประเด็นก็เลอะเทอะ
เพื่อความแม่นยำประเด็นที่1ไม่ได้เกี่ยวข้องโดยตรง แต่เป็นการทำลายการแก้ไขที่เห็นได้ชัดโดยนักแสดงในระยะที่ไม่เกิดซ้ำ: ARRAY[vc8]::varchar[]หรือคล้ายกันซึ่งเพิ่มความสับสน
รายการใดบ้างที่เป็นข้อผิดพลาดความผิดพลาดหรือสิ่งที่ควรจะเป็น
ฉันทำอะไรบางอย่างขาดหายไปหรือเราควรรายงานข้อผิดพลาด?


นี้ดูเหมือนว่าค่อนข้างน่าสงสัย ฉันสงสัยว่าความเข้ากันได้แบบย้อนหลังสำหรับแบบสอบถามแบบร่วมอาจมีส่วนร่วม
Craig Ringer

@ CraigRinger: ฉันไม่เห็นว่าทำไมการเรียงต่อกันของอาร์เรย์ลดลงโดยไม่จำเป็นต้องปรับเปลี่ยนและนักแสดงไม่ได้แม้ว่าจะมีการร้องขอ ไม่ว่าทำไม rCTE จึงต้องเข้มงวด (ฉลาดน้อยกว่า) มากกว่าการUNIONสืบค้นแบบง่าย เป็นไปได้ไหมที่เราพบบั๊กอิสระสามตัวพร้อมกัน? (หลังจากเดือนและเดือนที่ไม่มีการค้นพบเช่นนั้น) คุณควรจะยื่นข้อใดเป็นข้อผิดพลาด?
Erwin Brandstetter

คำตอบ:


1

นี่คือสาเหตุที่คุณสมบัติความสัมพันธ์ (กำหนดไว้ในpg_classและpg_attributeหรือกำหนดแบบไดนามิกจากselectคำสั่ง) สนับสนุนการปรับเปลี่ยน (ผ่านpg_attribute.atttypmod) ในขณะที่ฟังก์ชั่นพารามิเตอร์ไม่ได้ โมเดอเรเตอร์จะหายไปเมื่อประมวลผลผ่านฟังก์ชั่นและเนื่องจากโอเปอเรเตอร์ทั้งหมดได้รับการจัดการผ่านฟังก์ชั่นโมดิฟายเออร์จะสูญหายเมื่อประมวลผลโดยผู้ดำเนินการเช่นกัน

ฟังก์ชั่นที่มีค่าเอาต์พุตหรือชุดของระเบียนที่ส่งคืนหรือสิ่งที่เทียบเท่าreturns table(...)นั้นยังไม่สามารถคงไว้ซึ่งตัวดัดแปลงใด ๆ ที่รวมอยู่ในคำจำกัดความ แต่ตารางที่return setof <type>จะยังคงมี (ที่จริงอาจจะ typecast) การปรับเปลี่ยนใด ๆ ที่กำหนดไว้สำหรับในtypepg_attribute

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.