]> granicus.if.org Git - postgresql/blob - src/tutorial/complex.c
Pgindent run for 8.0.
[postgresql] / src / tutorial / complex.c
1 /******************************************************************************
2   This file contains routines that can be bound to a Postgres backend and
3   called by the backend in the process of processing queries.  The calling
4   format for these routines is dictated by Postgres architecture.
5 ******************************************************************************/
6
7 #include "postgres.h"
8
9 #include "fmgr.h"
10 #include "libpq/pqformat.h"             /* needed for send/recv functions */
11
12
13 typedef struct Complex
14 {
15         double          x;
16         double          y;
17 }       Complex;
18
19 /*
20  * Since we use V1 function calling convention, all these functions have
21  * the same signature as far as C is concerned.  We provide these prototypes
22  * just to forestall warnings when compiled with gcc -Wmissing-prototypes.
23  */
24 Datum           complex_in(PG_FUNCTION_ARGS);
25 Datum           complex_out(PG_FUNCTION_ARGS);
26 Datum           complex_recv(PG_FUNCTION_ARGS);
27 Datum           complex_send(PG_FUNCTION_ARGS);
28 Datum           complex_add(PG_FUNCTION_ARGS);
29 Datum           complex_abs_lt(PG_FUNCTION_ARGS);
30 Datum           complex_abs_le(PG_FUNCTION_ARGS);
31 Datum           complex_abs_eq(PG_FUNCTION_ARGS);
32 Datum           complex_abs_ge(PG_FUNCTION_ARGS);
33 Datum           complex_abs_gt(PG_FUNCTION_ARGS);
34 Datum           complex_abs_cmp(PG_FUNCTION_ARGS);
35
36
37 /*****************************************************************************
38  * Input/Output functions
39  *****************************************************************************/
40
41 PG_FUNCTION_INFO_V1(complex_in);
42
43 Datum
44 complex_in(PG_FUNCTION_ARGS)
45 {
46         char       *str = PG_GETARG_CSTRING(0);
47         double          x,
48                                 y;
49         Complex    *result;
50
51         if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
52                 ereport(ERROR,
53                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
54                                  errmsg("invalid input syntax for complex: \"%s\"",
55                                                 str)));
56
57         result = (Complex *) palloc(sizeof(Complex));
58         result->x = x;
59         result->y = y;
60         PG_RETURN_POINTER(result);
61 }
62
63 PG_FUNCTION_INFO_V1(complex_out);
64
65 Datum
66 complex_out(PG_FUNCTION_ARGS)
67 {
68         Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
69         char       *result;
70
71         result = (char *) palloc(100);
72         snprintf(result, 100, "(%g,%g)", complex->x, complex->y);
73         PG_RETURN_CSTRING(result);
74 }
75
76 /*****************************************************************************
77  * Binary Input/Output functions
78  *
79  * These are optional.
80  *****************************************************************************/
81
82 PG_FUNCTION_INFO_V1(complex_recv);
83
84 Datum
85 complex_recv(PG_FUNCTION_ARGS)
86 {
87         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
88         Complex    *result;
89
90         result = (Complex *) palloc(sizeof(Complex));
91         result->x = pq_getmsgfloat8(buf);
92         result->y = pq_getmsgfloat8(buf);
93         PG_RETURN_POINTER(result);
94 }
95
96 PG_FUNCTION_INFO_V1(complex_send);
97
98 Datum
99 complex_send(PG_FUNCTION_ARGS)
100 {
101         Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
102         StringInfoData buf;
103
104         pq_begintypsend(&buf);
105         pq_sendfloat8(&buf, complex->x);
106         pq_sendfloat8(&buf, complex->y);
107         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
108 }
109
110 /*****************************************************************************
111  * New Operators
112  *
113  * A practical Complex datatype would provide much more than this, of course.
114  *****************************************************************************/
115
116 PG_FUNCTION_INFO_V1(complex_add);
117
118 Datum
119 complex_add(PG_FUNCTION_ARGS)
120 {
121         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
122         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
123         Complex    *result;
124
125         result = (Complex *) palloc(sizeof(Complex));
126         result->x = a->x + b->x;
127         result->y = a->y + b->y;
128         PG_RETURN_POINTER(result);
129 }
130
131
132 /*****************************************************************************
133  * Operator class for defining B-tree index
134  *
135  * It's essential that the comparison operators and support function for a
136  * B-tree index opclass always agree on the relative ordering of any two
137  * data values.  Experience has shown that it's depressingly easy to write
138  * unintentionally inconsistent functions.      One way to reduce the odds of
139  * making a mistake is to make all the functions simple wrappers around
140  * an internal three-way-comparison function, as we do here.
141  *****************************************************************************/
142
143 #define Mag(c)  ((c)->x*(c)->x + (c)->y*(c)->y)
144
145 static int
146 complex_abs_cmp_internal(Complex * a, Complex * b)
147 {
148         double          amag = Mag(a),
149                                 bmag = Mag(b);
150
151         if (amag < bmag)
152                 return -1;
153         if (amag > bmag)
154                 return 1;
155         return 0;
156 }
157
158
159 PG_FUNCTION_INFO_V1(complex_abs_lt);
160
161 Datum
162 complex_abs_lt(PG_FUNCTION_ARGS)
163 {
164         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
165         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
166
167         PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0);
168 }
169
170 PG_FUNCTION_INFO_V1(complex_abs_le);
171
172 Datum
173 complex_abs_le(PG_FUNCTION_ARGS)
174 {
175         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
176         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
177
178         PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) <= 0);
179 }
180
181 PG_FUNCTION_INFO_V1(complex_abs_eq);
182
183 Datum
184 complex_abs_eq(PG_FUNCTION_ARGS)
185 {
186         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
187         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
188
189         PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) == 0);
190 }
191
192 PG_FUNCTION_INFO_V1(complex_abs_ge);
193
194 Datum
195 complex_abs_ge(PG_FUNCTION_ARGS)
196 {
197         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
198         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
199
200         PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) >= 0);
201 }
202
203 PG_FUNCTION_INFO_V1(complex_abs_gt);
204
205 Datum
206 complex_abs_gt(PG_FUNCTION_ARGS)
207 {
208         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
209         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
210
211         PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) > 0);
212 }
213
214 PG_FUNCTION_INFO_V1(complex_abs_cmp);
215
216 Datum
217 complex_abs_cmp(PG_FUNCTION_ARGS)
218 {
219         Complex    *a = (Complex *) PG_GETARG_POINTER(0);
220         Complex    *b = (Complex *) PG_GETARG_POINTER(1);
221
222         PG_RETURN_INT32(complex_abs_cmp_internal(a, b));
223 }