Kết quả đáng ngạc nhiên cho các loại dữ liệu với công cụ sửa đổi loại


11

Trong khi thảo luận về một giải pháp CTE đệ quy cho câu hỏi này:

@ypercube tình cờ phát hiện ra một ngoại lệ đáng ngạc nhiên, điều này dẫn chúng tôi điều tra việc xử lý các công cụ sửa đổi loại. Chúng tôi tìm thấy hành vi đáng ngạc nhiên.

1. Kiểu cast giữ lại bộ sửa đổi kiểu trong một số ngữ cảnh

Ngay cả khi được hướng dẫn không. Ví dụ cơ bản nhất:

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

Người ta có thể mong đợi varchar(không có sửa đổi), ít nhất là tôi sẽ làm. Nhưng kết quả là varchar(8)(có sửa đổi). Nhiều trường hợp liên quan trong fiddle dưới đây.

2. Nối mảng mất bộ sửa đổi kiểu trong một số ngữ cảnh

Không có nhu cầu, vì vậy lỗi này ở phía đối diện:

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

Biểu thức 1 mang lại varchar(8)[]như mong đợi.
Nhưng thứ 2, sau khi nối một cái khác varchar(8)được tưới xuống chỉ varchar[](không có sửa đổi). Hành vi tương tự từ array_append(), ví dụ trong fiddle dưới đây.

Tất cả điều này không quan trọng trong hầu hết các bối cảnh. Postgres không bị mất dữ liệu và khi được gán cho một cột, giá trị sẽ bị ép đúng loại. Tuy nhiên , sai lầm ở các hướng ngược lại lên đến đỉnh điểm trong một ngoại lệ đáng ngạc nhiên:

3. CTE đệ quy yêu cầu các loại dữ liệu khớp chính xác

Cho bảng đơn giản hóa này:

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

Trong khi rCTE này hoạt động cho varcharcột vc, nó không thành công cho varchar(8)cột 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;
LRI: truy vấn đệ quy "cte" cột 1 có ký tự loại thay đổi (8) [] trong thuật ngữ không đệ quy nhưng ký tự loại thay đổi [] tổng thể  
Gợi ý: Truyền đầu ra của thuật ngữ không đệ quy cho đúng loại. Vị trí: 103

Một cách giải quyết nhanh chóng sẽ được đúc text.

Một UNIONtruy vấn đơn giản không thể hiện cùng một vấn đề: nó giải quyết loại không có sửa đổi, được đảm bảo để lưu giữ tất cả thông tin. Nhưng rCTE thì kén chọn hơn.

Ngoài ra, bạn sẽ không gặp phải vấn đề với việc được sử dụng phổ biến hơn max(vc8)thay vì ORDER BY/ LIMIT 1, bởi vì max()và bạn bè giải quyết textngay lập tức (hoặc loại cơ sở tương ứng mà không cần sửa đổi).

SQL Fiddle trình bày 3 điều:

  1. Một loạt các biểu thức ví dụ bao gồm kết quả đáng ngạc nhiên.
  2. Một rCTE đơn giản hoạt động với varchar(không có sửa đổi).
  3. Cùng rCTE đưa ra một ngoại lệ cho varchar(n)(với công cụ sửa đổi).

Fiddle là cho pg 9.3. Tôi nhận được kết quả tương tự tại địa phương cho pg 9.4.4.

Tôi đã tạo các bảng từ các biểu thức demo để có thể hiển thị loại dữ liệu chính xác bao gồm cả công cụ sửa đổi. Mặc dù pgAdmin hiển thị thông tin này ngoài hộp nhưng nó không có sẵn từ sqlfiddle. Đáng chú ý, nó cũng không có sẵn trong psql(!). Điều này được biết là thiếu sót trong psql và một giải pháp khả thi đã được thảo luận trên các tin tặc pssql trước đây - nhưng chưa được thực hiện. Đây có thể là một trong những lý do vấn đề chưa được phát hiện và khắc phục.

Ở cấp độ SQL, bạn có thể sử dụng pg_typeof()để lấy loại (nhưng không phải là công cụ sửa đổi).

Câu hỏi

Cùng nhau, 3 vấn đề làm cho một mớ hỗn độn.
Nói chính xác, vấn đề 1. không liên quan trực tiếp, nhưng nó phá hỏng cách khắc phục dường như rõ ràng với một diễn viên trong thuật ngữ không đệ quy: ARRAY[vc8]::varchar[]hoặc tương tự, làm tăng thêm sự nhầm lẫn.
Những mặt hàng nào trong số này là một lỗi, trục trặc hoặc chỉ là nó phải như thế nào?
Tôi đang thiếu một cái gì đó hay chúng ta nên báo cáo một lỗi?


Điều này chắc chắn có vẻ khá đáng ngờ. Tôi nghi ngờ khả năng tương thích ngược cho các truy vấn công đoàn hiện tại có thể đóng một phần.
Craig Ringer

@CraigRinger: Tôi không thấy lý do tại sao việc ghép mảng làm giảm trình sửa đổi mà không cần và diễn viên thì không, mặc dù được yêu cầu. Không phải tại sao rCTE phải nghiêm ngặt hơn (kém thông minh hơn) so với UNIONcác truy vấn đơn giản . Có thể là chúng tôi đã tìm thấy ba lỗi nhỏ độc lập cùng một lúc? (Sau nhiều tháng và nhiều tháng không tìm thấy như vậy.) Bạn sẽ cảm thấy lỗi nào trong số đó?
Erwin Brandstetter

Câu trả lời:


1

Điều này là do các thuộc tính quan hệ (được xác định trong pg_classpg_attribute, hoặc được xác định động từ một selectcâu lệnh) hỗ trợ các bộ sửa đổi (thông qua pg_attribute.atttypmod), trong khi các tham số chức năng thì không. Công cụ sửa đổi bị mất khi được xử lý thông qua các chức năng và vì tất cả các nhà khai thác được xử lý thông qua các chức năng, công cụ sửa đổi cũng bị mất khi được xử lý bởi các nhà khai thác.

Các hàm có giá trị đầu ra hoặc các bộ bản ghi trả về hoặc tương đương returns table(...)cũng không thể giữ lại bất kỳ bộ sửa đổi nào có trong định nghĩa. Tuy nhiên, bảng return setof <type>sẽ giữ lại (trên thực tế, có lẽ định kiểu) vào bất kỳ từ bổ nghĩa được định nghĩa cho typetrong pg_attribute.

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.