To je těžké vyřešit, protože SQL vyžaduje znát návratový typ v době volání .
Funkce plpgsql také musí mít dobře definovaný návratový typ .
Pokud se rozhodnete vrátit anonymní záznamy , získáte to, co jste definovali:anonymní záznamy. Postgres neví, co je uvnitř. Proto je vyžadován seznam definic sloupců rozložit typ.
V závislosti na přesných požadavcích existují různá řešení. Pokud máte nějaký způsob, jak zjistit typ návratu v době hovoru , navrhuji polymorfní typy jak je uvedeno v poslední kapitole této odpovědi („Různé kompletní typy tabulek“):
Refaktorujte funkci PL/pgSQL, aby vrátila výstup různých SELECT dotazů
To však nezahrnuje přidání dalšího sloupce do návratového typu za běhu uvnitř funkce . To prostě není možné. Přehodnotil bych celý přístup .
Pokud jde o váš současný přístup, nejbližší věc, kterou mě napadá, by byla dočasná tabulka (nebo kurzor), kterou zadáte při druhém volání v rámci jediné transakce .
V kódu máte několik dalších problémů . Viz poznámky níže.
Důkaz konceptu
CREATE OR REPLACE FUNCTION f_tbl_plus_infowindow (_tbl regclass) -- regclass!
RETURNS void AS -- no direct return type
$func$
DECLARE
-- appending _tmp for temp table
_tmp text := quote_ident(_tbl::text || '_tmp');
BEGIN
-- Create temp table only for duration of transaction
EXECUTE format(
'CREATE TEMP TABLE %s ON COMMIT DROP AS TABLE %s LIMIT 0', _tmp, _tbl);
IF EXISTS (
SELECT 1
FROM pg_attribute a
WHERE a.attrelid = _tbl
AND a.attname = 'infowindow'
AND a.attisdropped = FALSE)
THEN
EXECUTE format('INSERT INTO %s SELECT * FROM %s', _tmp, _tbl);
ELSE
-- This is assuming a NOT NULL column named "id"!
EXECUTE format($x$
ALTER TABLE %1$s ADD COLUMN infowindow text;
INSERT INTO %1$s
SELECT *, 'ID: ' || id::text
FROM %2$s $x$
,_tmp, _tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
Hovor musí být v jedné transakci. V závislosti na vašem klientovi možná budete muset zahájit explicitní transakci.
BEGIN;
SELECT f_tbl_plus_infowindow ('tbl');
SELECT * FROM tbl_tmp; -- do something with the returned rows
ROLLBACK; -- or COMMIT, does not matter here
SQL Fiddle.
Alternativně můžete nechat dočasnou tabulku v provozu po dobu trvání relace. Dejte si však pozor na kolize pojmenování při opakovaných hovorech.
Poznámky
-
Používejte názvy parametrů namísto zastaralých
ALIAS
příkaz. -
Chcete-li skutečně "výchozí" aktuální schéma, použijte jednodušší dotaz, který zobrazím. Pomocí
regclass
dělá trik automaticky. Podrobnosti:- Název tabulky jako parametr funkce PostgreSQL
Kromě toho se tím také zabrání syntaktickým chybám a možnému vložení SQL z nestandardních (nebo škodlivě zdeformovaných) názvů tabulek ve vašem původním kódu.
-
Kód ve vašem
ELSE
klauzule by vůbec nefungovala. -
TABLE tbl;
je v podstatě zkratka proSELECT * FROM tbl;
. -
Podrobnosti o
format()
v návodu.