quinta-feira, 17 de novembro de 2011

Objetos dependentes

A alteração de um objeto (tabela, visão, procedure, ...) pode afetar outros objetos e obrigar, no mínimo , a recompilá-los. Assim, antes de iniciar a alteração é útil verificar quais outros objetos poderão ser afetados. Ou talvez muito antes disto, quando estiver avaliando custos e riscos de alterar o esquema para suportar um novo requisito. Para tanto, basta uma consulta a visão DBA_DEPENDENCIES (ou às equivalentes ALL_DEPENDENCIES  e USER_DEPENDENCIES).


SELECT 
FROM dba_dependencies 
WHERE referenced_owner = 'HR'
  AND referenced_name = 'JOB_HISTORY';

Esta consulta retorna uma única linha: a procedure ADD_JOB_HISTORY. Examinando o código fonte desta procedure, nota-se que há um comando de INSERT na tabela. Parece-me razoável que, se você incluir uma coluna na tabela, a procedure seja alteradap ara incluir um valor nesta nova coluna. E se por acaso remover uma coluna da tabela, a procedure obrigatoriamente terá que ser alterada.

Agora um passo a mais: como saber quais objetos a procedure pode afetar? Uma solução simples seria aplicar novamente a mesma consulta, apenas usando o nome da procedure. Para um esquema simples, até pode ser, mas num esquema complexo, com centenas de objetos, seria um esforço manual desnecessário e sujeito a erros. Muito mais conveniente e elegante é usar a consulta abaixo e deixar que o Oracle resolva este problema. 

SELECT *
FROM dba_dependencies
START WITH referenced_owner = 'HR
       AND referenced_name  = 'JOB_HISTORY'
CONNECT BY prior owner = referenced_owner
       AND prior name  = referenced_name; 


A consulta retorna duas linhas: a procedure ADD_JOB_HISTORY e a trigger UPDATE_JOB_HISTORY, que tem uma chamada para a procedure. 

Por tratar-se de uma consulta hierárquica, se houver um ciclo no grafo de dependências, o Oracle retornará um erro. Neste caso, é possível incluir um controle para limitar a recursão. Por exemplo:

SELECT *
FROM dba_dependencies
START WITH referenced_owner = 'SYS
       AND referenced_name  = 'OBJ$'
CONNECT BY prior owner = referenced_owner
       AND prior name  = referenced_name
       AND level < 4;


O valor 4 é o limite para este caso específico (tabela SYS.OBJ$). Se aumentar para 5, fecha-se um ciclo no grafo e um erro é retornado. Outros objetos podem permitir outros limites.

Um comentário: