]> granicus.if.org Git - postgresql/blob - src/tutorial/complex.source
From: Darren King <darrenk@insightdist.com>
[postgresql] / src / tutorial / complex.source
1 ---------------------------------------------------------------------------
2 --
3 -- complex.sql-
4 --    This file shows how to create a new user-defined type and how to
5 --    use this new type.
6 -- 
7 --
8 -- Copyright (c) 1994, Regents of the University of California
9 --
10 -- $Id: complex.source,v 1.4 1998/03/01 04:52:59 scrappy Exp $
11 --
12 ---------------------------------------------------------------------------
13
14 -----------------------------
15 -- Creating a new type:
16 --      a user-defined type must have an input and an output function. They
17 --      are user-defined C functions. We are going to create a new type 
18 --      called 'complex' which represents complex numbers.
19 -----------------------------
20
21 -- Assume the user defined functions are in _OBJWD_/complex.so
22 -- Look at $PWD/complex.c for the source.
23
24 -- the input function 'complex_in' takes a null-terminated string (the 
25 -- textual representation of the type) and turns it into the internal
26 -- (in memory) representation. You will get a message telling you 'complex'
27 -- does not exist yet but that's okay.
28
29 CREATE FUNCTION complex_in(opaque)
30    RETURNS complex
31    AS '_OBJWD_/complex.so'
32    LANGUAGE 'c';
33
34 -- the output function 'complex_out' takes the internal representation and
35 -- converts it into the textual representation.
36
37 CREATE FUNCTION complex_out(opaque)
38    RETURNS opaque
39    AS '_OBJWD_/complex.so'
40    LANGUAGE 'c';
41
42 -- now, we can create the type. The internallength specifies the size of the
43 -- memory block required to hold the type (we need two 8-byte doubles).
44
45 CREATE TYPE complex (
46    internallength = 16, 
47    input = complex_in,
48    output = complex_out
49 );
50
51
52 -----------------------------
53 -- Using the new type:
54 --      user-defined types can be use like ordinary built-in types.
55 -----------------------------
56
57 -- eg. we can use it in a schema
58
59 CREATE TABLE test_complex (
60         a       complex,
61         b       complex
62 );
63
64 -- data for user-defined type are just strings in the proper textual
65 -- representation. 
66
67 INSERT INTO test_complex VALUES ('(1.0, 2.5)', '(4.2, 3.55 )');
68 INSERT INTO test_complex VALUES ('(33.0, 51.4)', '(100.42, 93.55)');
69
70 SELECT * FROM test_complex;
71
72 -----------------------------
73 -- Creating an operator for the new type:
74 --      Let's define an add operator for complex types. Since POSTGRES
75 --      supports function overloading, we'll use + as the add operator.
76 --      (Operators can be reused with different number and types of 
77 --      arguments.)
78 -----------------------------
79
80 -- first, define a function complex_add (also in complex.c)
81 CREATE FUNCTION complex_add(complex, complex)
82    RETURNS complex
83    AS '_OBJWD_/complex.so'
84    LANGUAGE 'c';
85
86 -- we can now define the operator. We show a binary operator here but you
87 -- can also define unary operators by omitting either of leftarg or rightarg.
88 CREATE OPERATOR + ( 
89    leftarg = complex,
90    rightarg = complex,
91    procedure = complex_add,
92    commutator = +
93 );
94
95
96 SELECT (a + b) AS c FROM test_complex;
97
98 -- Occasionally, you may find it useful to cast the string to the desired
99 -- type explicitly. :: denotes a type cast.
100
101 SELECT  a + '(1.0,1.0)'::complex AS aa,
102         b + '(1.0,1.0)'::complex AS bb
103    FROM test_complex;
104
105
106 -----------------------------
107 -- Creating aggregate functions
108 --      you can also define aggregate functions. The syntax is somewhat
109 --      cryptic but the idea is to express the aggregate in terms of state
110 --      transition functions.
111 -----------------------------
112
113 CREATE AGGREGATE complex_sum (
114    sfunc1 = complex_add,
115    basetype = complex,
116    stype1 = complex,
117    initcond1 = '(0,0)'
118 );
119
120 SELECT complex_sum(a) FROM test_complex;
121
122
123 -------------------------------------------------------------------------------
124 --             ATTENTION!      ATTENTION!      ATTENTION!                    --
125 --  YOU MAY SKIP THE SECTION BELOW ON INTERFACING WITH INDICES. YOU DON'T    --
126 --  NEED THE FOLLOWING IF YOU DON'T USE INDICES WITH NEW DATA TYPES.         --
127 -------------------------------------------------------------------------------
128
129 SELECT 'READ ABOVE!' AS STOP;
130
131 -----------------------------
132 -- Interfacing New Types with Indices:
133 --      We cannot define a secondary index (eg. a B-tree) over the new type
134 --      yet. We need to modify a few system catalogs to show POSTGRES how
135 --      to use the new type. Unfortunately, there is no simple command to
136 --      do this. Please bear with me.
137 -----------------------------
138
139 -- first, define the required operators
140 CREATE FUNCTION complex_abs_lt(complex, complex) RETURNS bool
141    AS '_OBJWD_/complex.so' LANGUAGE 'c';
142 CREATE FUNCTION complex_abs_le(complex, complex) RETURNS bool
143    AS '_OBJWD_/complex.so' LANGUAGE 'c';
144 CREATE FUNCTION complex_abs_eq(complex, complex) RETURNS bool
145    AS '_OBJWD_/complex.so' LANGUAGE 'c';
146 CREATE FUNCTION complex_abs_ge(complex, complex) RETURNS bool
147    AS '_OBJWD_/complex.so' LANGUAGE 'c';
148 CREATE FUNCTION complex_abs_gt(complex, complex) RETURNS bool
149    AS '_OBJWD_/complex.so' LANGUAGE 'c';
150
151 -- the restrict and join selectivity functions are bogus (notice we only
152 -- have intltsel, eqsel and intgtsel)
153 CREATE OPERATOR < (
154    leftarg = complex, rightarg = complex, procedure = complex_abs_lt,
155    restrict = intltsel, join = intltjoinsel
156 );
157 CREATE OPERATOR <= (
158    leftarg = complex, rightarg = complex, procedure = complex_abs_le,
159    restrict = intltsel, join = intltjoinsel
160 );
161 CREATE OPERATOR = (
162    leftarg = complex, rightarg = complex, procedure = complex_abs_eq,
163    restrict = eqsel, join = eqjoinsel
164 );
165 CREATE OPERATOR >= (
166    leftarg = complex, rightarg = complex, procedure = complex_abs_ge,
167    restrict = intgtsel, join = intgtjoinsel
168 );
169 CREATE OPERATOR > (
170    leftarg = complex, rightarg = complex, procedure = complex_abs_gt,
171    restrict = intgtsel, join = intgtjoinsel
172 );
173
174 INSERT INTO pg_opclass VALUES ('complex_abs_ops');
175
176 SELECT oid, opcname FROM pg_opclass WHERE opcname = 'complex_abs_ops';
177
178 SELECT o.oid AS opoid, o.oprname
179 INTO TABLE complex_ops_tmp
180 FROM pg_operator o, pg_type t
181 WHERE o.oprleft = t.oid and o.oprright = t.oid
182    and t.typname = 'complex';
183
184 -- make sure we have the right operators
185 SELECT * from complex_ops_tmp;
186
187 INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy, 
188                      amopselect, amopnpages)
189    SELECT am.oid, opcl.oid, c.opoid, 1,
190         'btreesel'::regproc, 'btreenpage'::regproc
191    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
192    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
193       and c.oprname = '<';
194
195 INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy, 
196                      amopselect, amopnpages)
197    SELECT am.oid, opcl.oid, c.opoid, 2,
198         'btreesel'::regproc, 'btreenpage'::regproc
199    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
200    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
201       and c.oprname = '<=';
202
203 INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy, 
204                      amopselect, amopnpages)
205    SELECT am.oid, opcl.oid, c.opoid, 3,
206         'btreesel'::regproc, 'btreenpage'::regproc
207    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
208    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
209       and c.oprname = '=';
210
211 INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy, 
212                      amopselect, amopnpages)
213    SELECT am.oid, opcl.oid, c.opoid, 4,
214         'btreesel'::regproc, 'btreenpage'::regproc
215    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
216    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
217       and c.oprname = '>=';
218
219 INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy, 
220                      amopselect, amopnpages)
221    SELECT am.oid, opcl.oid, c.opoid, 5,
222         'btreesel'::regproc, 'btreenpage'::regproc
223    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
224    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
225       and c.oprname = '>';
226
227 --
228 CREATE FUNCTION complex_abs_cmp(complex, complex) RETURNS int4
229    AS '_OBJWD_/complex.so' LANGUAGE 'c';
230
231 SELECT oid, proname FROM pg_proc WHERE proname = 'complex_abs_cmp';
232
233 INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
234    SELECT am.oid, opcl.oid, pro.oid, 1
235    FROM pg_am am, pg_opclass opcl, pg_proc pro
236    WHERE  amname = 'btree' and opcname = 'complex_abs_ops'
237       and proname = 'complex_abs_cmp';
238
239 -- now, we can define a btree index on complex types. First, let's populate
240 -- the table. Note that postgres needs many more tuples to start using the
241 -- btree index during selects.
242 INSERT INTO test_complex VALUES ('(56.0,-22.5)', '(-43.2,-0.07)');
243 INSERT INTO test_complex VALUES ('(-91.9,33.6)', '(8.6,3.0)');
244
245 CREATE INDEX test_cplx_ind ON test_complex
246    USING btree(a complex_abs_ops);
247
248 SELECT * from test_complex where a = '(56.0,-22.5)';
249 SELECT * from test_complex where a < '(56.0,-22.5)';
250 SELECT * from test_complex where a > '(56.0,-22.5)';
251
252 DELETE FROM pg_amop where (amopid, amopclaid, amopopr, amopstrategy)
253    = (
254    SELECT am.oid, opcl.oid, c.opoid, 1
255    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
256    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
257       and c.oprname = '<');
258
259 DELETE FROM pg_amop where (amopid, amopclaid, amopopr, amopstrategy)
260    = (
261    SELECT am.oid, opcl.oid, c.opoid, 2
262    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
263    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
264       and c.oprname = '<=');
265
266 DELETE FROM pg_amop where (amopid, amopclaid, amopopr, amopstrategy)
267    = (
268    SELECT am.oid, opcl.oid, c.opoid, 3
269    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
270    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
271       and c.oprname = '=');
272
273 DELETE FROM pg_amop where (amopid, amopclaid, amopopr, amopstrategy)
274    = (
275    SELECT am.oid, opcl.oid, c.opoid, 4
276    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
277    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
278       and c.oprname = '>=');
279
280 DELETE FROM pg_amop where (amopid, amopclaid, amopopr, amopstrategy)
281    = (
282    SELECT am.oid, opcl.oid, c.opoid, 5
283    FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
284    WHERE amname = 'btree' and opcname = 'complex_abs_ops' 
285       and c.oprname = '>');
286
287 DELETE FROM pg_amproc where (amid, amopclaid, amproc, amprocnum)
288    = (
289    SELECT am.oid, opcl.oid, pro.oid, 1
290    FROM pg_am am, pg_opclass opcl, pg_proc pro
291    WHERE  amname = 'btree' and opcname = 'complex_abs_ops'
292       and proname = 'complex_abs_cmp');
293
294 DELETE FROM pg_opclass WHERE opcname = 'complex_abs_ops';
295
296 DROP FUNCTION complex_in(opaque);
297 DROP FUNCTION complex_out(opaque);
298 DROP FUNCTION complex_add(complex, complex);
299 DROP FUNCTION complex_abs_lt(complex, complex);
300 DROP FUNCTION complex_abs_le(complex, complex);
301 DROP FUNCTION complex_abs_eq(complex, complex);
302 DROP FUNCTION complex_abs_ge(complex, complex);
303 DROP FUNCTION complex_abs_gt(complex, complex);
304 DROP FUNCTION complex_abs_cmp(complex, complex);
305 DROP OPERATOR + (complex, complex);
306 DROP OPERATOR < (complex, complex);
307 DROP OPERATOR <= (complex, complex);
308 DROP OPERATOR = (complex, complex);
309 DROP OPERATOR >= (complex, complex);
310 DROP OPERATOR > (complex, complex);
311 DROP AGGREGATE complex_sum complex;
312 DROP TYPE complex;
313 DROP TABLE test_complex, complex_ops_tmp;