Schema temporaneo per connessione?


8

Sto cercando di migrare i miei test unitari da H2 a Postgresql.

Attualmente, H2 mi fornisce uno schema in memoria in modo tale che ogni connessione si associ a uno schema univoco, crei le tabelle, esegua il test e rilasci lo schema. La creazione e la distruzione dello schema sono gestite automaticamente da H2.

I test unitari vengono eseguiti contemporaneamente.

Qual è il modo migliore per farlo in Postgresql? In particolare,

  1. Come posso ottenere uno schema univoco per connessione?
    • Il framework di test dovrebbe generare nomi univoci o esiste un meccanismo integrato per farlo?
  2. Come posso accertarmi che lo schema venga eliminato quando viene interrotta la connessione?
    • Non voglio finire con schemi penzolanti quando i test unitari vengono uccisi.
  3. Quale approccio produrrà le massime prestazioni?
    • Devo creare / eliminare decine di schemi al secondo.

AGGIORNAMENTO : Ho trovato una risposta correlata qui ma non riesce a eliminare gli schemi nel caso in cui il processo che esegue i test unitari venga interrotto.

Risposte:


13

pg_temp è un alias per lo schema temporaneo della sessione corrente.

Se lo fai SET search_path TO pg_tempprima di eseguire i test, tutto dovrebbe funzionare (purché nulla faccia riferimento esplicitamente a uno schema).

Se non si desidera modificare affatto lo script, impostare search_pathl'utente che i test accedono come:

> ALTER ROLE testuser SET search_path = pg_temp;

Quindi tutto ciò che l'utente crea sarà in pg_temp se non specificato esplicitamente.

Ecco un esempio da psql, che mostra lo schema effettivo (per questa connessione) che l'alias risolve in:

> SET search_path TO pg_temp;
SET
> create table test();
CREATE TABLE
> \dt test
          List of relations
  Schema   | Name | Type  |  Owner
-----------+------+-------+----------
 pg_temp_4 | test | table | postgres
(1 row)

E, come prevedibile, quello schema è diverso per ogni connessione simultanea e scompare dopo la chiusura della connessione.

Si noti che questo funziona anche per le funzioni, anche se sarà necessario fare esplicito riferimento allo schema pg_temp quando le si chiama.


Ma pg_tempun singolo schema è giusto? Quindi, quando eseguo test unitari simultanei, non si ostruiscono l'un l'altro le tabelle / i dati?
Gili,

1
No. È un alias per lo schema temporaneo della sessione corrente. Aggiornerò la risposta con un esempio.
hbn,

Tieni presente che se chiudi e apri una connessione, potresti finire con lo stesso schema temporaneo, ma sarà stato svuotato. Apri 2 contemporaneamente per vedere quelli diversi assegnati. Non puoi vedere lo schema temporaneo di un'altra sessione se non sei un superutente.
hbn,

Certo, ho visto un tuo commento che ti chiedeva quando impostarlo. Comunque - è impostato per sessione se fai semplicemente un SET search_path; utilizzare SET LOCAL search_pathper impostare per sottotransazione o, se lo si desidera, è possibile impostare a livello di utente con ALTER USER mytestuser SET search_path = 'pg_temp'o a livello di database conALTER DATABASE mytestdb SET search_path = 'pg_temp'
hbn

Per curiosità, c'è un modo per farlo funzionare per funzioni senza un riferimento esplicito allo schema? O è impossibile per lo pg_tempschema?
Gili,

3

È possibile ottenere il nome dello schema temporaneo corrente (dopo aver creato la prima tabella temporanea) come indicato nel collegamento aggiunto:

SELECT nspname
FROM   pg_namespace
WHERE  oid = pg_my_temp_schema();

Ma il tuo piano attuale non avrebbe ancora molto senso. Per creare tabelle nello schema temporaneo corrente, basta creare tabelle temporanee. È tutto. Per impostazione predefinita, search_pathviene definito in modo che le tabelle temporanee siano visibili per prime. Non è mai necessario classificare le tabelle temporanee. Non dovresti mai dover affrontare lo schema temporaneo corrente direttamente in alcun modo - questo è un dettaglio di implementazione.


D'accordo, è un hack, ma potrebbe essere significativamente più semplice della parametrizzazione del codice di creazione per consentire la creazione di tabelle temporanee.
hbn,

Un buon punto, ad eccezione di quanto menzionato da @hbn, voglio che i test unitari e il codice di produzione eseguano lo stesso script SQL. Il primo dovrebbe essere eseguito su uno schema temporaneo mentre il secondo no.
Gili,

@hbn, per curiosità come sarebbe il codice di creazione parametrizzato? Sto usando flywaydb.org ed esegue solo semplici file SQL (senza variabili). Probabilmente non voglio percorrere questa strada. Sono solo curioso di cosa sia coinvolto.
Gili,

Non ho mai usato flywaydb. A un livello molto semplice, potresti usare un linguaggio di template del testo (ad esempio Jinja2 in Python) per preelaborare i tuoi script di creazione, aggiungendo facoltativamente un "temporaneo" quando crei una tabella. Se stai creando esplicitamente funzioni, l'hack dello schema get-the-temporary è probabilmente inevitabile in quanto (per quanto ne so), non puoi creare direttamente una funzione temporanea.
hbn,

@hbn,: If you're explicitly sequences ...penso che il tuo ultimo commento contenesse un refuso. Cosa intendevi dire tra explicitlye sequences?
Gili,

1

I tuoi test comportano transazioni? DDL è transazionale in PostgreSQL, quindi se si creano lo schema e le tabelle, quindi si eseguono i test, il tutto all'interno di una singola transazione che viene quindi ripristinata, lo schema non viene mai effettivamente impegnato e visibile ad altre sessioni.

Dovresti comunque usare un nome probabilmente univoco per il tuo schema (forse includere nome host e PID), poiché CREATE SCHEMAfallirà immediatamente se esiste già uno schema con nome identico e si bloccherà se un'altra sessione ha creato uno schema con nome identico in una transazione non impegnata.

Un'alternativa potrebbe essere solo quella di utilizzare tabelle temporanee, se sei in grado di modificare gli script di creazione del database per farlo.


Bel trucco, ma nel mio caso non funzionerebbe perché un singolo test funziona su più transazioni. Ogni metodo di test è un client Web che genera più transazioni sul lato server. Ad esempio, crea, interroga ed elimina un utente. Ogni chiamata è una richiesta HTTP separata e viene eseguita nella propria transazione.
Gili,

Abbastanza giusto, il mio approccio era molto limitato.
hbn,

@Gili: Nota che questa tecnica di non commettere mai CREATE SCHEMAè l'unica che può garantire la loro scomparsa quando il test unitario viene ucciso.
Daniel Vérité,

0

Ho appena avuto un'idea.

Postgresql garantisce che una sessione non può vedere le tabelle temporanee di un'altra. Immagino che questo significhi che quando crei una tabella temporanea, crea uno schema temporaneo. Quindi forse potrei fare quanto segue:

  1. Crea una tabella (fittizia) temporanea e cerca il suo schema.
  2. Utilizzare questo schema per il test (creare le tabelle, eseguire il test).
  3. Quando la connessione viene chiusa, Postgresql eliminerà lo schema.

Non mi piace fare affidamento sui dettagli di implementazione, ma in questo caso sembra abbastanza sicuro.

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.