diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-10-21 22:51:14 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-10-21 22:51:14 +0000 |
commit | 6fbb14a17432681f80a98f64cc810a7871a0a757 (patch) | |
tree | 17a2e4b1214aa1fae976b71515cc0c2b37c86cf8 /src/tutorial/complex.c | |
parent | 6c7c493a093ed8f2060015f91b3d1ffe881f1339 (diff) | |
download | postgresql-6fbb14a17432681f80a98f64cc810a7871a0a757.tar.gz postgresql-6fbb14a17432681f80a98f64cc810a7871a0a757.zip |
Update the complex-datatype example to V1 function calling conventions,
and add binary send/receive functions. Fix some other grottiness such
as failure to mark the C functions STRICT.
Diffstat (limited to 'src/tutorial/complex.c')
-rw-r--r-- | src/tutorial/complex.c | 217 |
1 files changed, 134 insertions, 83 deletions
diff --git a/src/tutorial/complex.c b/src/tutorial/complex.c index 5e8f75ae32e..38aafd9ff56 100644 --- a/src/tutorial/complex.c +++ b/src/tutorial/complex.c @@ -6,33 +6,44 @@ #include "postgres.h" +#include "fmgr.h" +#include "libpq/pqformat.h" /* needed for send/recv functions */ + + typedef struct Complex { double x; double y; } Complex; -/* These prototypes declare the requirements that Postgres places on these - user written functions. -*/ -Complex *complex_in(char *str); -char *complex_out(Complex * complex); -Complex *complex_add(Complex * a, Complex * b); -bool complex_abs_lt(Complex * a, Complex * b); -bool complex_abs_le(Complex * a, Complex * b); -bool complex_abs_eq(Complex * a, Complex * b); -bool complex_abs_ge(Complex * a, Complex * b); -bool complex_abs_gt(Complex * a, Complex * b); -int4 complex_abs_cmp(Complex * a, Complex * b); +/* + * 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. + */ +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); /***************************************************************************** * Input/Output functions *****************************************************************************/ -Complex * -complex_in(char *str) +PG_FUNCTION_INFO_V1(complex_in); + +Datum +complex_in(PG_FUNCTION_ARGS) { + char *str = PG_GETARG_CSTRING(0); double x, y; Complex *result; @@ -40,133 +51,173 @@ complex_in(char *str) if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for complex: \"%s\"", str))); + errmsg("invalid input syntax for complex: \"%s\"", + str))); result = (Complex *) palloc(sizeof(Complex)); result->x = x; result->y = y; - return result; + PG_RETURN_POINTER(result); } -char * -complex_out(Complex * complex) +PG_FUNCTION_INFO_V1(complex_out); + +Datum +complex_out(PG_FUNCTION_ARGS) { + Complex *complex = (Complex *) PG_GETARG_POINTER(0); char *result; - if (complex == NULL) - return NULL; - result = (char *) palloc(100); snprintf(result, 100, "(%g,%g)", complex->x, complex->y); - return result; + 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. *****************************************************************************/ -Complex * -complex_add(Complex * a, Complex * b) +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; - return result; + 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) -bool -complex_abs_lt(Complex * a, Complex * b) +static int +complex_abs_cmp_internal(Complex *a, Complex *b) { double amag = Mag(a), bmag = Mag(b); - return amag < bmag; + if (amag < bmag) + return -1; + if (amag > bmag) + return 1; + return 0; } -bool -complex_abs_le(Complex * a, Complex * b) + +PG_FUNCTION_INFO_V1(complex_abs_lt); + +Datum +complex_abs_lt(PG_FUNCTION_ARGS) { - double amag = Mag(a), - bmag = Mag(b); + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); - return amag <= bmag; + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0); } -bool -complex_abs_eq(Complex * a, Complex * b) +PG_FUNCTION_INFO_V1(complex_abs_le); + +Datum +complex_abs_le(PG_FUNCTION_ARGS) { - double amag = Mag(a), - bmag = Mag(b); + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); - return amag == bmag; + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) <= 0); } -bool -complex_abs_ge(Complex * a, Complex * b) +PG_FUNCTION_INFO_V1(complex_abs_eq); + +Datum +complex_abs_eq(PG_FUNCTION_ARGS) { - double amag = Mag(a), - bmag = Mag(b); + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); - return amag >= bmag; + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) == 0); } -bool -complex_abs_gt(Complex * a, Complex * b) +PG_FUNCTION_INFO_V1(complex_abs_ge); + +Datum +complex_abs_ge(PG_FUNCTION_ARGS) { - double amag = Mag(a), - bmag = Mag(b); + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); - return amag > bmag; + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) >= 0); } -int4 -complex_abs_cmp(Complex * a, Complex * b) +PG_FUNCTION_INFO_V1(complex_abs_gt); + +Datum +complex_abs_gt(PG_FUNCTION_ARGS) { - double amag = Mag(a), - bmag = Mag(b); + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); - if (amag < bmag) - return -1; - else if (amag > bmag) - return 1; - else - return 0; + PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) > 0); } -/***************************************************************************** - * test code - *****************************************************************************/ +PG_FUNCTION_INFO_V1(complex_abs_cmp); -/* - * You should always test your code separately. Trust me, using POSTGRES to - * debug your C function will be very painful and unproductive. In case of - * POSTGRES crashing, it is impossible to tell whether the bug is in your - * code or POSTGRES's. - */ -void test_main(void); -void -test_main() +Datum +complex_abs_cmp(PG_FUNCTION_ARGS) { - Complex *a; - Complex *b; - - a = complex_in("(4.01, 3.77 )"); - printf("a = %s\n", complex_out(a)); - b = complex_in("(1.0,2.0)"); - printf("b = %s\n", complex_out(b)); - printf("a + b = %s\n", complex_out(complex_add(a, b))); - printf("a < b = %d\n", complex_abs_lt(a, b)); - printf("a <= b = %d\n", complex_abs_le(a, b)); - printf("a = b = %d\n", complex_abs_eq(a, b)); - printf("a >= b = %d\n", complex_abs_ge(a, b)); - printf("a > b = %d\n", complex_abs_gt(a, b)); + Complex *a = (Complex *) PG_GETARG_POINTER(0); + Complex *b = (Complex *) PG_GETARG_POINTER(1); + + PG_RETURN_INT32(complex_abs_cmp_internal(a, b)); } |