G-7230: Avoid declaring global variables public.

Major

Reliability

Reason

You should always declare package-level data inside the package body. You can then define "get and set" methods (functions and procedures, respectively) in the package specification to provide controlled access to that data. By doing so you can guarantee data integrity, you can change your data structure implementation, and also track access to those data structures.

Data structures (scalar variables, collections, cursors) declared in the package specification (not within any specific program) can be referenced directly by any program running in a session with EXECUTE rights to the package.

Instead, declare all package-level data in the package body and provide "get and set" methods - a function to get the value and a procedure to set the value - in the package specification. Developers then can access the data using these methods - and will automatically follow all rules you set upon data modification.

Example (bad)

CREATE OR REPLACE PACKAGE employee_api AS
   co_min_increase CONSTANT types_up.sal_increase_type := 0.01;
   co_max_increase CONSTANT types_up.sal_increase_type := 0.5;
   g_salary_increase types_up.sal_increase_type := co_min_increase;

   PROCEDURE set_salary_increase (in_increase IN types_up.sal_increase_type);
   FUNCTION salary_increase RETURN types_up.sal_increase_type;
END employee_api;
/

CREATE OR REPLACE PACKAGE BODY employee_api AS
   PROCEDURE set_salary_increase (in_increase IN types_up.sal_increase_type) IS
   BEGIN
      g_salary_increase := GREATEST(LEAST(in_increase,co_max_increase)
                                   ,co_min_increase);
   END set_salary_increase;

   FUNCTION salary_increase RETURN types_up.sal_increase_type IS
   BEGIN
      RETURN g_salary_increase;
   END salary_increase;
END employee_api;
/

Example (good)

CREATE OR REPLACE PACKAGE employee_api AS
   PROCEDURE set_salary_increase (in_increase IN types_up.sal_increase_type);
   FUNCTION salary_increase RETURN types_up.sal_increase_type;
END employee_api;
/

CREATE OR REPLACE PACKAGE BODY employee_api AS
   g_salary_increase types_up.sal_increase_type(4,2);

   PROCEDURE init;

   PROCEDURE set_salary_increase (in_increase IN types_up.sal_increase_type) IS
   BEGIN
      g_salary_increase := GREATEST(LEAST(in_increase
                                         ,constants_up.max_salary_increase())
                                   ,constants_up.min_salary_increase());
   END set_salary_increase;

   FUNCTION salary_increase RETURN types_up.sal_increase_type IS
   BEGIN
      RETURN g_salary_increase;
   END salary_increase;

   PROCEDURE init
   IS
   BEGIN
      g_salary_increase := constants_up.min_salary_increase();
   END init;
BEGIN
   init();
END employee_api;
/