A documentação a seguir descreve como ver o refcursor retornado de uma função, aqui , assim:
CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS '
BEGIN
OPEN $1 FOR SELECT col FROM test;
RETURN $1;
END;
' LANGUAGE plpgsql;
BEGIN;
SELECT reffunc('funccursor');
FETCH ALL IN funccursor;
COMMIT;
Isso funciona para mim. Porém, se eu quiser manter os resultados na minha tela, tenho que manter a transação aberta. Quando executo o COMMIT, meu conjunto de resultados é descartado. Quando executo FETCH e COMMIT ao mesmo tempo, o primeiro conjunto de resultados é descartado.
Existe uma maneira de confirmar a transação, mas manter o conjunto de resultados? A versão do PgAdmin é 1.18.1.
Quando um cursor é definido no nível SQL com DECLARE , existe uma opção
WITH HOLD
que faz com que ele continue existindo após o commit da transação atual. Citando o documento:Por outro lado, um refcursor aberto por uma função plpgsql é fechado ao final da transação. Citando o documento plpgsql :
Para criar um cursor em uma função plpgsql que pode ser usada fora de sua transação "pai", é apenas uma questão de sintaxe. Você deseja a implementação SQL de um cursor, não a variante plpgsql. Para isso,
EXECUTE
deve ser usado.Como exemplo, aqui está o esqueleto de uma função semelhante à sua, mas usando cursores de nível SQL que sobrevivem à transação:
Demonstração:
pgAdmin é apenas uma GUI. Em grande parte irrelevante para esta questão. Acontece que uma ou mais sessões são vinculadas a uma janela do editor SQL e terminam quando a janela é fechada.
Se você deseja manter a transação aberta, apenas não
COMMIT
(ouROLLBACK
) ainda.Se você realmente deseja "manter" o conjunto de resultados, escreva-o em uma
table
- possivelmente uma tabelaTEMPORARY
ouUNLOGGED
se você não precisar persistir permanentemente. Uma tabela temporária vive e morre com a sessão por padrão.SQL e PL/pgSQL são bastante rígidos com seu sistema de tipos e algumas coisas que parecem possíveis não foram implementadas (ainda). Mas o que você está tentando fazer provavelmente pode ser resolvido sem cursores. Se você precisar fornecer um nome de tabela para uma função dinamicamente, use um tipo de retorno polimórfico encadeado a um parâmetro de entrada:
Ligar:
Este formulário é automaticamente seguro contra injeção de SQL, pois
pg_typeof()
retorna umregtype
valor que é escapado automaticamente (se necessário) quando é convertido automaticamentetext
durante a concatenação de strings.Eu escrevi uma resposta intimamente relacionada lidando com tipos polimórficos ontem. Tem mais explicações e links:
Inserir valores de uma variável de registro em uma tabela
Normalmente , um simples e simples
SELECT
faria o trabalho. É uma condição rara que os nomes das tabelas sejam fornecidos dinamicamente.