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