2010-01-20 6 views
6

Sto provando a scrivere una funzione in PL/PgSQL che deve funzionare con una tabella che riceve come parametro.ESEGUI ... L'istruzione USING in PL/pgSQL non funziona con il tipo di record?

Uso le istruzioni EXECUTE..INTO..USING all'interno della definizione di funzione per creare query dinamiche (è l'unico modo che conosco per farlo) ma ... ho riscontrato un problema con i tipi di dati RECORD.

Consideriamo l'esempio seguente (estremamente semplificato).

-- A table with some values. 
DROP TABLE IF EXISTS table1; 
CREATE TABLE table1 (
    code INT, 
    descr TEXT 
); 

INSERT INTO table1 VALUES ('1','a'); 
INSERT INTO table1 VALUES ('2','b'); 


-- The function code. 
DROP FUNCTION IF EXISTS foo (TEXT); 
CREATE FUNCTION foo (tbl_name TEXT) RETURNS VOID AS $$ 
DECLARE 
    r RECORD; 
    d TEXT; 
BEGIN 
    FOR r IN 
    EXECUTE 'SELECT * FROM ' || tbl_name 
    LOOP 
    --SELECT r.descr INTO d; --IT WORK 
    EXECUTE 'SELECT ($1)' || '.descr' INTO d USING r; --IT DOES NOT WORK 
    RAISE NOTICE '%', d; 
END LOOP; 

END; 
$$ LANGUAGE plpgsql STRICT; 

-- Call foo function on table1 
SELECT foo('table1'); 

E 'in uscita il seguente errore:

ERROR: could not identify column "descr" in record data type

anche se la sintassi che ho usato sembra valida a me. Non posso usare la selezione statica (commentato nell'esempio) perché voglio fare dinamicamente riferimento ai nomi delle colonne.

Quindi ... qualcuno sa cosa c'è che non va nel codice sopra?

risposta

7

È vero. Non è possibile utilizzare il record di tipo al di fuori dello spazio PL/pgSQL.

Il valore RECORD è valido solo in plpgsql.

si può fare

EXECUTE 'SELECT $1.descr' INTO d USING r::text::xx; 
+0

Il tuo codice non funziona. – Hobbes

+3

Ok, purtroppo il tuo codice funziona sostituendo 'xx' con 'table1'. Ma in questo modo non posso specificare dinamicamente il nome della tabella. Quindi la risposta corretta è: "ESEGUI 'SELEZIONA $ 1 :: testo :: table1.descr' IN d UTILIZZO r;". MOLTE GRAZIE! – Hobbes

3

$1 dovrebbe essere all'interno del ||, come || $1 || e dare spazi correttamente allora funzionerà.

BEGIN 

EXECUTE ' delete from ' || quote_ident($1) || ' where condition '; 

END; 
+0

Il problema in questione era come ottenere un campo RECORD in _reflective_ way (per nome, usando la concatenazione di stringhe). – botchniaque