#include "postgres.h" #include "fmgr.h" #include "libpq/pqformat.h" #ifndef TINY_MAX #define TINY_MAX (0xFF) #endif #ifndef PG_GETARG_UINT8 #define PG_GETARG_UINT8(n) DatumGetUInt8(PG_GETARG_DATUM(n)) #endif #ifndef PG_RETURN_UINT8 #define PG_RETURN_UINT8(x) return UInt8GetDatum(x) #endif /* * DatumGetInt8 * Returns 8-bit integer value of a datum. */ #ifndef DatumGetInt8 #define DatumGetInt8(X) ((int8) GET_1_BYTE(X)) #endif /* * tinyintin - converts "num" to unsigned byte */ PG_FUNCTION_INFO_V1(utinyintin); Datum utinyintin(PG_FUNCTION_ARGS) { char *num = PG_GETARG_CSTRING(0); int32 res=pg_atoi(num, sizeof(int32), '\0'); /* As pg_atoi is signed, we get the number in a int32 and do our own bounds * checking. This results in an incorrect error if the number is bigger than * 2^31-1, or smaller than -2^31. The error message will say that the number * is too big for 32 bits, which is true but slightly misleading. * The alternative is to rewrite pg_atoi, which doesn't seem worth the trouble. */ if( res<0 || res>TINY_MAX ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type tinyint", num))); PG_RETURN_UINT8(res); } /* * tinyintout - converts unsigned byte to "num" */ PG_FUNCTION_INFO_V1(utinyintout); Datum utinyintout(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); char *result = (char *) palloc(4); /* no sign, 3 digits, '\0' */ pg_itoa(arg1, result); PG_RETURN_CSTRING(result); } /* * tinyintrecv - converts external binary format to tinyint */ PG_FUNCTION_INFO_V1(utinyintrecv); Datum utinyintrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_UINT8((uint8) pq_getmsgint(buf, sizeof(uint8))); } /* * tinyintsend - converts tinyint to binary format */ PG_FUNCTION_INFO_V1(utinyintsend); Datum utinyintsend(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendint(&buf, arg1, sizeof(uint8)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } PG_FUNCTION_INFO_V1(utinytoi2); Datum utinytoi2(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); PG_RETURN_INT16((int16) arg1); } PG_FUNCTION_INFO_V1(utinytoi4); Datum utinytoi4(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); PG_RETURN_INT32((int32) arg1); } PG_FUNCTION_INFO_V1(i2toutiny); Datum i2toutiny(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); if (arg1 < 0 || arg1 > TINY_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_UINT8((uint8) arg1); } PG_FUNCTION_INFO_V1(i4toutiny); Datum i4toutiny(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); if (arg1 < 0 || arg1 > TINY_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_UINT8((uint8) arg1); } PG_FUNCTION_INFO_V1(utinyint_text); Datum utinyint_text(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); text *result = (text *) palloc(4 + VARHDRSZ); /* no sign,4 digits, '\0' */ pg_itoa(arg1, VARDATA(result)); VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ; PG_RETURN_TEXT_P(result); } PG_FUNCTION_INFO_V1(text_utinyint); Datum text_utinyint(PG_FUNCTION_ARGS) { text *string = PG_GETARG_TEXT_P(0); Datum result; int len; char *str; len = VARSIZE(string) - VARHDRSZ; str = palloc(len + 1); memcpy(str, VARDATA(string), len); *(str + len) = '\0'; result = DirectFunctionCall1(utinyintin, CStringGetDatum(str)); pfree(str); return result; } /* Comparation functions */ PG_FUNCTION_INFO_V1(utinyinteq); Datum utinyinteq(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); uint8 arg2 = PG_GETARG_UINT8(1); PG_RETURN_BOOL(arg1 == arg2); } PG_FUNCTION_INFO_V1(utinyintne); Datum utinyintne(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); uint8 arg2 = PG_GETARG_UINT8(1); PG_RETURN_BOOL(arg1 != arg2); } PG_FUNCTION_INFO_V1(utinyintlt); Datum utinyintlt(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); uint8 arg2 = PG_GETARG_UINT8(1); PG_RETURN_BOOL(arg1 < arg2); } PG_FUNCTION_INFO_V1(utinyintle); Datum utinyintle(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); uint8 arg2 = PG_GETARG_UINT8(1); PG_RETURN_BOOL(arg1 <= arg2); } PG_FUNCTION_INFO_V1(utinyintgt); Datum utinyintgt(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); uint8 arg2 = PG_GETARG_UINT8(1); PG_RETURN_BOOL(arg1 > arg2); } PG_FUNCTION_INFO_V1(utinyintge); Datum utinyintge(PG_FUNCTION_ARGS) { uint8 arg1 = PG_GETARG_UINT8(0); uint8 arg2 = PG_GETARG_UINT8(1); PG_RETURN_BOOL(arg1 >= arg2); } PG_FUNCTION_INFO_V1(btutinyintcmp); Datum btutinyintcmp(PG_FUNCTION_ARGS) { uint8 a=PG_GETARG_UINT8(0); uint8 b=PG_GETARG_UINT8(1); if(a>b) PG_RETURN_INT32(1); else if (a==b) PG_RETURN_INT32(0); else PG_RETURN_INT32(-1); } PG_FUNCTION_INFO_V1(hashutinyint); Datum hashutinyint(PG_FUNCTION_ARGS) { PG_RETURN_UINT32(~PG_GETARG_UINT8(0)); }