Errore: funzione set_valued chiamata nel contesto che non può accettare un set. Di cosa si tratta?


11

Uso Postgresql 9.1, con Ubuntu 12.04.

Ispirato dalla risposta di Craig alla mia domanda concatenazione di tipo setof o registrare setof ho pensato di andare bene con l'utilizzo return query, setof recorde un generatore di serie in questa funzione plpgsql:

create or replace function compute_all_pair_by_craig(id_obj bigint)
    returns setof record as $$
begin
    return query select o.id, generate_series(0,o.value) from m_obj as o;     
end;
$$    language plpgsql;

Durante l'esecuzione viene visualizzato l'errore:

ERROR: set_valued function called in context that cannot accept a set

Che c'è ? Contrariamente a Craig, dico alla funzione di tornare setof record.

Posso ottenere qualcosa che funzioni facendo esattamente come Craig, cioè definendo un tipo create type pair_id_value as (idx bigint, value integer)e facendo in modo che la mia funzione plpgsql restituisca un setof of pair_id_valueanziché un setof record.

Ma anche con questa soluzione funzionante, ancora non capisco perché select id, generate_series(0,13)da solo verrà restituito un risultato in due colonne ... e al contrario chiamando la funzione (restituisce setof pair_id_value) con return query select id, generate_series(0,my_obj.value) from my_objverrà restituito un risultato in una sola colonna il cui campo appare come questo "(123123,0)" "(123123,1)" "(123123,2)" (3 file) che sono tuple ovviamente.

È un caso in cui una / tabella temporanea deve / deve essere creata?


Questo non può essere il testo esatto della funzione che stai eseguendo perché non viene compilato; c'è un punto BEGINe virgola in eccesso dopo e uno mancante dopo il RETURN QUERY. Dopo aver corretto quegli errori, confermo l'errore al ritorno record; spiegherà in risposta.
Craig Ringer,

@CraigRinger Ho rimesso a posto il punto e virgola.
Stephane Rolland,

Risposte:


7

Il messaggio di errore non è molto utile:

regress=> SELECT * FROM  compute_all_pair_by_craig(100);
ERROR:  a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM  compute_all_pair_by_craig(100);

ma se riformuli la query per chiamarla come una corretta funzione di restituzione del set, vedrai il vero problema:

regress=> SELECT * FROM compute_all_pair_by_craig(100);
ERROR:  a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM compute_all_pair_by_craig(100);

Se si utilizza SETOF RECORDsenza un OUTelenco di parametri, è necessario specificare i risultati nell'istruzione chiamante, ad esempio:

regress=> SELECT * FROM compute_all_pair_by_craig(100) theresult(a integer, b integer);

Tuttavia, è molto meglio usare RETURNS TABLEo OUTparametri. Con la precedente sintassi la tua funzione sarebbe:

create or replace function compute_all_pair_by_craig(id_obj bigint)
    returns table(a integer, b integer) as $$
begin
    return query select o.id, generate_series(0,o.value) from m_obj as o;     
end;
$$ language plpgsql;

È richiamabile nel contesto dell'elenco SELECT e può essere utilizzato senza creare un tipo in modo esplicito o senza specificare la struttura dei risultati nel sito della chiamata.


Per quanto riguarda la seconda metà della domanda, ciò che sta accadendo è che il primo caso specifica due colonne separate in un elenco SELECT, mentre la seconda restituisce un singolo composito. In realtà non ha a che fare con il modo in cui stai restituendo il risultato, ma come stai invocando la funzione. Se creiamo la funzione di esempio:

CREATE OR REPLACE FUNCTION twocols() RETURNS TABLE(a integer, b integer) 
AS $$ SELECT x, x FROM generate_series(1,5) x; $$ LANGUAGE sql;

Vedrai la differenza nei due modi per chiamare una funzione di restituzione di set: SELECTnell'elenco, un'estensione non standard specifica di PostgreSQL con un comportamento bizzarro:

regress=> SELECT twocols();
 twocols 
---------
 (1,1)
 (2,2)
 (3,3)
 (4,4)
 (5,5)
(5 rows)

o come tabella nel modo più standard:

regress=> SELECT * FROM twocols();
 a | b 
---+---
 1 | 1
 2 | 2
 3 | 3
 4 | 4
 5 | 5
(5 rows)

Appena testato, funziona perfettamente. E mi piace questa sintassi con returns table.
Stephane Rolland,

@StephaneRolland Aggiornato con spiegazione anche dell'ultima parte della domanda.
Craig Ringer,

grazie per il supporto. Ora è molto più chiaro.
Stephane Rolland,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.