型修飾子を使用したデータ型の驚くべき結果


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)[]期待どおりに生成されます。
しかし、2番目は、連結した後、別のもの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は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の型は、非再帰的な用語では文字vary(8)[]ですが、全体では文字Variation []です  
ヒント:非再帰的な用語の出力を正しいタイプにキャストします。ポジション:103

1つの簡単な回避策は、にキャストすることtextです。

単純なUNIONクエリでも同じ問題は発生しません。すべての情報が保持されることが保証されている修飾子なしのタイプで解決されます。しかし、rCTEはよりうるさいです。

また、/のmax(vc8)代わりに一般的に使用される問題に遭遇することはありません。なぜなら、友達はすぐに解決するからです(または修飾子のないそれぞれの基本型)。ORDER BYLIMIT 1max()text

3つのことを示す SQL Fiddle

  1. 意外な結果を含む一連の式の例。
  2. varchar(修飾子なしで)機能する単純なrCTE 。
  3. 同じrCTEでvarchar(n)(修飾子付き)の例外が発生します。

フィドルは9.3ページ用です。ローカルで同じ結果がpg 9.4.4で得られます。

修飾子を含む正確なデータ型を表示できるように、デモ式からテーブルを作成しました。pgAdminはこの情報をそのまま表示しますが、sqlfiddleからは利用できません。驚くべきことに、psql(!)でも利用できません。これはpsqlの既知の欠点であり、可能な解決策は以前にpgsql-hackersで議論されていますが、まだ実装されていません。これが、まだ問題が検出および修正されていない理由の1つである可能性があります。

SQLレベルでは、を使用pg_typeof()して型を取得できます(修飾子は不可)。

ご質問

一緒に、3つの問題は混乱を引き起こします。
正確には、問題1.は直接関与していませんが、非再帰的な用語であるキャストなどの明らかな修正を台無しにARRAY[vc8]::varchar[]し、混乱を招いています。
これらの項目のどれがバグ、グリッチ、またはそれがどのように想定されているのですか?
何か不足していますか、それともバグを報告する必要がありますか?


これは確かにかなり疑わしいようです。既存のユニオンクエリの下位互換性が役割を果たすと思います。
クレイグリンガー

@CraigRinger:要求されていても、配列の連結で修飾子が不要になり、キャストが不要になる理由がわかりません。rCTEが単純なUNIONクエリよりも厳密でなければならない(それほどスマートではない)理由もありません。3つの独立した小さなバグを一度に見つけたのでしょうか?(そのような発見が何ヶ月も何ヶ月もない後。)バグとして提出する必要があると思うのはどれですか。
Erwin Brandstetter、2015

回答:


1

これは、(およびで定義された、またはステートメントから動的に定義された)リレーション属性が(を介して)修飾子をサポートするためですが、関数パラメーターはサポートしていません。修飾子は関数を介して処理されると失われ、すべての演算子は関数を介して処理されるため、演算子によって処理されると修飾子も失われます。pg_classpg_attributeselectpg_attribute.atttypmod

出力値を持つ関数、またはレコードのセットを返す関数、または同等の関数returns table(...)も、定義に含まれる修飾子を保持できません。ただし、でreturn setof <type>定義されtypeた修飾子を保持する(実際には、おそらく型キャストされる)テーブルpg_attribute

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.