Le funzioni di PostgreSQL sono transazionali?

È una funzione PostgreSQL come la seguente transazione automatica?

CREATE OR REPLACE FUNCTION refresh_materialized_view(name) RETURNS integer AS $BODY$ DECLARE _table_name ALIAS FOR $1; _entry materialized_views%ROWTYPE; _result INT; BEGIN EXECUTE 'TRUNCATE TABLE ' || _table_name; UPDATE materialized_views SET last_refresh = CURRENT_TIMESTAMP WHERE table_name = _table_name; RETURN 1; END $BODY$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER; 

In altre parole, se si verifica un errore durante l’esecuzione della funzione, le eventuali modifiche verranno annullate ? Se questo non è il comportamento predefinito, come posso rendere transazionale la funzione?

Le funzioni fanno parte della transazione da cui sono chiamate. I loro effetti vengono annullati se la transazione viene ripristinata. Il loro lavoro si impegna se la transazione viene commessa. Tutti i blocchi BEGIN ... EXCEPT all’interno della funzione funzionano come (e sotto la cappa usano) punti di salvataggio come le ROLLBACK TO SAVEPOINT SQL SAVEPOINT e ROLLBACK TO SAVEPOINT .

La funzione riesce o nella sua interezza o fallisce nella sua interezza, salvo BEGIN ... EXCEPT gestione degli errori. Se viene sollevato un errore all’interno della funzione e non viene gestito, la transazione che chiama la funzione viene interrotta. Le transazioni interrotte non possono essere confermate e, se provano a eseguire il commit, COMMIT viene considerato come ROLLBACK , come per qualsiasi altra transazione in errore. Osservare:

 regress=# BEGIN; BEGIN regress=# SELECT 1/0; ERROR: division by zero regress=# COMMIT; ROLLBACK 

Scopri come la transazione, che si trova nello stato di errore dovuto alla divisione zero, torna su COMMIT ?

Se chiami una funzione senza una transazione esplicita, le regole sono esattamente le stesse di ogni altra istruzione Pg:

 BEGIN; SELECT refresh_materialized_view(name); COMMIT; 

(dove COMMIT avrà esito negativo se SELECT generato un errore).

PostgreSQL non supporta (ancora) transazioni autonome in funzioni, in cui la procedura / funzione potrebbe eseguire il commit / rollback indipendentemente dalla transazione chiamante. Questo può essere simulato usando una nuova sessione tramite dblink .

MA , le cose che non sono transazionali o sono imperfettamente transazionali esistono in PostgreSQL. Se ha un comportamento non transazionale in un normale BEGIN; do stuff; COMMIT; BEGIN; do stuff; COMMIT; blocco, ha anche un comportamento non transazionale in una funzione. Ad esempio, nextval e setval , TRUNCATE , ecc.

Poiché la mia conoscenza di PostgreSQL è meno profonda di quella di Craig Ringer, cercherò di dare una risposta più breve: Sì.

Se si esegue una funzione che presenta un errore, nessuna delle operazioni avrà conseguenze sul database.

Inoltre, se si esegue una query in PgAdmin lo stesso.

Ad esempio, se esegui una query:

 update your_table yt set column1 = 10 where yt.id=20; select anything_that_do_not_exists; 

L’aggiornamento nella riga, id = 20 di your_table non verrà salvato nel database.

Nel livello di funzione, non è transnazionale. In altre parole, ogni istruzione nella funzione appartiene a una singola transazione, che è il valore predefinito del commit automatico db. Il commit automatico è true per impostazione predefinita. Ma comunque, devi chiamare la funzione usando

select schemaName.functionName()

La precedente istruzione ‘select schemaName.functionName ()’ è una singola transazione, denominiamo la transazione T1 e quindi tutte le istruzioni nella funzione appartengono alla transazione T1. In questo modo, la funzione è in una singola transazione.

https://www.postgresql.org/docs/current/static/plpgsql-structure.html

È importante non confondere l’uso di BEGIN / END per le istruzioni di raggruppamento in PL / pgSQL con i comandi SQL con il nome simile per il controllo delle transazioni. BEGIN / END di PL / pgSQL sono solo per il raggruppamento; non iniziano o terminano una transazione. Le funzioni e le procedure di trigger vengono sempre eseguite all’interno di una transazione stabilita da una query esterna: non possono avviare o eseguire il commit di quella transazione, poiché non vi sarebbe alcun contesto in cui eseguirle. Tuttavia, un blocco contenente una clausola EXCEPTION forma effettivamente una subtransaction che può essere ripristinato senza influenzare la transazione esterna. Per maggiori informazioni vedi Sezione 39.6.6.