diff options
Diffstat (limited to 'src/tutorial/complex.c')
-rw-r--r-- | src/tutorial/complex.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/src/tutorial/complex.c b/src/tutorial/complex.c new file mode 100644 index 0000000..6798a9e --- /dev/null +++ b/src/tutorial/complex.c @@ -0,0 +1,209 @@ +/* + * src/tutorial/complex.c + * + ****************************************************************************** + 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. +******************************************************************************/ + +#include "postgres.h" + +#include "fmgr.h" +#include "libpq/pqformat.h" /* needed for send/recv functions */ + +PG_MODULE_MAGIC; + +typedef struct Complex +{ + double x; + double y; +} Complex; + + +/***************************************************************************** + * Input/Output functions + *****************************************************************************/ + +PG_FUNCTION_INFO_V1(complex_in); + +Datum +complex_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + double x, + y; + Complex *result; + + if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "complex", str))); + + result = (Complex *) palloc(sizeof(Complex)); + result->x = x; + result->y = y; + PG_RETURN_POINTER(result); +} + +PG_FUNCTION_INFO_V1(complex_out); + +Datum +complex_out(PG_FUNCTION_ARGS) +{ + Complex *complex = (Complex *) PG_GETARG_POINTER(0); + char *result; + + result = psprintf("(%g,%g)", complex->x, complex->y); + 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) +{ + Complex *complex = (Complex *) PG_GETARG_POINTER(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendfloat8(&buf, complex->x); + pq_sendfloat8(&buf, complex->y); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + +/***************************************************************************** + * New Operators + * + * A practical Complex datatype would provide much more than this, of course. + *****************************************************************************/ + +PG_FUNCTION_INFO_V1(complex_add); + +Datum +complex_add(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + Complex *result; + + result = (Complex *) palloc(sizeof(Complex)); + result->x = a->x + b->x; + result->y = a->y + b->y; + PG_RETURN_POINTER(result); +} + + +/***************************************************************************** + * Operator class for defining B-tree index + * + * 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 + * unintentionally inconsistent functions. One way to reduce the odds of + * making a mistake is to make all the functions simple wrappers around + * an internal three-way-comparison function, as we do here. + *****************************************************************************/ + +#define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y) + +static int +complex_abs_cmp_internal(Complex * a, Complex * b) +{ + double amag = Mag(a), + bmag = Mag(b); + + if (amag < bmag) + return -1; + if (amag > bmag) + return 1; + return 0; +} + + +PG_FUNCTION_INFO_V1(complex_abs_lt); + +Datum +complex_abs_lt(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0); +} + +PG_FUNCTION_INFO_V1(complex_abs_le); + +Datum +complex_abs_le(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) <= 0); +} + +PG_FUNCTION_INFO_V1(complex_abs_eq); + +Datum +complex_abs_eq(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) == 0); +} + +PG_FUNCTION_INFO_V1(complex_abs_ge); + +Datum +complex_abs_ge(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) >= 0); +} + +PG_FUNCTION_INFO_V1(complex_abs_gt); + +Datum +complex_abs_gt(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) > 0); +} + +PG_FUNCTION_INFO_V1(complex_abs_cmp); + +Datum +complex_abs_cmp(PG_FUNCTION_ARGS) +{ + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_INT32(complex_abs_cmp_internal(a, b)); +} |