-
Notifications
You must be signed in to change notification settings - Fork 849
/
Copy pathmulti-dimension-array-emulation.sql
154 lines (134 loc) · 4.21 KB
/
multi-dimension-array-emulation.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
152
153
/*
PL/SQL doesn't offer native support for multi-dimensional arrays,
as you will find in other programming languages. You can, however,
emulate these structures using nested collections. The syntax can be
something of a surprise to developers, so be sure to hide the details
behind a simple API.
*/
-- Helper Procedure to Display Booleans
CREATE OR REPLACE PROCEDURE bpl (val IN BOOLEAN)
IS
BEGIN
DBMS_OUTPUT.put_line (
CASE val
WHEN TRUE THEN 'TRUE'
WHEN FALSE THEN 'FALSE'
ELSE 'NULL'
END);
END bpl;
/
-- Define Three Level Nested Collection for 3D Array
/*
Dimension 3 is a collection of Dimension 2. Dimension 2 is a collection
of Dimension 1. It's awkward and it can be even more awkward to remember
the order in which to reference the dimensions, so we add an API to set
and get cell values.
*/
CREATE OR REPLACE PACKAGE multdim AUTHID DEFINER
IS
-- In other languages: l_space array (3, 5, 100);
TYPE dim1_t IS TABLE OF VARCHAR2 (32767) INDEX BY PLS_INTEGER;
TYPE dim2_t IS TABLE OF dim1_t INDEX BY PLS_INTEGER;
TYPE dim3_t IS TABLE OF dim2_t INDEX BY PLS_INTEGER;
PROCEDURE setcell (
array_in IN OUT dim3_t
,dim1_in PLS_INTEGER
,dim2_in PLS_INTEGER
,dim3_in PLS_INTEGER
,value_in IN VARCHAR2
);
FUNCTION getcell (
array_in IN dim3_t
,dim1_in PLS_INTEGER
,dim2_in PLS_INTEGER
,dim3_in PLS_INTEGER
)
RETURN VARCHAR2;
FUNCTION EXISTS (
array_in IN dim3_t
,dim1_in PLS_INTEGER
,dim2_in PLS_INTEGER
,dim3_in PLS_INTEGER
)
RETURN BOOLEAN;
END multdim;
/
-- Hide the Details
-- Are you going to remember - are you going to trust others to remember -
-- the right order in which to specify the dimensions? No!
CREATE OR REPLACE PACKAGE BODY multdim
IS
PROCEDURE setcell (
array_in IN OUT dim3_t
,dim1_in PLS_INTEGER
,dim2_in PLS_INTEGER
,dim3_in PLS_INTEGER
,value_in IN VARCHAR2
)
IS
BEGIN
-- Typical syntax: array_in (dim1_in, dim2_in, dim3_in) := value_in;
array_in (dim3_in) (dim2_in) (dim1_in) := value_in;
-- Or is it? array_in (dim1_in) (dim2_in) (dim3_in) := value_in;
END;
FUNCTION getcell (
array_in IN dim3_t
,dim1_in PLS_INTEGER
,dim2_in PLS_INTEGER
,dim3_in PLS_INTEGER
)
RETURN VARCHAR2
IS
BEGIN
RETURN array_in (dim3_in) (dim2_in) (dim1_in);
END;
FUNCTION EXISTS (
array_in IN dim3_t
,dim1_in PLS_INTEGER
,dim2_in PLS_INTEGER
,dim3_in PLS_INTEGER
)
RETURN BOOLEAN
IS
l_value VARCHAR2 (32767);
BEGIN
-- 11/2002 Manchester
-- The value doesn't matter; what matters is whether
-- this combination exists or not.
--
-- 02/2003 NWOUG Seattle
-- Note: EXISTS method only applies to a single
-- collection at a time.
/*
IF array_in(dim3_in )(dim2_in )(dim1_in) IS NOT NULL
THEN
RETURN TRUE;
ELSE
RETURN TRUE;
END IF;
*/
-- Disney World approach 4/2003
l_value := array_in (dim3_in) (dim2_in) (dim1_in);
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND OR VALUE_ERROR
THEN
RETURN FALSE;
END;
END multdim;
/
-- Exercise the Package
DECLARE
my_3d_array multdim.dim3_t;
BEGIN
multdim.setcell (my_3d_array, 1, 5, 800, 'def');
multdim.setcell (my_3d_array, 1, 15, 800, 'def');
multdim.setcell (my_3d_array, 5, 5, 800, 'def');
multdim.setcell (my_3d_array, 5, 5, 805, 'def');
DBMS_OUTPUT.PUT_LINE (multdim.getcell (my_3d_array, 1, 5, 800));
bpl (multdim.EXISTS (my_3d_array, 1, 5, 800));
bpl (multdim.EXISTS (my_3d_array, 6000, 5, 800));
bpl (multdim.EXISTS (my_3d_array, 6000, 5, 807));
DBMS_OUTPUT.PUT_LINE (my_3d_array.COUNT);
END;
/