Header And Logo

PostgreSQL
| The world's most advanced open source database.

complex.c

Go to the documentation of this file.
00001 /*
00002  * src/tutorial/complex.c
00003  *
00004  ******************************************************************************
00005   This file contains routines that can be bound to a Postgres backend and
00006   called by the backend in the process of processing queries.  The calling
00007   format for these routines is dictated by Postgres architecture.
00008 ******************************************************************************/
00009 
00010 #include "postgres.h"
00011 
00012 #include "fmgr.h"
00013 #include "libpq/pqformat.h"     /* needed for send/recv functions */
00014 
00015 
00016 PG_MODULE_MAGIC;
00017 
00018 typedef struct Complex
00019 {
00020     double      x;
00021     double      y;
00022 }   Complex;
00023 
00024 /*
00025  * Since we use V1 function calling convention, all these functions have
00026  * the same signature as far as C is concerned.  We provide these prototypes
00027  * just to forestall warnings when compiled with gcc -Wmissing-prototypes.
00028  */
00029 Datum       complex_in(PG_FUNCTION_ARGS);
00030 Datum       complex_out(PG_FUNCTION_ARGS);
00031 Datum       complex_recv(PG_FUNCTION_ARGS);
00032 Datum       complex_send(PG_FUNCTION_ARGS);
00033 Datum       complex_add(PG_FUNCTION_ARGS);
00034 Datum       complex_abs_lt(PG_FUNCTION_ARGS);
00035 Datum       complex_abs_le(PG_FUNCTION_ARGS);
00036 Datum       complex_abs_eq(PG_FUNCTION_ARGS);
00037 Datum       complex_abs_ge(PG_FUNCTION_ARGS);
00038 Datum       complex_abs_gt(PG_FUNCTION_ARGS);
00039 Datum       complex_abs_cmp(PG_FUNCTION_ARGS);
00040 
00041 
00042 /*****************************************************************************
00043  * Input/Output functions
00044  *****************************************************************************/
00045 
00046 PG_FUNCTION_INFO_V1(complex_in);
00047 
00048 Datum
00049 complex_in(PG_FUNCTION_ARGS)
00050 {
00051     char       *str = PG_GETARG_CSTRING(0);
00052     double      x,
00053                 y;
00054     Complex    *result;
00055 
00056     if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
00057         ereport(ERROR,
00058                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00059                  errmsg("invalid input syntax for complex: \"%s\"",
00060                         str)));
00061 
00062     result = (Complex *) palloc(sizeof(Complex));
00063     result->x = x;
00064     result->y = y;
00065     PG_RETURN_POINTER(result);
00066 }
00067 
00068 PG_FUNCTION_INFO_V1(complex_out);
00069 
00070 Datum
00071 complex_out(PG_FUNCTION_ARGS)
00072 {
00073     Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
00074     char       *result;
00075 
00076     result = (char *) palloc(100);
00077     snprintf(result, 100, "(%g,%g)", complex->x, complex->y);
00078     PG_RETURN_CSTRING(result);
00079 }
00080 
00081 /*****************************************************************************
00082  * Binary Input/Output functions
00083  *
00084  * These are optional.
00085  *****************************************************************************/
00086 
00087 PG_FUNCTION_INFO_V1(complex_recv);
00088 
00089 Datum
00090 complex_recv(PG_FUNCTION_ARGS)
00091 {
00092     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00093     Complex    *result;
00094 
00095     result = (Complex *) palloc(sizeof(Complex));
00096     result->x = pq_getmsgfloat8(buf);
00097     result->y = pq_getmsgfloat8(buf);
00098     PG_RETURN_POINTER(result);
00099 }
00100 
00101 PG_FUNCTION_INFO_V1(complex_send);
00102 
00103 Datum
00104 complex_send(PG_FUNCTION_ARGS)
00105 {
00106     Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
00107     StringInfoData buf;
00108 
00109     pq_begintypsend(&buf);
00110     pq_sendfloat8(&buf, complex->x);
00111     pq_sendfloat8(&buf, complex->y);
00112     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00113 }
00114 
00115 /*****************************************************************************
00116  * New Operators
00117  *
00118  * A practical Complex datatype would provide much more than this, of course.
00119  *****************************************************************************/
00120 
00121 PG_FUNCTION_INFO_V1(complex_add);
00122 
00123 Datum
00124 complex_add(PG_FUNCTION_ARGS)
00125 {
00126     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00127     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00128     Complex    *result;
00129 
00130     result = (Complex *) palloc(sizeof(Complex));
00131     result->x = a->x + b->x;
00132     result->y = a->y + b->y;
00133     PG_RETURN_POINTER(result);
00134 }
00135 
00136 
00137 /*****************************************************************************
00138  * Operator class for defining B-tree index
00139  *
00140  * It's essential that the comparison operators and support function for a
00141  * B-tree index opclass always agree on the relative ordering of any two
00142  * data values.  Experience has shown that it's depressingly easy to write
00143  * unintentionally inconsistent functions.  One way to reduce the odds of
00144  * making a mistake is to make all the functions simple wrappers around
00145  * an internal three-way-comparison function, as we do here.
00146  *****************************************************************************/
00147 
00148 #define Mag(c)  ((c)->x*(c)->x + (c)->y*(c)->y)
00149 
00150 static int
00151 complex_abs_cmp_internal(Complex * a, Complex * b)
00152 {
00153     double      amag = Mag(a),
00154                 bmag = Mag(b);
00155 
00156     if (amag < bmag)
00157         return -1;
00158     if (amag > bmag)
00159         return 1;
00160     return 0;
00161 }
00162 
00163 
00164 PG_FUNCTION_INFO_V1(complex_abs_lt);
00165 
00166 Datum
00167 complex_abs_lt(PG_FUNCTION_ARGS)
00168 {
00169     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00170     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00171 
00172     PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0);
00173 }
00174 
00175 PG_FUNCTION_INFO_V1(complex_abs_le);
00176 
00177 Datum
00178 complex_abs_le(PG_FUNCTION_ARGS)
00179 {
00180     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00181     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00182 
00183     PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) <= 0);
00184 }
00185 
00186 PG_FUNCTION_INFO_V1(complex_abs_eq);
00187 
00188 Datum
00189 complex_abs_eq(PG_FUNCTION_ARGS)
00190 {
00191     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00192     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00193 
00194     PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) == 0);
00195 }
00196 
00197 PG_FUNCTION_INFO_V1(complex_abs_ge);
00198 
00199 Datum
00200 complex_abs_ge(PG_FUNCTION_ARGS)
00201 {
00202     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00203     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00204 
00205     PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) >= 0);
00206 }
00207 
00208 PG_FUNCTION_INFO_V1(complex_abs_gt);
00209 
00210 Datum
00211 complex_abs_gt(PG_FUNCTION_ARGS)
00212 {
00213     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00214     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00215 
00216     PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) > 0);
00217 }
00218 
00219 PG_FUNCTION_INFO_V1(complex_abs_cmp);
00220 
00221 Datum
00222 complex_abs_cmp(PG_FUNCTION_ARGS)
00223 {
00224     Complex    *a = (Complex *) PG_GETARG_POINTER(0);
00225     Complex    *b = (Complex *) PG_GETARG_POINTER(1);
00226 
00227     PG_RETURN_INT32(complex_abs_cmp_internal(a, b));
00228 }