1 /* 2 * src/tutorial/complex.c 3 * 4 ****************************************************************************** 5 This file contains routines that can be bound to a Postgres backend and 6 called by the backend in the process of processing queries. The calling 7 format for these routines is dictated by Postgres architecture. 8 ******************************************************************************/ 9 10 #include "postgres.h" 11 12 #include "fmgr.h" 13 #include "libpq/pqformat.h" /* needed for send/recv functions */ 14 15 PG_MODULE_MAGIC; 16 17 typedef struct Complex 18 { 19 double x; 20 double y; 21 } Complex; 22 23 24 /***************************************************************************** 25 * Input/Output functions 26 *****************************************************************************/ 27 28 PG_FUNCTION_INFO_V1(complex_in); 29 30 Datum 31 complex_in(PG_FUNCTION_ARGS) 32 { 33 char *str = PG_GETARG_CSTRING(0); 34 double x, 35 y; 36 Complex *result; 37 38 if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) 39 ereport(ERROR, 40 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 41 errmsg("invalid input syntax for type %s: \"%s\"", 42 "complex", str))); 43 44 result = (Complex *) palloc(sizeof(Complex)); 45 result->x = x; 46 result->y = y; 47 PG_RETURN_POINTER(result); 48 } 49 50 PG_FUNCTION_INFO_V1(complex_out); 51 52 Datum 53 complex_out(PG_FUNCTION_ARGS) 54 { 55 Complex *complex = (Complex *) PG_GETARG_POINTER(0); 56 char *result; 57 58 result = psprintf("(%g,%g)", complex->x, complex->y); 59 PG_RETURN_CSTRING(result); 60 } 61 62 /***************************************************************************** 63 * Binary Input/Output functions 64 * 65 * These are optional. 66 *****************************************************************************/ 67 68 PG_FUNCTION_INFO_V1(complex_recv); 69 70 Datum 71 complex_recv(PG_FUNCTION_ARGS) 72 { 73 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); 74 Complex *result; 75 76 result = (Complex *) palloc(sizeof(Complex)); 77 result->x = pq_getmsgfloat8(buf); 78 result->y = pq_getmsgfloat8(buf); 79 PG_RETURN_POINTER(result); 80 } 81 82 PG_FUNCTION_INFO_V1(complex_send); 83 84 Datum 85 complex_send(PG_FUNCTION_ARGS) 86 { 87 Complex *complex = (Complex *) PG_GETARG_POINTER(0); 88 StringInfoData buf; 89 90 pq_begintypsend(&buf); 91 pq_sendfloat8(&buf, complex->x); 92 pq_sendfloat8(&buf, complex->y); 93 PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 94 } 95 96 /***************************************************************************** 97 * New Operators 98 * 99 * A practical Complex datatype would provide much more than this, of course. 100 *****************************************************************************/ 101 102 PG_FUNCTION_INFO_V1(complex_add); 103 104 Datum 105 complex_add(PG_FUNCTION_ARGS) 106 { 107 Complex *a = (Complex *) PG_GETARG_POINTER(0); 108 Complex *b = (Complex *) PG_GETARG_POINTER(1); 109 Complex *result; 110 111 result = (Complex *) palloc(sizeof(Complex)); 112 result->x = a->x + b->x; 113 result->y = a->y + b->y; 114 PG_RETURN_POINTER(result); 115 } 116 117 118 /***************************************************************************** 119 * Operator class for defining B-tree index 120 * 121 * It's essential that the comparison operators and support function for a 122 * B-tree index opclass always agree on the relative ordering of any two 123 * data values. Experience has shown that it's depressingly easy to write 124 * unintentionally inconsistent functions. One way to reduce the odds of 125 * making a mistake is to make all the functions simple wrappers around 126 * an internal three-way-comparison function, as we do here. 127 *****************************************************************************/ 128 129 #define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y) 130 131 static int 132 complex_abs_cmp_internal(Complex * a, Complex * b) 133 { 134 double amag = Mag(a), 135 bmag = Mag(b); 136 137 if (amag < bmag) 138 return -1; 139 if (amag > bmag) 140 return 1; 141 return 0; 142 } 143 144 145 PG_FUNCTION_INFO_V1(complex_abs_lt); 146 147 Datum 148 complex_abs_lt(PG_FUNCTION_ARGS) 149 { 150 Complex *a = (Complex *) PG_GETARG_POINTER(0); 151 Complex *b = (Complex *) PG_GETARG_POINTER(1); 152 153 PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0); 154 } 155 156 PG_FUNCTION_INFO_V1(complex_abs_le); 157 158 Datum 159 complex_abs_le(PG_FUNCTION_ARGS) 160 { 161 Complex *a = (Complex *) PG_GETARG_POINTER(0); 162 Complex *b = (Complex *) PG_GETARG_POINTER(1); 163 164 PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) <= 0); 165 } 166 167 PG_FUNCTION_INFO_V1(complex_abs_eq); 168 169 Datum 170 complex_abs_eq(PG_FUNCTION_ARGS) 171 { 172 Complex *a = (Complex *) PG_GETARG_POINTER(0); 173 Complex *b = (Complex *) PG_GETARG_POINTER(1); 174 175 PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) == 0); 176 } 177 178 PG_FUNCTION_INFO_V1(complex_abs_ge); 179 180 Datum 181 complex_abs_ge(PG_FUNCTION_ARGS) 182 { 183 Complex *a = (Complex *) PG_GETARG_POINTER(0); 184 Complex *b = (Complex *) PG_GETARG_POINTER(1); 185 186 PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) >= 0); 187 } 188 189 PG_FUNCTION_INFO_V1(complex_abs_gt); 190 191 Datum 192 complex_abs_gt(PG_FUNCTION_ARGS) 193 { 194 Complex *a = (Complex *) PG_GETARG_POINTER(0); 195 Complex *b = (Complex *) PG_GETARG_POINTER(1); 196 197 PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) > 0); 198 } 199 200 PG_FUNCTION_INFO_V1(complex_abs_cmp); 201 202 Datum 203 complex_abs_cmp(PG_FUNCTION_ARGS) 204 { 205 Complex *a = (Complex *) PG_GETARG_POINTER(0); 206 Complex *b = (Complex *) PG_GETARG_POINTER(1); 207 208 PG_RETURN_INT32(complex_abs_cmp_internal(a, b)); 209 } 210