Detta är svårt att lösa, eftersom SQL kräver att man känner till returtypen vid samtalstid .
En plpgsql-funktion måste också ha en väldefinierad returtyp .
Om du väljer att returnera anonyma poster , får du vad du definierade:anonyma poster. Postgres vet inte vad som finns inuti. Därför är en kolumndefinitionslista obligatorisk för att dekomponera typen.
Det finns olika lösningar, beroende på exakta krav. Om du har något sätt att veta returtypen vid samtalstid , jag föreslår polymorfa typer som beskrivs i det sista kapitlet i detta svar ("Olika kompletta tabelltyper"):
Refaktorera en PL/pgSQL-funktion för att returnera utdata från olika SELECT-frågor
Men det täcker inte att lägga till ytterligare en kolumn till returtypen vid körning inuti funktionen . Det är bara inte möjligt. Jag skulle ompröva hela tillvägagångssättet .
När det gäller ditt nuvarande tillvägagångssätt är det närmaste jag kan komma på en tillfällig tabell (eller en markör), som du frågar efter i ett andra samtal inom en enskild transaktion .
Du har ett par andra problem i din kod . Se anteckningarna nedan.
Proof of concept
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;
Samtalet måste vara i en enda transaktion. Du kan behöva starta en explicit transaktion, beroende på din klient.
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-fiol.
Alternativt kan du låta det tillfälliga bordet leva under hela sessionen. Var dock försiktig med att namnge kollisioner med upprepade samtal.
Anteckningar
-
Använd parameternamn istället för det föråldrade
ALIAS
kommando. -
För att faktiskt "ställa in som standard" till det aktuella schemat, använd den enklare frågan jag visar. Använder
regclass
gör susen automatiskt. Detaljer:- Tabellnamn som en PostgreSQL-funktionsparameter
Dessutom undviker detta också syntaxfel och eventuell SQL-injektion från icke-standardiserade (eller uppsåtligt felaktiga) tabellnamn i din ursprungliga kod.
-
Koden i din
ELSE
klausul skulle inte fungera alls. -
TABLE tbl;
är i princip förkortning förSELECT * FROM tbl;
. -
Detaljer om
format()
i manualen.