PL/PGSQL Funções Aninhadas
quarta-feira, outubro 29th, 2008Utilizando 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!




