From dbdf7e6b886d2f107661ce2f58f8d0924fceaea0 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sat, 28 Apr 2012 19:35:57 +0200 Subject: [PATCH] Added initial version of the CData data type. For now, the type provides simple input and output functions only. --- src/Makefile.pgxs.in | 1 + src/cdata.c | 180 +++++++++++++++++++++++++++++++++++++++++++ src/postrr.h.in | 19 +++++ src/postrr.sql.in | 29 +++++++ 4 files changed, 229 insertions(+) create mode 100644 src/cdata.c diff --git a/src/Makefile.pgxs.in b/src/Makefile.pgxs.in index 0ccc4f1..f223061 100644 --- a/src/Makefile.pgxs.in +++ b/src/Makefile.pgxs.in @@ -28,6 +28,7 @@ MODULE_big=postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@ MODULEDIR=contrib/$(MODULE) PG_OBJS=base.o \ + cdata.o \ rrtimeslice.o \ utils/pg_spi.o diff --git a/src/cdata.c b/src/cdata.c new file mode 100644 index 0000000..b929e3a --- /dev/null +++ b/src/cdata.c @@ -0,0 +1,180 @@ +/* + * PostRR - src/cdata.c + * Copyright (C) 2012 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A PostgreSQL data-type providing consolidated data points. + */ + +#include "postrr.h" + +#include + +#include +#include + +/* Postgres utilities */ +#include + +/* + * data type + */ + +struct cdata { + double value; + int32 undef_num; + int32 val_num; + int32 cf; +}; + +/* + * prototypes for PostgreSQL functions + */ + +PG_FUNCTION_INFO_V1(cdata_validate); + +PG_FUNCTION_INFO_V1(cdata_in); +PG_FUNCTION_INFO_V1(cdata_out); +PG_FUNCTION_INFO_V1(cdata_typmodin); +PG_FUNCTION_INFO_V1(cdata_typmodout); + +PG_FUNCTION_INFO_V1(cdata_to_cdata); + +/* + * public API + */ + +Datum +cdata_validate(PG_FUNCTION_ARGS) +{ + char type_info[1024]; + char *result; + size_t req_len; + size_t len; + + if (PG_NARGS() != 1) + ereport(ERROR, ( + errmsg("cdata_validate() expect one argument"), + errhint("Usage cdata_validate(expected_size)") + )); + + req_len = (size_t)PG_GETARG_UINT32(0); + len = sizeof(cdata_t); + + if (req_len != len) + ereport(ERROR, ( + errmsg("length of the cdata type " + "does not match the expected length"), + errhint("Please report a bug against PostRR") + )); + + snprintf(type_info, sizeof(type_info), + "cdata validated successfully; type length = %zu", len); + type_info[sizeof(type_info) - 1] = '\0'; + + result = pstrdup(type_info); + PG_RETURN_CSTRING(result); +} /* cdata_validate */ + +Datum +cdata_in(PG_FUNCTION_ARGS) +{ + cdata_t *data; + int32 typmod; + + char *val_str, *orig; + char *endptr = NULL; + + if (PG_NARGS() != 3) + ereport(ERROR, ( + errmsg("cdata_in() expects three arguments"), + errhint("Usage: cdata_in(col_name, oid, typmod)") + )); + + data = (cdata_t *)palloc0(sizeof(*data)); + + val_str = PG_GETARG_CSTRING(0); + typmod = PG_GETARG_INT32(2); + + orig = val_str; + while ((*val_str != '\0') && isspace((int)*val_str)) + ++val_str; + + if (*val_str == '\0') + ereport(ERROR, ( + errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cdata: \"%s\"", orig) + )); + + errno = 0; + data->value = strtod(val_str, &endptr); + data->val_num = 1; + + if ((endptr == val_str) || errno) + ereport(ERROR, ( + errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cdata: \"%s\"", orig) + )); + + while ((*endptr != '\0') && isspace((int)*endptr)) + ereport(ERROR, ( + errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cdata: \"%s\"", orig) + )); + + if (typmod > 0) + data->cf = typmod; + else + data->cf = 0; + + PG_RETURN_RRTIMESLICE_P(data); +} /* cdata_in */ + +Datum +cdata_out(PG_FUNCTION_ARGS) +{ + cdata_t *data; + + char cd_str[1024]; + char *result; + + if (PG_NARGS() != 1) + ereport(ERROR, ( + errmsg("cdata_out() expects one argument"), + errhint("Usage: cdata_out(cdata)") + )); + + data = PG_GETARG_CDATA_P(0); + + snprintf(cd_str, sizeof(cd_str), "%g (U:%i/%i)", + data->value, data->undef_num, data->val_num); + + result = pstrdup(cd_str); + PG_RETURN_CSTRING(result); +} /* cdata_out */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/postrr.h.in b/src/postrr.h.in index 3db5045..b2c9ad2 100644 --- a/src/postrr.h.in +++ b/src/postrr.h.in @@ -102,6 +102,25 @@ rrtimeslice_cmp(PG_FUNCTION_ARGS); int rrtimeslice_cmp_internal(rrtimeslice_t *ts1, rrtimeslice_t *ts2); +/* + * CData data type + */ + +struct cdata; +typedef struct cdata cdata_t; + +#define PG_GETARG_CDATA_P(n) (cdata_t *)PG_GETARG_POINTER(n) +#define PG_RETURN_CDATA_P(p) PG_RETURN_POINTER(p) + +Datum +cdata_validate(PG_FUNCTION_ARGS); + +/* I/O functions */ +Datum +cdata_in(PG_FUNCTION_ARGS); +Datum +cdata_out(PG_FUNCTION_ARGS); + #endif /* ! POSTRR_H */ /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/postrr.sql.in b/src/postrr.sql.in index bc0d20a..22ce15c 100644 --- a/src/postrr.sql.in +++ b/src/postrr.sql.in @@ -198,6 +198,35 @@ CREATE OPERATOR CLASS rrtimeslice_ops OPERATOR 5 > , FUNCTION 1 RRTimeslice_cmp(rrtimeslice, rrtimeslice); +CREATE TYPE CData; + +CREATE OR REPLACE FUNCTION CData_validate(integer) + RETURNS cstring + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_validate' + LANGUAGE 'C' IMMUTABLE STRICT; + +-- this will abort the transaction in case the expected internal length does +-- not match the actual length +SELECT CData_validate(24); + +CREATE OR REPLACE FUNCTION CData_in(cstring, oid, integer) + RETURNS CData + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_in' + LANGUAGE 'C' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION CData_out(CData) + RETURNS cstring + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_out' + LANGUAGE 'C' IMMUTABLE STRICT; + +CREATE TYPE CData ( + INTERNALLENGTH = 24, + INPUT = CData_in, + OUTPUT = CData_out, + ALIGNMENT = double, + STORAGE = plain +); + COMMIT; SET client_min_messages TO DEFAULT; -- 2.30.2