#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));
}