complex.c 5.8 KB
Newer Older
1 2 3 4
/*
 * $PostgreSQL: pgsql/src/tutorial/complex.c,v 1.14 2008/05/17 01:28:26 adunstan Exp $ 
 *
 ******************************************************************************
5 6 7 8 9
  This file contains routines that can be bound to a Postgres backend and
  called by the backend in the process of processing queries.  The calling
  format for these routines is dictated by Postgres architecture.
******************************************************************************/

10 11
#include "postgres.h"

12 13 14 15
#include "fmgr.h"
#include "libpq/pqformat.h"		/* needed for send/recv functions */


16 17
PG_MODULE_MAGIC;

18 19
typedef struct Complex
{
20 21
	double		x;
	double		y;
22
}	Complex;
23

24 25 26 27 28
/*
 * Since we use V1 function calling convention, all these functions have
 * the same signature as far as C is concerned.  We provide these prototypes
 * just to forestall warnings when compiled with gcc -Wmissing-prototypes.
 */
B
Bruce Momjian 已提交
29 30 31 32 33 34 35 36 37 38 39
Datum		complex_in(PG_FUNCTION_ARGS);
Datum		complex_out(PG_FUNCTION_ARGS);
Datum		complex_recv(PG_FUNCTION_ARGS);
Datum		complex_send(PG_FUNCTION_ARGS);
Datum		complex_add(PG_FUNCTION_ARGS);
Datum		complex_abs_lt(PG_FUNCTION_ARGS);
Datum		complex_abs_le(PG_FUNCTION_ARGS);
Datum		complex_abs_eq(PG_FUNCTION_ARGS);
Datum		complex_abs_ge(PG_FUNCTION_ARGS);
Datum		complex_abs_gt(PG_FUNCTION_ARGS);
Datum		complex_abs_cmp(PG_FUNCTION_ARGS);
40 41


42 43 44 45
/*****************************************************************************
 * Input/Output functions
 *****************************************************************************/

46 47 48 49
PG_FUNCTION_INFO_V1(complex_in);

Datum
complex_in(PG_FUNCTION_ARGS)
50
{
51
	char	   *str = PG_GETARG_CSTRING(0);
52 53 54
	double		x,
				y;
	Complex    *result;
55 56

	if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
T
Tom Lane 已提交
57 58
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
59 60
				 errmsg("invalid input syntax for complex: \"%s\"",
						str)));
T
Tom Lane 已提交
61

62 63 64
	result = (Complex *) palloc(sizeof(Complex));
	result->x = x;
	result->y = y;
65
	PG_RETURN_POINTER(result);
66 67
}

68 69 70 71
PG_FUNCTION_INFO_V1(complex_out);

Datum
complex_out(PG_FUNCTION_ARGS)
72
{
B
Bruce Momjian 已提交
73
	Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
74
	char	   *result;
75

76 77
	result = (char *) palloc(100);
	snprintf(result, 100, "(%g,%g)", complex->x, complex->y);
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
	PG_RETURN_CSTRING(result);
}

/*****************************************************************************
 * Binary Input/Output functions
 *
 * These are optional.
 *****************************************************************************/

PG_FUNCTION_INFO_V1(complex_recv);

Datum
complex_recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	Complex    *result;

	result = (Complex *) palloc(sizeof(Complex));
	result->x = pq_getmsgfloat8(buf);
	result->y = pq_getmsgfloat8(buf);
	PG_RETURN_POINTER(result);
}

PG_FUNCTION_INFO_V1(complex_send);

Datum
complex_send(PG_FUNCTION_ARGS)
{
B
Bruce Momjian 已提交
106
	Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
107 108 109 110 111 112
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendfloat8(&buf, complex->x);
	pq_sendfloat8(&buf, complex->y);
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
113 114 115 116
}

/*****************************************************************************
 * New Operators
117 118
 *
 * A practical Complex datatype would provide much more than this, of course.
119 120
 *****************************************************************************/

121 122 123 124
PG_FUNCTION_INFO_V1(complex_add);

Datum
complex_add(PG_FUNCTION_ARGS)
125
{
B
Bruce Momjian 已提交
126 127
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
128
	Complex    *result;
129 130 131 132

	result = (Complex *) palloc(sizeof(Complex));
	result->x = a->x + b->x;
	result->y = a->y + b->y;
133
	PG_RETURN_POINTER(result);
134 135 136 137 138
}


/*****************************************************************************
 * Operator class for defining B-tree index
139 140 141 142
 *
 * It's essential that the comparison operators and support function for a
 * B-tree index opclass always agree on the relative ordering of any two
 * data values.  Experience has shown that it's depressingly easy to write
B
Bruce Momjian 已提交
143
 * unintentionally inconsistent functions.	One way to reduce the odds of
144 145
 * making a mistake is to make all the functions simple wrappers around
 * an internal three-way-comparison function, as we do here.
146 147 148 149
 *****************************************************************************/

#define Mag(c)	((c)->x*(c)->x + (c)->y*(c)->y)

150
static int
B
Bruce Momjian 已提交
151
complex_abs_cmp_internal(Complex * a, Complex * b)
152
{
153 154
	double		amag = Mag(a),
				bmag = Mag(b);
155

156 157 158 159 160
	if (amag < bmag)
		return -1;
	if (amag > bmag)
		return 1;
	return 0;
161 162
}

163 164 165 166 167

PG_FUNCTION_INFO_V1(complex_abs_lt);

Datum
complex_abs_lt(PG_FUNCTION_ARGS)
168
{
B
Bruce Momjian 已提交
169 170
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
171

172
	PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0);
173 174
}

175 176 177 178
PG_FUNCTION_INFO_V1(complex_abs_le);

Datum
complex_abs_le(PG_FUNCTION_ARGS)
179
{
B
Bruce Momjian 已提交
180 181
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
182

183
	PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) <= 0);
184 185
}

186 187 188 189
PG_FUNCTION_INFO_V1(complex_abs_eq);

Datum
complex_abs_eq(PG_FUNCTION_ARGS)
190
{
B
Bruce Momjian 已提交
191 192
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
193

194
	PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) == 0);
195 196
}

197 198 199 200
PG_FUNCTION_INFO_V1(complex_abs_ge);

Datum
complex_abs_ge(PG_FUNCTION_ARGS)
201
{
B
Bruce Momjian 已提交
202 203
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
204

205
	PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) >= 0);
206 207
}

208 209 210 211
PG_FUNCTION_INFO_V1(complex_abs_gt);

Datum
complex_abs_gt(PG_FUNCTION_ARGS)
212
{
B
Bruce Momjian 已提交
213 214
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
215

216
	PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) > 0);
217 218
}

219
PG_FUNCTION_INFO_V1(complex_abs_cmp);
220

221 222
Datum
complex_abs_cmp(PG_FUNCTION_ARGS)
223
{
B
Bruce Momjian 已提交
224 225
	Complex    *a = (Complex *) PG_GETARG_POINTER(0);
	Complex    *b = (Complex *) PG_GETARG_POINTER(1);
226 227

	PG_RETURN_INT32(complex_abs_cmp_internal(a, b));
228
}