The package body contains all the code required to implement the package specification. As you saw in the previous section, some packages do not even need a body. A package body is required when any of the following conditions is true:
The package body can have declaration, execution, and exception sections, just like a normal PL/SQL block. The declaration section contains the definition of any objects in public packages (listed in the specification) and also the definition of any private objects (not listed in the specification).
The execution section is the "initialization section" of the package. It is executed when the package is instantiated (which usually occurs the very first time you reference a package element) and is described in more detail below. The exception section handles any exceptions raised in the initialization section.
A package body could have an empty declaration section but include an initialization section (see the last section in the chapter). A package body could also have a declaration section without an initialization section -- this is the format of most of the packages you will write.
If you declare a variable, exception, TYPE, or constant in the package specification, you do not also declare that same object in the body. If you declare it in the specification, it is available in the package body without an explicit, local declaration. This can be a hard thing to get used to; the object is not declared in the immediately visible scope of code, yet your package modules compile just fine. Remember: objects declared in the package specification are global data, so they should certainly be available within the body of that same package!
If you do try to redeclare an object within the body, you receive the following kind of error:
PLS-00371 at one more declaration for 'PETID_NU' is permitted in the declaration section
If you declare objects in the package body that are outside of all the modules, but not in the package specification, then those objects are global within the package but invisible outside of the package. The values held by package variables persist from one call to a package module to another call to the same or a different package module. Such objects are called package data, since their scope is the package. Any module may reference such an object without explicitly declaring it in the module itself.
The package specification and the package body of a package must be kept synchronized. Whenever you make a change in the package body to the name, parameter list, datatype, default value, or RETURN clause of a public object (to the portion of the object, in other words, that must be in the package specification), you must make that same change to the package specification. If the specifications for the objects do not match exactly, the body will fail to compile. In the PL/SQL language, the specification (like the proverbial customer) is always right.
Suppose that in my pet maintenance package, I decide to change the datatype of the pet_id_in parameter in next_pet_shot from the subtype for the primary key to simply NUMBER. My package body then looks like this:
PACKAGE BODY pets_inc IS ... FUNCTION next_pet_shot (pet_id_in IN NUMBER) RETURN DATE IS BEGIN ... END; ... END pets_inc;
while my package specification remains the same:
PACKAGE pets_inc IS ... FUNCTION next_pet_shot (pet_id_in IN petid_type) RETURN DATE; ... END pets_inc;
When I try to compile the package body, I receive the following error:
PLS-00323: subprogram 'NEXT_PET_SHOT' is declared in a package specification and must be defined in the package body.
This can be a very alarming and confusing error. The next_pet_shot subprogram must be "defined"? "But it's right there in the package body!" you exclaim. "What is wrong with that compiler?" The problem is that the parameter list of next_pet_shot in the body is different from that in the specification. Even if the datatype to which the petid_type subtype evaluates is a NUMBER, PL/SQL will not accept the version in the body as the implementation for the module in the specification.
When PL/SQL tries to compile a package body, it checks to see that everything defined in the package specification has a body (cursor or module) in the package body. If PL/SQL does not find an exact match for a specification in the body, then it decides that that object is not defined in the package body at all. PL/SQL doesn't look at the object named next_pet_shot in the body and say, "Gee, you really are so close to the version in the specification!" It just throws up its hands and points to the incriminating module. It would be nice to have PL/SQL automatically synchronize the body with the specification, but there are all sorts of complications and, anyway, it would probably destroy something you wanted left intact. So you just have to remember to make changes in both places.
Copyright (c) 2000 O'Reilly & Associates. All rights reserved.