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