Il problema è che FlameRobin ha bisogno di sapere quando un'istruzione finisce e inizia l'istruzione successiva. Per impostazione predefinita usa il punto e virgola (;
) per questo. Tuttavia uno EXECUTE BLOCK
è essenzialmente una stored procedure che non è archiviata nel database, quindi contiene il codice PSQL che utilizza anche il punto e virgola come separatore di istruzioni.
La conseguenza di ciò è che si verificano errori di sintassi poiché FlameRobin invia istruzioni incomplete al server (ovvero: invia una dichiarazione dopo ogni ;
che incontra).
È necessario istruire FlameRobin per utilizzare un terminatore di istruzioni diverso utilizzando SET TERM
. Anche altri strumenti di query di Firebird (ad esempio isql) richiedono questo, ma in realtà non fa parte della sintassi stessa di Firebird!
quindi è necessario eseguire il codice come:
-- Instruct flamerobin to use # as the terminator
SET TERM #;
EXECUTE BLOCK
AS
DECLARE customerID INT = 1234;
BEGIN
SELECT * FROM customers WHERE customerid = :customerID;
END#
-- Restore terminator to ;
SET TERM ;#
Tuttavia questo modo sarà ancora generato un errore, perché questa query non è valida per PSQL: Un SELECT
in un blocco PSQL richiede una clausola INTO
per mappare le colonne alle variabili. E per ottenere i valori fuori dalla EXECUTE BLOCK
tornato a FlameRobin è inoltre necessario specificare una clausola di RETURNS
come descritto nella documentation of EXECUTE BLOCK
:
-- Instruct flamerobin to use # as the terminator
SET TERM #;
EXECUTE BLOCK
RETURNS (col1 INTEGER, col2 VARCHAR(100))
AS
DECLARE customerID INT = 1234;
BEGIN
SELECT col1, col2 FROM customers WHERE customerid = :customerID INTO :col1, :col2;
SUSPEND;
END#
-- Restore terminator to ;
SET TERM ;#
Per quanto ne so il SUSPEND
non è tecnicamente necessario qui, ma FlameRobin non lo farà recupera la riga restituita se non è inclusa.
Tuttavia, quanto sopra non funzionerà se la selezione produce più righe. Per questo è necessario utilizzare FOR SELECT ... DO
combinato con un SUSPEND
:
-- Instruct flamerobin to use # as the terminator
SET TERM #;
EXECUTE BLOCK
RETURNS (col1 INTEGER, col2 VARCHAR(100))
AS
DECLARE customerID INT = 1234;
BEGIN
FOR SELECT col1, col2 FROM customers WHERE customerid = :customerID INTO :col1, :col2
DO
SUSPEND;
END#
-- Restore terminator to ;
SET TERM ;#
Il SUSPEND
qui restituisce la riga e aspetta fino a quando il chiamante ha recuperato quella riga e poi prosegue con il ciclo FOR
. In questo modo itererà sui risultati.
IMHO questo troppo sforzo per la parametrizzazione. Potresti considerare semplicemente di non parametrizzare quando usi flamerobin, o usare uno strumento che supporti la richiesta di valori di parametro per i normali segnaposti dei parametri di Firebird (ma per essere onesti non sono sicuro che ce ne siano).
I tuoi campioni funzionano perfettamente. Grazie per la risposta.È davvero troppo sforzo implementarlo, dovrei cambiare molte domande. Ma almeno so di conoscere la porta sbagliata. –