Inherit the Database: Oracle9i's Support for Object Type Inheritance
Pages: 1, 2, 3, 4, 5
An Example of Dynamic Polymorphism
Let's take a look at how I can take advantage of dynamic polymorphism with my hierarchy of different types of persons. I need to write a program to show what happens when different types of persons (which, in the U.S., include corporations by legal precedent) commit a crime. I'll walk through the individual steps for such a program.
First, I'll define my different types of persons:
A pre-citizenship person, Eve:
eve person_ot := person_ot ( 'Human', 'Eve', 175 /* Rubanesque */, NULL );A U.S. citizen who's currently on death row for murder, but is believed by many to be innocent of the crime (or at least to have received a grossly unfair trial). Notice that I add two additional attributes for a citizen, nation, and political preference.
ondeathrow citizen_ot := citizen_ot ( 'Human', 'Mumia Abul Jamal', 150, NULL, 'USA', 'Radical' );A very scary company, the likes of which we're likely to see in the next decade or so with the way mergers and acquisitions are proceeding these days:
theglobalmonster corporation_ot := corporation_ot ( 'Inhuman', 'Northrup-Ford-Mattel-Yahoo-ATT', NULL, SYSDATE, 5000000, 50000000 );An even scarier human being, defined as a war criminal for his direction of the carpet- bombing of Vietnam and Cambodia:
wiseman warcriminal_ot := warcriminal_ot ( 'Human?', 'Henry Kissinger', 175, NULL, 'USA', 'Above the law', 1000000, 'Vietnam and Cambodia' );
I've now defined four different objects, instantiated from different types in the person
hierarchy: person, citizen, corporation, and war criminal. Now for the really interesting
stuff. I want to define an array or list that contains all of these objects and then manipulate
the contents of that array. Since all of the objects derive from the person supertype, I can
declare a nested table of persons and populate that array with either person objects or
objects declared from subtypes of person:
TYPE bighappyfamily_nt IS TABLE OF person_ot;
bighappyfamily bighappyfamily_nt
:= bighappyfamily_nt (
eve,
ondeathrow,
theglobalmonster,
wiseman
);
I've now completed my declarations. On to my executable section. What I need to do is show what happens to each "person" when he or she commits a crime. What political power do they have and what is their punishment? To do that I can simply execute the following loop:
BEGIN
FOR persindx IN
bighappyfamily.FIRST .. bighappyfamily.LAST
LOOP
DBMS_OUTPUT.PUT_LINE (' ');
bighappyfamily (persindx).when_crime_committed;
END LOOP;
END;
The output from this loop's execution is shown in Listing 4. It all looks perfectly appropriate. For each different type of person, the information displayed is specific to that object. Yet quite a lot is going on behind the scenes to make that happen. Let's take a closer took.
Listing 4. Output from displaying the contents of the bighappyfamily array.
Suppose Eve Was Convicted of a Crime.--
Person named Eve weighs 175 and was born on
Political power?
The existence of a soul
Punishment?
Leave Garden of Eden
--Suppose Mumia Abul Jamal Was Convicted of a Crime.--
Citizen Mumia Abul Jamal is a citizen of USA whose politics are Radical
Political power?
One vote
Punishment?
Go to jail, do not pass Go, do not survive.
--Suppose Northrup-Ford-Mattel-Yahoo-ATT Was Convicted of a Crime.--
Corporation Northrup-Ford-Mattel-Yahoo-ATT is a trans-national entity with
50000000 laid-off employees, paying its Chief Executive Officer 5000000
Political power?
Virtually unlimited
Punishment?
Increased political contributions.
--Suppose Henry Kissinger Was Convicted of a Crime.--
War criminal Henry Kissinger killed 1000000 in Vietnam and Cambodia
Political power?
Filling the vacuum.
Punishment?
Sometimes you win the Nobel Peace Prize.
My FOR loop iterates through every row of bighappyfamily. Recall that
bighappyfamily is a nested table of persons. Within the FOR loop, I invoke the
when_crime_committed method for each element in the array. The
when_crime_committed method is declared as FINAL in the person object and
implemented as follows:
FINAL MEMBER PROCEDURE when_crime_committed
IS
BEGIN
DBMS_OUTPUT.PUT_LINE ( '--Suppose '
|| name
|| ' Was Convicted of a Crime.--');
DBMS_OUTPUT.PUT_LINE (' ');
show;
DBMS_OUTPUT.PUT_LINE (' ');
DBMS_OUTPUT.PUT_LINE ('Political power?');
showPoliticalPower;
DBMS_OUTPUT.PUT_LINE (' ');
DBMS_OUTPUT.PUT_LINE ('Punishment?');
showpunishment;
END;
By defining the method as FINAL, I disallow any of the subtypes of person to override
this program. Notice, however, that when_crime_committed invokes three other methods:
show, showPoliticalPower and showPunishment. None of these methods, defined in person_ot, are defined as FINAL and, in fact, are overridden in each of the object types citizen_ot, corporation_ot, and war_criminal_ot. Here's one example of such an override, the citizen.showPoliticalPower method:
OVERRIDING
MEMBER PROCEDURE
showpoliticalpower
IS
BEGIN
DBMS_OUTPUT.PUT_LINE (
'One vote');
END;
So, at the time of compilation of the person_ot object type, references to the show,
showPoliticalPower, and showPunishment methods are all resolved to the person_ot methods. But when the when_crime_committed method is actually executed by the PL/SQL runtime engine, dynamic method dispatch results in a very different resolution.
When Oracle executes the following method, for example:
bighappyfamily(3).when_crime_committed
it identifies the object type as corporation_ot. Then it checks to see whether
when_crime_committed is defined as a method in corporation_ot. It's not and, in fact, is only defined in person_ot. So the runtime engine then invokes
person.when_crime_committed. As it runs that method, it encounters the
showPoliticalPower method. Once again, Oracle must identify which of the
showPoliticalPower methods to run. Even though it's currently executing a person_ot method, it hasn't forgotten where it came from. It therefore starts its search through the
hierarchy with the corporation_ot object type. And, in fact, it finds that corporation_ot has
implemented an overriding showPoliticalPower method. So it uses that one and not the
person_ot.show method.
There are two approaches to resolving invocations to methods, static and dynamic.
Dynamic polymorphism gives developers an incredible amount of flexibility. We can write generalized programs that seemingly overlook variations in subtypes and levels in the hierarchy. We leave it to the runtime engine to locate and execute the most appropriate definition of a method.
It's Time to Try Out Object Types
Prior to Oracle9i, there was no compelling reason to use object types unless you used Oracle Advanced Queuing or some other Oracle utility that relied on object types. There were simply too many limitations to its implementation. With Oracle9i and the support for inheritance, however, Oracle takes PL/SQL a big step closer to a true object-oriented language.
Now that we can set up object-type hierarchies, it's worth revisiting object types to see how they can be used to construct robust applications based on PL/SQL. We'll explore further nuances of inheritance in the next article.
This article was originally published in the December 2001 issue of Oracle Professional. The material in Feuerstein and Bryn Llewellyn's articles is based on Oracle Corporation white papers originally prepared by Llewellyn for Oracle OpenWorld 2001 in San Francisco and OracleWorld Copenhagen in June 2002 and Oracle PL/SQL Programming, 3rd Edition.
Steven Feuerstein is considered one of the world's leading experts on the Oracle PL/SQL language, having written ten books on the subject. Steven is a Senior Technology Advisor with Quest Software and has been developing software since 1980.
O'Reilly & Associates recently released (September 2002) Oracle PL/SQL Programming, 3rd Edition.
Sample Chapter 10, Dates and Timestamps , is available free online.
You can also look at the Table of Contents, the Index, and the Full Description of the book.
For more information, or to order the book, click here.
|
Related Reading Oracle PL/SQL Programming |
Return to the O'Reilly Network.




