Les packages peuvent être invalidés pour plusieurs raisons :

  • lorsque la spécification d'un package (une "spéc" de package correspond à une interface en java) dont ils dépendent change ou a été supprimée
  • lorsque la spécification du package dépend d'une table qui a été modifiée ou supprimée
  • lorsqu'il contient des variables globales de package
  • lorsqu'il contient des exceptions au niveau du package

Il est donc dangereux en production de modifier des spécifications de package, à moins de pouvoir recompiler en masse tous les packages impliqués. Cela peut suffire pour les 2 premières causes d'invalidation du package. Mais les deux dernières causes sont plus problématiques.

Voici les spécs de notre package avec notamment une constante, une variable globale et une exception.

CREATE OR REPLACE PACKAGE SCHEMA_REF.MON_PACKAGE AS
--
RAD_TO_DEG    CONSTANT NUMBER := 180 / ( ATAN(1) * 4 );
MA_VARIABLE_GLOBALE      NUMBER := 0;
EXCEPTION e_mon_exception;
--
FUNCTION MA_FONCTION_RIGHT(vString VARCHAR2, vLength NUMBER) RETURN VARCHAR2;
PROCEDURE MA_PROC();
END;

Cette spécification de package provoquera immanquablement l'erreur ORA-04061 car les variables et constantes au niveau package font partie de l'ETAT du package. Si cet état change, comme par exemple la modification de la valeur de MA_VARIABLE_GLOBALE par une procédure ou fonction, Oracle considère que les spécifications du package sont changées! Ce qui est normal car si 2 utilisateurs créent 2 sessions en parallèle : on a une concurrence potentielle au niveau des variables d'état du package. Oracle met alors le package en statut invalide.
Le problème est le même pour les exceptions qui sont en fait des objets potentiellement modifiables au cours de la session d'un utilisateur, provoquant ainsi l'invalidation d'un package.

Pour mieux structurer un projet PL/SQL, la seule option est de placer toutes les constantes dans un package ne contenant que des spécifications de constantes. Il est impossible d'isoler et regrouper les exceptions dans un package de spécifications, ni dans l'entête d'un package : toutes les exceptions doivent être gérées à l'intérieur des fonctions et procédures, ce qui représente un travail d'uniformisation et normalisation important. C'est un point faible pour maintenir convenablement des applications PL/SQL.

Ces deux articles expliquent bien le problème (mis à part qu'il ne parlent pas du cas des EXCEPTION) :

http://kr.forums.oracle.com/forums/thread.jspa?threadID=903490

http://oraclequirks.blogspot.com/2007/03/ora-04061-existing-state-of-package-has.html

Ce dernier article explique comment recompiler en masse ou programmatiquement des objets dans Oracle :

http://www.oracle-base.com/articles/misc/RecompilingInvalidSchemaObjects.php