Il problema non era la sintassi, perché la sintassi funzionava perfettamente con flyway o direttamente nella CLI di PostgreSQL. Il problema era con Hibernate, in particolare con l'analisi del file di importazione. Il modo in cui Hibernate funziona è che esegue ogni espressione dai file individualmente, non l'intero contenuto come una singola espressione. Ho provato a mettere tutte le definizioni delle funzioni in una riga e ha funzionato, ma non era leggibile. Quindi ho scoperto che esiste una configurazione per Hibernate per dirgli che le espressioni possono essere a più righe, ma il $$
delimitatore non era ancora riconosciuto quando utilizzato in multilinea.
Quindi la soluzione era definire il comando con '
delimitatore e quindi sfuggire alle virgolette singole dove necessario con un ulteriore '
.
La soluzione è impostare spring.jpa.properties.hibernate.hbm2ddl.import_files_sql_extractor
per usare org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
. MultipleLinesSqlCommandExtractor estrae l'espressione SQL da più righe e si interrompe quando è presente un punto e virgola. Questa è la fine dell'espressione. Avvolgendo il corpo della funzione in una stringa tra virgolette singole, Hibernate tratterà tale avvolgimento come una singola riga.
data.sql
CREATE OR REPLACE FUNCTION insert_timeout_configuration() RETURNS bigint AS '
DECLARE created_id bigint;
BEGIN
INSERT INTO timeout_configuration (id, version, timeout)
VALUES (nextval(''my_sequence''), 0, 300)
RETURNING id INTO created_id;
return created_id;
END;
' language plpgsql;
CREATE OR REPLACE FUNCTION insert_url_configuration() RETURNS bigint AS '
DECLARE created_id bigint;
BEGIN
INSERT INTO url_configuration (id, version, my_url)
VALUES (nextval(''my_sequence''), 0,''http://localhost:8080/'')
RETURNING id INTO created_id;
return created_id;
END;
' language plpgsql;
DO '
INSERT INTO global_configuration(id, version, name, timeout_configuration_id, url_configuration_id)
VALUES (nextval(''my_sequence''), 0, ''My global config'', insert_timeout_configuration(), insert_url_configuration());
-- do some other code
END
';
drop function insert_timeout_configuration();
drop function insert_url_configuration();
Devo sempre tenere a mente di evitare le virgolette singole nelle espressioni, ma ora posso avere un file seme più leggibile dall'uomo.