Questa è un po' una verruca nell'implementazione di IF NOT EXISTS
per tabelle e schemi. Fondamentalmente, sono un tentativo di upsert e PostgreSQL non gestisce le condizioni di gara in modo pulito. È sicuro, ma brutto.
Se lo schema viene creato contemporaneamente in un'altra sessione ma non è ancora stato eseguito il commit, allora esiste e non esiste, a seconda di chi sei e del tuo aspetto. Non è possibile che altre transazioni "vedano" il nuovo schema nei cataloghi di sistema perché non è vincolato, quindi è inserito in pg_namespace
non è visibile ad altre transazioni. Quindi CREATE SCHEMA
/ CREATE TABLE
cerca di crearlo perché, per quanto lo riguarda, l'oggetto non esiste.
Tuttavia, ciò inserisce una riga in una tabella con un vincolo univoco. I vincoli univoci devono essere in grado di visualizzare le righe non vincolate per funzionare. Quindi l'inserimento si blocca (si interrompe) fino alla prima transazione che ha eseguito il CREATE
o esegue il commit o esegue il rollback. Se esegue il commit, la seconda transazione viene interrotta, poiché ha tentato di inserire una riga che viola un vincolo univoco. CREATE SCHEMA
non è abbastanza intelligente da prendere questo caso e riprovare.
Per correggere correttamente questo PostgreSQL sarebbe probabilmente necessario il blocco del predicato, in cui potrebbe bloccare il potenziale per una riga . Questo potrebbe essere aggiunto come parte del lavoro in corso per l'implementazione di UPSERT
.
Per questi comandi particolari, PostgreSQL potrebbe probabilmente eseguire una lettura sporca dei cataloghi di sistema, dove può vedere le modifiche non vincolate. Quindi potrebbe attendere il commit o il rollback della transazione non vincolata, ripetere la lettura sporca per vedere se qualcun altro è in attesa e riprovare. Ma questo avrebbe una condizione di competizione in cui qualcun altro potrebbe creare lo schema tra quando esegui la lettura per verificarlo e quando provi a crearlo.
Quindi IF NOT EXISTS
le varianti dovrebbero:
- Verifica se lo schema esiste; se lo fa, finisci senza fare nulla.
- Tentativo di creare la tabella
- Se la creazione non riesce a causa di un errore di vincolo univoco, riprova dall'inizio
- Se la creazione della tabella riesce, termina
Per quanto ne so nessuno l'ha implementato, oppure ci hanno provato e non è stato accettato. Ci sarebbero possibili problemi con la velocità di masterizzazione dell'ID transazione e così via con questo approccio.
Penso che questo sia una specie di bug, ma è un tipo di bug "sì, lo sappiamo", non un tipo di bug "faremo in modo di risolverlo". Sentiti libero di postare su pgsql-bugs a riguardo; perlomeno la documentazione dovrebbe menzionare questo avvertimento su IF NOT EXISTS
.
Non consiglio di eseguire DDL contemporaneamente in questo modo.