/* * src/common/tutorial/complex.cpp * ****************************************************************************** This file contains routines that can be bound to a openGauss backend and called by the backend in the process of processing queries. The calling format for these routines is dictated by openGauss architecture. ******************************************************************************/ #include "postgres.h" #include "knl/knl_variable.h" #include "fmgr.h" #include "libpq/pqformat.h" /* needed for send/recv functions */ PG_MODULE_MAGIC; typedef struct Complex { double x; double y; } Complex; /* * 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 *****************************************************************************/ PG_FUNCTION_INFO_V1(complex_in); Datum complex_in(PG_FUNCTION_ARGS) { char* str = PG_GETARG_CSTRING(0); double x, y; Complex* result = NULL; if (sscanf_s(str, " ( %lf , %lf )", &x, &y) != 2) { ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for complex: \"%s\"", 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 = NULL; result = (char*)palloc(100); int rc = snprintf_s(result, 100, 99, "(%g,%g)", complex->x, complex->y); securec_check_ss(rc, "\0", "\0"); 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 = NULL; 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 = NULL; 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); double 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)); }