Tür değiştiricili veri türleri için şaşırtıcı sonuçlar


11

Bu soru için özyinelemeli bir CTE çözümü tartışılırken:

@ ypercube , tip değiştiricilerin kullanımını araştırmamıza neden olan şaşırtıcı bir istisna karşısında tökezledi. Şaşırtıcı bir davranış bulduk.

1. Tür döküm, bazı bağlamlarda tür değiştiriciyi korur

Olmaması talimatı verildiğinde bile. En temel örnek:

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

Biri bekleyebilir varchar(değiştirici yok), en azından ben isterim. Ama sonuç varchar(8)(değiştirici ile). Aşağıdaki kemanda ilgili birçok vaka.

2. Dizi birleştirme, bazı bağlamlarda tür değiştiricisini kaybeder

İhtiyaç yok, bu yüzden karşı tarafta erir:

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

1. ekspresyon varchar(8)[]beklendiği gibi sonuç verir .
Ancak ikincisi, bir başkasını birleştirdikten sonra varchar(8)sadece varchar[](değiştirici olmadan) sulanır . Benzer davranış array_append(), aşağıdaki keman örnekleri.

Bütün bunlar çoğu bağlamda önemli değil. Postgres veri kaybetmez ve bir sütuna atandığında, değer yine de doğru türe zorlanır. Bununla birlikte , zıt yönlerde hata, şaşırtıcı bir istisna ile sonuçlanır:

3. Özyinelemeli CTE veri türlerinin tam olarak eşleşmesini ister

Bu basitleştirilmiş tablo göz önüne alındığında:

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

Bu rCTE işe yararken varcharsütunda vc, bu başarısız varchar(8)sütununda 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;
HATA: özyinelemeli sorgu "cte" sütun 1, özyinelemesiz terimde tip karakteri değişen (8) [] var, ancak genel olarak tür karakter [] genel olarak  
İpucu: Özyinelemesiz terimin çıktısını doğru türe çevirin. Pozisyon: 103

Hızlı bir çözüm, kullanmaktır text.

Düz bir UNIONsorgu aynı sorunu göstermez: değiştiricisiz tür için yerleşir ve tüm bilgileri koruyacağı garanti edilir. Ama rCTE daha seçici.

Ayrıca, / max(vc8)yerine daha yaygın olarak kullanılan sorunlarla karşılaşmazsınız , çünkü arkadaşlar hemen (veya değiştiricisiz ilgili temel tür) için yerleşir .ORDER BYLIMIT 1max()text

3 şey gösteren SQL Fiddle :

  1. Şaşırtıcı sonuçlar içeren bir dizi örnek ifade.
  2. varchar(Değiştirici olmadan) ile çalışan basit bir rCTE .
  3. Aynı rCTE varchar(n)(değiştirici ile) için bir istisna oluşturur .

Keman pg 9.3 içindir. Aynı sonuçları pg 9.4.4 için yerel olarak alıyorum.

Değiştirici dahil tam veri türünü gösterebilmek için demo ifadelerinden tablolar oluşturdum. PgAdmin bu bilgiyi kutudan çıkarırken, sqlfiddle'da mevcut değildir. Dikkat çekici bir şekilde, psql(!) 'De de mevcut değildir . Bu psql'de eksiklik olduğu bilinmektedir ve olası bir çözüm daha önce pgsql-hacker'larda tartışılmıştır - ancak henüz uygulanmamıştır. Bu, sorunun henüz tespit edilememesinin ve çözülememesinin nedenlerinden biri olabilir.

SQL düzeyinde, pg_typeof()türü almak için kullanabilirsiniz (ancak değiştiriciyi değil).

Sorular

3 sayı birlikte ortalığı karıştırıyor.
Kesin olmak gerekirse, sorun 1. doğrudan dahil değildir, ancak görünüşte bariz düzeltmeyi özyinelemesiz terimde bir dökümle mahveder: ARRAY[vc8]::varchar[]veya benzeri, karışıklığa katkıda bulunur.
Bu öğelerden hangisi bir hata, bir aksaklık ya da nasıl olması gerekiyor?
Bir şey mi kaçırıyorum yoksa bir hatayı rapor etmeli miyiz?


Bu kesinlikle şüpheli görünüyor. Mevcut sendika sorguları için geriye dönük uyumluluğun bir rol oynayabileceğinden şüpheleniyorum.
Craig Ringer

@CraigRinger: Dizi birleştirmesinin neden değiştiriciyi gerek kalmadan düşürdüğünü ve döküm bile istenmiyor olsa bile görmüyorum. Neden RCTE'nin basit UNIONsorgulardan daha katı (daha az akıllı) olması gerekmiyor . Bulduğumuz olabilir misin üç kerede bağımsız küçük hatalar? (Aylar ve aylar sonra böyle bir buluntu yok.) Bunlardan hangisini böcek olarak dosyalamanız gerektiğini düşünüyorsunuz?
Erwin Brandstetter

Yanıtlar:


1

Bunun nedeni , işlev parametreleri desteklemezken değiştiricileri (yoluyla ) destekleyen ilişki özniteliklerinden ( pg_classve pg_attributebir selectifadede dinamik olarak tanımlanmış veya bir ifadeden dinamik olarak tanımlanmıştır ) kaynaklanmaktadır . Değiştiriciler işlevler aracılığıyla işlendiğinde kaybolur ve tüm işleçler işlevlerle işlendiğinden, değiştiriciler de işleçler tarafından işlendiğinde kaybolur.pg_attribute.atttypmod

Çıktı değerlerine sahip olan veya kayıt kümelerini döndüren işlevler veya eşdeğeri returns table(...)de tanıma dahil olan değiştiricileri tutamaz. Ancak, masalar return setof <type>(muhtemelen kalıplaştığı için, aslında) koruyacaktır için tanımlanan herhangi değiştiricileri typeiçinde pg_attribute.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.