aboutsummaryrefslogtreecommitdiff
path: root/src/tutorial/complex.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-10-21 22:51:14 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-10-21 22:51:14 +0000
commit6fbb14a17432681f80a98f64cc810a7871a0a757 (patch)
tree17a2e4b1214aa1fae976b71515cc0c2b37c86cf8 /src/tutorial/complex.c
parent6c7c493a093ed8f2060015f91b3d1ffe881f1339 (diff)
downloadpostgresql-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.c217
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));
}