Automatische Konvertierung anonymer Datensätze, die von einer UDF zurückgegeben wurden, in einen bekannten Tabellentyp

8

Proprietärer Code (den wir nicht ändern können) enthält eine Reihe von benutzerdefinierten Funktionen des Typs:

create or replace function f() returns record as $$ ... $$

was wir folgendermaßen nennen (zum Beispiel):

SELECT status, log FROM f() as (status boolean, log text);

(status boolean, log text)ist ein Zeilentyp einer Tabelle T. Ist es möglich, den record(oder den setof recordRückgabetyp) automatisch in den TZeilentyp zu konvertieren, ohne die Attribute aufzulisten? Was ich suche, ist von der Art:

SELECT * FROM f() as T%rowtype
Arthur
quelle
1
Wenn die Funktion keine Argumente enthält, können Sie diese in eine Ansicht einschließen.
a_horse_with_no_name
1
Oder Sie können diese genauso gut in Funktionen in einem anderen Schema, aber einer identischen Signatur einschließen. Oder wenn Sie die Quelle kennen, erstellen Sie Ihre eigenen, verwendbaren Sätze.
Dekso
Technisch gesehen ist das, was Sie vorschlagen, nicht möglich.
Dekso
@dezso: Ich habe einen Weg gefunden, wie Funktionen eine einzelne Zeile zurückgeben können.
Erwin Brandstetter
@ErwinBrandstetter Ja, und es ist so einfach wie es nur geht, aber immer noch eine Verpackung :). Die Zuordnung zu und von Datensatz- / Zeilenvariablen ist übrigens voller Überraschungen.
Dekso

Antworten:

8

Da ist ein Weg.

Gegeben eine Tabelle tund eine Funktion f(), die einen anonymen Datensatz zurückgibt, der diesem Tabellentyp entspricht:

CREATE TABLE t (id int, d date);

Sie können nicht nur den anonymen Datensatz werfen, da eine Spalte Definitionsliste ist erforderlich für

SELECT * FROM f()

Zitieren des Handbuchs zum Befehl SELECT :

Wenn die Funktion so definiert wurde, dass sie den Datensatzdatentyp zurückgibt, muss ein Alias ​​oder das Schlüsselwort ASvorhanden sein, gefolgt von einer Spaltendefinitionsliste im Formular ...

Meine kühne Betonung.

Während all diese Abfragen funktionieren:

SELECT '(1,2013-11-11)'::t;
SELECT ('(1,2013-11-11)'::t).*;
SELECT f();                      -- returning anonymous record
SELECT * FROM f() AS f(id int, d date);

Beides nicht:

SELECT * FROM f();
SELECT * FROM f()::t;

Letzteres wirft eine Ausnahme auf:

FEHLER: Typdatensatz kann nicht in t umgewandelt werden

Sie können die SELECTListe mit der Spaltendefinition in eine VIEWoder eine Funktion wie @a_horse und @deszo einschließen . Das würde gut funktionieren:

CREATE OR REPLACE VIEW v1 AS
SELECT * FROM f() AS f(id int, d date);

Aber das würde Ihre Frage nicht beantworten:

Konvertieren Sie den Datensatz (oder den Satz des Datensatzrückgabetyps) in den TZeilentyp, ohne die Attribute aufzulisten.

Lösung für einzelne Reihe

Während eine Besetzung fehlschlägt, funktioniert eine Zuweisung in plpgsql .

CREATE OR REPLACE function f1(OUT rec t) AS
$func$
BEGIN
rec := f();   -- assignment succeeds where cast failed (!)
END
$func$ LANGUAGE plpgsql;

Anruf:

SELECT * FROM f1();

Während Sie mit diesem Muster auch eine Set-Return-Funktion schreiben können, habe ich keinen Weg gefunden, SELECTvon einer Set-Return-Funktion zu kommen, ohne eine Spaltendefinitionsliste anzugeben ...

-> SQLfiddle

Erwin Brandstetter
quelle
Vielen Dank für die Antwort. Ihre Lösung zum "Umwandeln" der Signatur der UDF, sodass ein Tabellen- (Zeilen-) Typ anstelle des Datensatztyps zurückgesetzt wird, funktioniert. Außerdem muss ich sagen, dass ich diesen Ansatz erfolgreich verwendet habe, um auch eine Reihe von Datensätzen zurückzugeben. In Ihrer Antwort muss man die Zeile CREATE OR REPLACE function f1(OUT rec t) AS table typedurch ersetzen CREATE OR REPLACE function f1() returns setof T as....
Arthur
Die gestellte Frage ist eine Vereinfachung des ursprünglichen Problems, das ich tatsächlich habe. Mein ursprüngliches Problem ist, dass die Funktion einen Parameter vom Typ regclassals Eingabe verwendet und einen setofDatensatz zurückgibt (den Zeilentyp der entsprechenden Eingabe-Regclass). In diesem Fall kann ich keine Wrapper-Funktion erstellen, da der Rückgabetyp nur zur Ausführungszeit bekannt ist, oder?
Arthur
@arthur: Das ist kniffliges Zeug. Ich schlage vor, Sie erstellen eine neue Frage mit allen erforderlichen Details. Sie können immer auf diesen für den Kontext verweisen. Ich denke, ich habe eine Lösung dafür ...
Erwin Brandstetter
@arthur: Es würde mich auch sehr interessieren, wie Sie es geschafft haben, aus einer Set-Return-Funktion SELECT auszuwählen, ohne eine Spaltendefinitionsliste anzugeben . Können Sie hier eine Antwort mit einem Codebeispiel posten?
Erwin Brandstetter
Ich habe keine Antwort darauf, wie man eine Auswahlabfrage für eine zurückkehrende Funktion durchführen kann setof record. Ich dachte über mögliche Problemumgehungen nach und erstellte das Einfügen von Werten aus einer Datensatzvariablen in eine Tabelle . Die Auswahl einer zurückgegebenen Funktion setof Tist relativ einfach. Aber ich gehe davon aus, dass Ihr Ausdruck set retuning functiontatsächlich bedeutet setof record returning function...
Arthur