-
Notifications
You must be signed in to change notification settings - Fork 849
/
Copy pathgeneralized-invocation.sql
152 lines (137 loc) · 4.36 KB
/
generalized-invocation.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
PL/SQL supports object-oriented development via object types (our version of classes).
In Oracle Database 11g, you can now reference the method of a (any) supertype in the
type hierarchy via a generalized invocation.
*/
-- Create the Object Type Hierarchy
-- Root type is food, all desserts are a type of food, all cakes are a type of dessert.
-- But not all desserts are cakes. Not all food is dessert. Too bad! :-)
CREATE TYPE food_t AS OBJECT
(name VARCHAR2 (100)
, food_group VARCHAR2 (100)
, grown_in VARCHAR2 (100)
, MEMBER FUNCTION to_string
RETURN VARCHAR2)
NOT FINAL;
/
CREATE OR REPLACE TYPE BODY food_t
IS
MEMBER FUNCTION to_string
RETURN VARCHAR2
IS
BEGIN
RETURN 'FOOD! '
|| self.name
|| '-'
|| self.food_group
|| '-'
|| self.grown_in;
END;
END;
/
-- Override to_string Method
-- Tweak the string representation of a dessert to specialize it, compared to general dessert strings.
CREATE TYPE dessert_t
UNDER food_t
(contains_chocolate CHAR (1)
, OVERRIDING MEMBER FUNCTION to_string
RETURN VARCHAR2)
NOT FINAL;
/
CREATE OR REPLACE TYPE BODY dessert_t
IS
OVERRIDING MEMBER FUNCTION to_string
RETURN VARCHAR2
IS
BEGIN
/* Display the dessert information + food info. */
RETURN 'DESSERT! Chocolate='
|| contains_chocolate
|| ' '
|| (SELF as food_t).to_string ;
END;
END;
/
-- Second Override of to_string Method
-- Further specialize the way a cake is represented as a string
CREATE TYPE cake_t
UNDER dessert_t
(diameter NUMBER
, OVERRIDING MEMBER FUNCTION to_string
RETURN VARCHAR2);
/
CREATE OR REPLACE TYPE BODY cake_t
IS
OVERRIDING MEMBER FUNCTION to_string
RETURN VARCHAR2
IS
BEGIN
/* Call two supertype methods... */
RETURN 'CAKE! Diameter='
|| self.diameter
|| ' '
|| (SELF as dessert_t).to_string;
END;
END;
/
-- Dynamic Polymorphism At Work
-- At runtime, the engine determines which method in the hierarchy should be invoked.
-- That's pretty cool. But what if you want to override that and pick a specific supertype method?
DECLARE
TYPE foodstuffs_nt IS TABLE OF food_t;
fridge_contents foodstuffs_nt
:= foodstuffs_nt (food_t ('Eggs benedict', 'PROTEIN', 'Farm')
, dessert_t ('Strawberries and cream'
, 'FRUIT'
, 'Backyard'
, 'N')
, cake_t ('Chocolate Supreme'
, 'CARBOHYDATE'
, 'Kitchen'
, 'Y'
, 8));
BEGIN
FOR indx IN fridge_contents.FIRST .. fridge_contents.LAST
LOOP
DBMS_OUTPUT.put_line (fridge_contents (indx).to_string);
END LOOP;
END;
/
-- Change Cake's to_string to "Skip" Over Dessert
-- I don't want to invoke cake's to_string. I don't even want to invoke dessert's to_string.
-- I want to go all the way up to food: (SELF as food_t).to_string
CREATE OR REPLACE TYPE BODY cake_t
IS
OVERRIDING MEMBER FUNCTION to_string
RETURN VARCHAR2
IS
BEGIN
/* Call two supertype methods... */
RETURN 'CAKE! Diameter='
|| self.diameter
|| ' '
|| (SELF as food_t).to_string;
END;
END;
/
-- Cake Display Now Different!
DECLARE
TYPE foodstuffs_nt IS TABLE OF food_t;
fridge_contents foodstuffs_nt
:= foodstuffs_nt (food_t ('Eggs benedict', 'PROTEIN', 'Farm')
, dessert_t ('Strawberries and cream'
, 'FRUIT'
, 'Backyard'
, 'N')
, cake_t ('Chocolate Supreme'
, 'CARBOHYDATE'
, 'Kitchen'
, 'Y'
, 8));
BEGIN
FOR indx IN fridge_contents.FIRST .. fridge_contents.LAST
LOOP
DBMS_OUTPUT.put_line (fridge_contents (indx).to_string);
END LOOP;
END;
/