PL/PGSQL Funções Aninhadas

Posted on out 29, 2008 under Tutoriais | No Comment

Utilizando a versão 8.2.7 do Postgresql verifiquei a possibilidade de criar funções aninhadas.
Veja o exemplo:

CREATE OR REPLACE FUNCTION testNestedFunction() RETURNS  REAL as
$$
<>
DECLARE
v_test REAL;
r REAL;
BEGIN
   CREATE OR REPLACE FUNCTION addTest(a REAL,b REAL) RETURNS REAL AS
   $BODY_ADDTEST$
	DECLARE
		r REAL;
	BEGIN
		r := a + b;
	RETURN r;
   END;
   $BODY_ADDTEST$language plpgsql;

   r := addTest(1,1);
   RAISE NOTICE 'addTest = %',r;

   r := addTest(2,2);
   RAISE NOTICE 'addTest = %',r;

   RETURN r;
END global;
$$ LANGUAGE 'plpgsql';

Na função acima criei uma função aninhada chamada addTest(REAL,REAL) recebendo como parâmetro dois valores do tipo real, com os quais é efetuado uma soma e retornado o resultado. Executando a função temos o seguinte resultado:

SELECT testNestedFunction();

NOTA:  addTest = 2
NOTA:  addTest = 4

Tempo total de execução da consulta: 18 ms.
1 registros recuperados.

Como pode ser visto foi realizado duas chamadas a função aninhada addTest() passando diferentes parâmetros.

O interessante é que o Postgresql cria duas funções: testNestedFunction() e addTest(REAL,REAL). E não somente uma função aninhada, isso favorece aos bugs, vamos simular um então.

Vamos deletar a função addTest(REAL,REAL) e executar novamente.

DROP FUNCTION addtest(real, real);
SELECT testNestedFunction();

ERRO:  cache lookup failed for function 1906343
CONTEXT:  PL/pgSQL function "testnestedfunction" line 16 at assignment

********** Erro **********

ERRO: cache lookup failed for function 1906343
SQL state: XX000
Contexto: PL/pgSQL function "testnestedfunction" line 16 at assignment

O comando DROP FUNCTION addTest(REAL,REAL) não verificou que a função testnestedfunction() é depende daquela para sua execução, procurei na documentação uma maneira de declarar a dependência mas não encontrei. Outro detalhe interessante é que a função addTest() não existe até a primeira execução, ou seja, quando o comando é executado SELECT testnestedfunction() pela primeira vez a função addTest() é criada. Então quando deletamos a função addTest() e executamos novamente o comando SELECT testnestedfunction(), a função addTest() não é criada novamente.

Funções aninhadas são interessantes para melhorar a leitura do código e prover reutilização de código. O problema é se por acidente algum DBA deletar a função aninhada como mostrado acima. Irá causar um bug difícil de resolver. Pois, a resposta do erro é pouco intuitiva não informando claramente a função que não foi encontrada.

Criar funções separadas é uma outra solução invés de criar uma função aninhada. Mas, o problema que dificulta a leitura e entendimento do código.

Carpe Diem!

Leave a Reply