유형 수정자를 사용한 데이터 유형에 대한 놀라운 결과


11

이 질문에 대한 재귀 CTE 솔루션을 논의하는 동안 :

@ypercube 는 놀라운 예외를 우연히 발견하여 유형 수정 자의 처리를 조사했습니다. 우리는 놀라운 행동을 발견했습니다.

1. 유형 캐스트는 일부 상황에서 유형 수정자를 유지합니다.

지시하지 않더라도. 가장 기본적인 예 :

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

varchar적어도 나는 아마 수정자를 기대 하지 않을 것입니다. 그러나 결과는 varchar(8)(수정 자 포함)입니다. 아래 바이올린의 많은 관련 사례.

2. 일부 상황에서는 배열 연결이 유형 수정자를 잃습니다.

필요하지 않으므로 반대쪽에서 오류가 발생합니다.

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

첫 번째 표현은 varchar(8)[]예상대로 산출 됩니다.
그러나 두 번째 varchar(8)는 다른 하나를 연결 한 후 varchar[]수정 자 없음으로 물을 뿌립니다 . 의 유사한 행동array_append() , 아래 바이올린의 예.

이 모든 것은 대부분의 상황에서 중요하지 않습니다. Postgres는 데이터를 잃지 않으며 열에 할당되면 값이 올바른 유형으로 강제됩니다. 하나 반대 방향으로 잘못하면 놀라운 예외가 발생합니다.

3. 재귀 CTE는 정확하게 일치하는 데이터 유형을 요구합니다

이 단순화 된 테이블이 주어지면 :

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

이 rCTE가 작동하는 동안 varcharvc, 그것은 실패 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에는 비 재귀 용어로 유형 문자 varying (8) []이 있지만 전체적으로 유형 문자 가변 []이 있습니다.  
힌트 : 비 재귀 항의 출력을 올바른 유형으로 캐스트하십시오. 위치 : 103

한 가지 빠른 해결 방법은로 캐스팅하는 것 text입니다.

일반 UNION쿼리는 동일한 문제를 나타내지 않습니다. 수정자가없는 유형에 대해 해결되므로 모든 정보가 보존됩니다. 그러나 rCTE는 더 까다 롭습니다.

또한 친구 max(vc8)ORDER BY/ 대신에 일반적으로 사용되는 문제 (또는 수정자가없는 각 기본 유형) LIMIT 1때문에 문제가 발생하지 않습니다 .max()text

3 가지를 보여주는 SQL Fiddle :

  1. 놀라운 결과를 포함한 다양한 표현 예.
  2. varchar수정 자없이 작동하는 간단한 rCTE .
  3. varchar(n)(수정자를 사용 하여) 예외를 발생시키는 동일한 rCTE .

바이올린은 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_classpg_attribute에서 정의되거나 select명령문 에서 동적으로 정의 됨)으로 인해 발생합니다 . 수정자는 함수를 통해 처리 될 때 유실되며 모든 연산자는 함수를 통해 처리되므로 수정자는 운영자가 처리 할 때 유실됩니다.pg_attribute.atttypmod

출력 값이 있거나 레코드 세트를 리턴하는 함수 또는 이에 상응하는 함수 returns table(...)도 정의에 포함 된 수정자를 보유 할 수 없습니다. 그러나 테이블 return setof <type>(아마도 배역에, 실제로) 유지됩니다에 정의 된 모든 수정 type에서 pg_attribute.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.