[BACK]Return to uint.c CVS log [TXT][DIR] Up to [pgFoundry] / uint / uint

File: [pgFoundry] / uint / uint / uint.c (download)

Revision 1.1, Mon Sep 29 04:53:59 2008 UTC (23 months ago) by rbrad
Branch: MAIN
CVS Tags: HEAD

Initial checking for the unsigned integer data type.

#include "postgres.h"
#include "fmgr.h"
#include "libpq/pqformat.h"
#include "access/hash.h"

#include "utils/selfuncs.h"
#include "utils/syscache.h"
#include "utils/lsyscache.h"
#include "catalog/pg_statistic.h"

#include <stdlib.h>
#include <limits.h>

#define PG_GETARG_UINT8(n) DatumGetUInt8(PG_GETARG_DATUM(n))
#define PG_RETURN_UINT8(x) return UInt8GetDatum(x)
#define PG_RETURN_UINT16(x) return UInt16GetDatum(x)

#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
#   define likely(x) __builtin_expect((x),1)
#   define unlikely(x) __builtin_expect((x),0)
#else
#   define likely(x) (x)
#   define unlikely(x) (x)
#endif

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

/*
 *  ==================
 *  UINT1 DECLARATIONS
 *  ==================
 */
Datum uint1in(PG_FUNCTION_ARGS);
Datum uint1out(PG_FUNCTION_ARGS);
Datum uint1recv(PG_FUNCTION_ARGS);
Datum uint1send(PG_FUNCTION_ARGS);
Datum btuint1cmp(PG_FUNCTION_ARGS);
Datum uint1eq(PG_FUNCTION_ARGS);
Datum uint1ne(PG_FUNCTION_ARGS);
Datum uint1lt(PG_FUNCTION_ARGS);
Datum uint1le(PG_FUNCTION_ARGS);
Datum uint1gt(PG_FUNCTION_ARGS);
Datum uint1ge(PG_FUNCTION_ARGS);
Datum int4uint1eq(PG_FUNCTION_ARGS);
Datum uint1and(PG_FUNCTION_ARGS);
Datum uint1or(PG_FUNCTION_ARGS);
Datum uint1xor(PG_FUNCTION_ARGS);
Datum uint1not(PG_FUNCTION_ARGS);
Datum uint1shl(PG_FUNCTION_ARGS);
Datum uint1shr(PG_FUNCTION_ARGS);
Datum hashuint1(PG_FUNCTION_ARGS);
Datum int4touint1(PG_FUNCTION_ARGS);
Datum uint1toint4(PG_FUNCTION_ARGS);


/*
 *  =====================
 *  UINT1 PUBLIC ROUTINES
 *  =====================
 */
PG_FUNCTION_INFO_V1(uint1in);
PG_FUNCTION_INFO_V1(uint1out);
PG_FUNCTION_INFO_V1(uint1recv);
PG_FUNCTION_INFO_V1(uint1send);

/**
 * Convert a c-string into a value suitable for the uint1 datatype.
 *
 * @param  s The c-string representation.
 * @return   The Datum containing the converted uint1 value.
 */
Datum
uint1in(PG_FUNCTION_ARGS)
{
   char *badp;
   unsigned long ul;
   char *s = PG_GETARG_CSTRING(0);

   /* Check for NULL pointer. */
   if(unlikely(s == NULL)) {
      elog(ERROR, "NULL pointer");
   }

   /*
    * Some versions of strtoul treat the empty string as an error, but some
    * seem not to.  Make an explicit test to be sure we catch it.
    */
   if(unlikely(*s == 0)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   errno = 0;
   ul = strtoul(s, &badp, 10);

   /* We made no progress parsing the string, so bail out */
   if(unlikely(s == badp)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   /* Verify value is valid in the uint1 datatype range. */
   if(unlikely(errno == ERANGE || ul < 0 || ul > UCHAR_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
              errmsg("value \"%s\" is out of range for unsigned 8-bit integer", s)));
   }

   /*
    * Skip any trailing whitespace; if anything but whitespace remains before
    * the terminating character, bail out
    */
   while(*badp && isspace((unsigned char)*badp)) {
      badp++;
   }

   /* Verify the c-string is empty. */
   if(unlikely(*badp)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   PG_RETURN_UINT8((unsigned char)ul);
}

/**
 * Convert the uint1 value into a c-string.
 *
 * @param  num The uint1 value.
 * @return     The Datum containing the converted uint1 value.
 */
Datum
uint1out(PG_FUNCTION_ARGS)
{
   uint8 num = PG_GETARG_UINT8(0);
   char *str = (char *) palloc(5);

   snprintf(str, 5, "%u", num);
   PG_RETURN_CSTRING(str);
}

/**
 * Convert the binary represented value	into a value suitable for
 * the uint1 datatype.
 *
 * @param  buf The uint1 value.
 * @return     The Datum containing the converted uint1 value.
 */
Datum
uint1recv(PG_FUNCTION_ARGS)
{
   StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
   PG_RETURN_UINT8((uint8)pq_getmsgint(buf, sizeof(uint8)));
}

/**
 * Convert the uint1 datatype into its binary representation.
 *
 * @param  num The uint1 value.
 * @return     The Datum containing the converted uint1 value.
 */
Datum
uint1send(PG_FUNCTION_ARGS)
{
   uint8 num = PG_GETARG_UINT8(0);
   StringInfoData buf;

   pq_begintypsend(&buf);
   pq_sendint(&buf, num, sizeof(uint8));
   PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

/*
 *  ==================================
 *  UINT1 COMPARISON OPERATOR ROUTINES
 *  ==================================
 */

PG_FUNCTION_INFO_V1(btuint1cmp);

/**
 * Comparison function used by the B-tree index for sorting purposes.
 *
 * It is safe to directly subtract the values in this function because
 * the return value can not overflow a signed 32-bit integer.
 *
 * @param  a The first uint1 value.
 * @param  b The second uint1 value.
 * @return The Datum containing the comparison value.
 *         The comparison value is:
 *         < 0 if a < b
 *           0 if a == b
 *         > 0 if a > b
 */
Datum
btuint1cmp(PG_FUNCTION_ARGS)
{
   uint8 a = PG_GETARG_UINT8(0);
   uint8 b = PG_GETARG_UINT8(1);

   PG_RETURN_INT32((int32)a - (int32)b);
}

PG_FUNCTION_INFO_V1(uint1eq);
PG_FUNCTION_INFO_V1(uint1ne);
PG_FUNCTION_INFO_V1(uint1lt);
PG_FUNCTION_INFO_V1(uint1le);
PG_FUNCTION_INFO_V1(uint1gt);
PG_FUNCTION_INFO_V1(uint1ge);
PG_FUNCTION_INFO_V1(uint1int4eq);

/**
 * This function implements the "equal" (=) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2
 *         false if arg1 != arg2
 */
Datum
uint1eq(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 == arg2);
}

/**
 * This function implements the "not equal" (<>) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 != arg2
 *         false if arg1 == arg2
 */
Datum
uint1ne(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 != arg2);
}

/**
 * This function implements the "less than" (<) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 < arg2
 *         false if arg1 >= arg2
 */
Datum
uint1lt(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 < arg2);
}

/**
 * This function implements the "less than or equal" (<=) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 <= arg2
 *         false if arg1 > arg2
 */
Datum
uint1le(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 <= arg2);
}

/**
 * This function implements the "greater than" (>) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 > arg2
 *         false if arg1 <= arg2
 */
Datum
uint1gt(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 > arg2);
}

/**
 * This function implements the "greater than or equal" (>=) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 >= arg2
 *         false if arg1 < arg2
 */
Datum
uint1ge(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 >= arg2);
}

/**
 * This function implements the "equal" (=) operator between the int4
 * and uint1 data types.  
 *
 * This function is required to support hash joins for the uint1 data
 * type when the one argument is an int4 data type.
 *
 * Example query:
 *   SELECT t.u1 FROM test t, generate_series(1, 10) gs WHERE t.u1 = gs;
 *
 * XXX
 * RBRAD TODO: test and make sure this works.
 * XXX
 *
 * @param  arg1 The int32 value.
 * @param  arg2 The uint1 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2 
 *         false if arg1 != arg2
 */
Datum
int4uint1eq(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_BOOL(arg1 == (int32)arg2);
}


/*
 *  ============================
 *  UINT1 BIT OPERATION ROUTINES
 *  ============================
 */
PG_FUNCTION_INFO_V1(uint1and);
PG_FUNCTION_INFO_V1(uint1or);
PG_FUNCTION_INFO_V1(uint1xor);
PG_FUNCTION_INFO_V1(uint1not);
PG_FUNCTION_INFO_V1(uint1shl);
PG_FUNCTION_INFO_V1(uint1shr);

/**
 * This function implements the bit-wise AND (&) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the new value.
 */
Datum
uint1and(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_UINT8(arg1 & arg2);
}

/**
 * This function implements the bit-wise OR (|) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the new value.
 */
Datum
uint1or(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_UINT8(arg1 | arg2);
}

/**
 * This function implements the bit-wise XOR (#) operator for the uint1 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint1 datatypes.
 *
 * @param  arg1 The first uint1 value.
 * @param  arg2 The second uint1 value.
 * @return The Datum containing the new value.
 */
Datum
uint1xor(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   uint8 arg2 = PG_GETARG_UINT8(1);

   PG_RETURN_UINT8(arg1 ^ arg2);
}

/**
 * This function implements the compliment (~) operator for the uint1 datatype.
 *
 * @param  arg1 The uint1 value.
 * @return The Datum containing the new value.
 */
Datum
uint1not(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);

   PG_RETURN_UINT8(~arg1);
}

/**
 * This function implements the "shift left" (<<) operator for the uint1 datatype.
 *
 * @param  arg1 The uint1 value.
 * @param  arg2 The number of bits to shift.
 * @return The Datum containing the new value.
 */
Datum
uint1shl(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_UINT8(arg1 << arg2);
}

/**
 * This function implements the "shift right" (>>) operator for the uint1 datatype.
 *
 * @param  arg1 The uint1 value.
 * @param  arg2 The number of bits to shift.
 * @return The Datum containing the new value.
 */
Datum
uint1shr(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_UINT8(arg1 >> arg2);
}


/*
 *  ============================
 *  UINT1 HASH OPERATOR ROUTINES
 *  ============================
 */
PG_FUNCTION_INFO_V1(hashuint1);

/**
 * This function returns a hash value suitable for the hash index.
 *
 * @param  arg1 The uint1 value.
 * @return      The Datum containing the hash value.
 */
Datum
hashuint1(PG_FUNCTION_ARGS)
{
   uint8 arg1 = PG_GETARG_UINT8(0);
 
   return hash_uint32((uint32) arg1);
}


/*
 *  =========================
 *  UINT1 CONVERSION ROUTINES
 *  =========================
 */
PG_FUNCTION_INFO_V1(int4touint1);
PG_FUNCTION_INFO_V1(uint1toint4);

/**
 * Cast an int4 value into a uint1 value.
 * This function throws an error if the int4 value is out-of-range
 * for the uint1 value.
 *
 * @param  num The int4 value.
 * @return     The Datum containing the uint1 value.
 */
Datum
int4touint1(PG_FUNCTION_ARGS)
{
   int32 num = PG_GETARG_INT32(0);

   if(unlikely(num < 0 || num > UCHAR_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                      errmsg("uint1 out of range")));
   }

   PG_RETURN_UINT8((uint8) num);
}

/**
 * Cast a uint1 value into an int4 value.
 * 
 * @param  num The uint1 value.
 * @return     The Datum containing the int4 value.
 */
Datum
uint1toint4(PG_FUNCTION_ARGS)
{
   uint8 num = PG_GETARG_UINT8(0);

   PG_RETURN_INT32((int32) num);
}


/*
 *  ==================
 *  UINT2 DECLARATIONS
 *  ==================
 */
Datum uint2in(PG_FUNCTION_ARGS);
Datum uint2out(PG_FUNCTION_ARGS);
Datum uint2recv(PG_FUNCTION_ARGS);
Datum uint2send(PG_FUNCTION_ARGS);
Datum btuint2cmp(PG_FUNCTION_ARGS);
Datum uint2eq(PG_FUNCTION_ARGS);
Datum uint2ne(PG_FUNCTION_ARGS);
Datum uint2lt(PG_FUNCTION_ARGS);
Datum uint2le(PG_FUNCTION_ARGS);
Datum uint2gt(PG_FUNCTION_ARGS);
Datum uint2ge(PG_FUNCTION_ARGS);
Datum int4uint2eq(PG_FUNCTION_ARGS);
Datum uint2and(PG_FUNCTION_ARGS);
Datum uint2or(PG_FUNCTION_ARGS);
Datum uint2xor(PG_FUNCTION_ARGS);
Datum uint2not(PG_FUNCTION_ARGS);
Datum uint2shl(PG_FUNCTION_ARGS);
Datum uint2shr(PG_FUNCTION_ARGS);
Datum hashuint2(PG_FUNCTION_ARGS);
Datum int4touint2(PG_FUNCTION_ARGS);
Datum uint2toint4(PG_FUNCTION_ARGS);


/*
 *  =====================
 *  UINT2 PUBLIC ROUTINES
 *  =====================
 */
PG_FUNCTION_INFO_V1(uint2in);
PG_FUNCTION_INFO_V1(uint2out);
PG_FUNCTION_INFO_V1(uint2recv);
PG_FUNCTION_INFO_V1(uint2send);

/**
 * Convert a c-string into a value suitable for the uint2 datatype.
 *
 * @param  s The c-string representation.
 * @return   The Datum containing the converted uint2 value.
 */
Datum
uint2in(PG_FUNCTION_ARGS)
{
   char *badp;
   unsigned long ul;
   char *s = PG_GETARG_CSTRING(0);

   /* Check for NULL pointer. */
   if(unlikely(s == NULL)) {
      elog(ERROR, "NULL pointer");
   }

   /*
    * Some versions of strtoul treat the empty string as an error, but some
    * seem not to.  Make an explicit test to be sure we catch it.
    */
   if(unlikely(*s == 0)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   errno = 0;
   ul = strtoul(s, &badp, 10);

   /* We made no progress parsing the string, so bail out */
   if(unlikely(s == badp)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   /* Verify value is valid in the uint2 datatype range. */
   if(unlikely(errno == ERANGE || ul < 0 || ul > USHRT_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
              errmsg("value \"%s\" is out of range for type unsigned smallint", s)));
   }

   /*
    * Skip any trailing whitespace; if anything but whitespace remains before
    * the terminating character, bail out
    */
   while(*badp && isspace((unsigned char)*badp)) {
      badp++;
   }

   /* Verify the c-string is empty. */
   if(unlikely(*badp)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   PG_RETURN_UINT16((uint16)ul);
}

/**
 * Convert the uint2 value into a c-string.
 *
 * @param  num The uint2 value.
 * @return     The Datum containing the converted uint2 value.
 */
Datum
uint2out(PG_FUNCTION_ARGS)
{
   uint16 num = PG_GETARG_UINT16(0);
   char *str = (char *) palloc(7);

   snprintf(str, 7, "%u", num);
   PG_RETURN_CSTRING(str);
}

/**
 * Convert the binary represented value into a value suitable for
 * the uint2 datatype.
 *
 * @param  buf The uint2 value.
 * @return     The Datum containing the converted uint2 value.
 */
Datum
uint2recv(PG_FUNCTION_ARGS)
{
   StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
   PG_RETURN_UINT16((uint16) pq_getmsgint(buf, sizeof(uint16)));
}

/**
 * Convert the uint2 datatype into its binary representation.
 *
 * @param  num The uint2 value.
 * @return     The Datum containing the converted uint2 value.
 */
Datum
uint2send(PG_FUNCTION_ARGS)
{
   uint16 num = PG_GETARG_UINT16(0);
   StringInfoData buf;

   pq_begintypsend(&buf);
   pq_sendint(&buf, num, sizeof(uint16));
   PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}


/*
 *  ==================================
 *  UINT2 COMPARISON OPERATOR ROUTINES
 *  ==================================
 */

PG_FUNCTION_INFO_V1(btuint2cmp);

/**
 * Comparison function used by the B-tree index for sorting purposes.
 *
 * It is safe to directly subtract the values in this function because
 * the return value can not overflow a signed 32-bit integer.
 *
 * @param  a The first uint2 value.
 * @param  b The second uint2 value.
 * @return The Datum containing the comparison value.
 *         The comparison value is:
 *         < 0 if a < b
 *           0 if a == b
 *         > 0 if a > b
 */
Datum
btuint2cmp(PG_FUNCTION_ARGS)
{
   uint16 a = PG_GETARG_UINT16(0);
   uint16 b = PG_GETARG_UINT16(1);

   PG_RETURN_INT32((int32)a - (int32)b);
}

PG_FUNCTION_INFO_V1(uint2eq);
PG_FUNCTION_INFO_V1(uint2ne);
PG_FUNCTION_INFO_V1(uint2lt);
PG_FUNCTION_INFO_V1(uint2le);
PG_FUNCTION_INFO_V1(uint2gt);
PG_FUNCTION_INFO_V1(uint2ge);
PG_FUNCTION_INFO_V1(uint2int4eq);

/**
 * This function implements the "equal" (=) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2
 *         false if arg1 != arg2
 */
Datum
uint2eq(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 == arg2);
}

/**
 * This function implements the "not equal" (<>) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 != arg2
 *         false if arg1 == arg2
 */
Datum
uint2ne(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 != arg2);
}

/**
 * This function implements the "less than" (<) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 < arg2
 *         false if arg1 >= arg2
 */
Datum
uint2lt(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 < arg2);
}

/**
 * This function implements the "less than or equal" (<=) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 <= arg2
 *         false if arg1 > arg2
 */
Datum
uint2le(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 <= arg2);
}

/**
 * This function implements the "greater than" (>) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 > arg2
 *         false if arg1 <= arg2
 */
Datum
uint2gt(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 > arg2);
}

/**
 * This function implements the "greater than or equal" (>=) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 >= arg2
 *         false if arg1 < arg2
 */
Datum
uint2ge(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 >= arg2);
}

/**
 * This function implements the "equal" (=) operator between the int4
 * and uint2 data types.
 *
 * This function is required to support hash joins for the uint2 data
 * type when the one argument is an int2 data type.
 *
 * Example query:
 *   SELECT t.u2 FROM test t, generate_series(1, 10) gs WHERE t.u2 = gs;
 *
 * XXX
 * RBRAD TODO: test and make sure this works.
 * XXX
 *
 * @param  arg1 The int32 value.
 * @param  arg2 The uint2 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2
 *         false if arg1 != arg2
 */
Datum
int4uint2eq(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_BOOL(arg1 == (int32)arg2);
}


/*
 *  ============================
 *  UINT2 BIT OPERATION ROUTINES
 *  ============================
 */
PG_FUNCTION_INFO_V1(uint2and);
PG_FUNCTION_INFO_V1(uint2or);
PG_FUNCTION_INFO_V1(uint2xor);
PG_FUNCTION_INFO_V1(uint2not);
PG_FUNCTION_INFO_V1(uint2shl);
PG_FUNCTION_INFO_V1(uint2shr);

/**
 * This function implements the bit-wise AND (&) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the new value.
 */
Datum
uint2and(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_UINT16(arg1 & arg2);
}

/**
 * This function implements the bit-wise OR (|) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the new value.
 */
Datum
uint2or(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_UINT16(arg1 | arg2);
}

/**
 * This function implements the bit-wise XOR (#) operator for the uint2 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint2 datatypes.
 *
 * @param  arg1 The first uint2 value.
 * @param  arg2 The second uint2 value.
 * @return The Datum containing the new value.
 */
Datum
uint2xor(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   uint16 arg2 = PG_GETARG_UINT16(1);

   PG_RETURN_UINT16(arg1 ^ arg2);
}

/**
 * This function implements the compliment (~) operator for the uint2 datatype.
 *
 * @param  arg1 The uint2 value.
 * @return The Datum containing the new value.
 */
Datum
uint2not(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);

   PG_RETURN_UINT16(~arg1);
}

/**
 * This function implements the "shift left" (<<) operator for the uint2 datatype.
 *
 * @param  arg1 The uint2 value.
 * @param  arg2 The number of bits to shift.
 * @return The Datum containing the new value.
 */
Datum
uint2shl(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   int32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_UINT16(arg1 << arg2);
}

/**
 * This function implements the "shift right" (>>) operator for the uint2 datatype.
 *
 * @param  arg1 The uint2 value.
 * @param  arg2 The number of bits to shift.
 * @return The Datum containing the new value.
 */
Datum
uint2shr(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_UINT16(arg1 >> arg2);
}


/*
 *  ============================
 *  UINT2 HASH OPERATOR ROUTINES
 *  ============================
 */
PG_FUNCTION_INFO_V1(hashuint2);

/**
 * This function returns a hash value suitable for the hash index.
 *
 * @param  arg1 The uint2 value.
 * @return      The Datum containing the hash value.
 */
Datum
hashuint2(PG_FUNCTION_ARGS)
{
   uint16 arg1 = PG_GETARG_UINT16(0);

   return hash_uint32((uint32) arg1);
}


/*
 *  =========================
 *  UINT2 CONVERSION ROUTINES
 *  =========================
 */
PG_FUNCTION_INFO_V1(int4touint2);
PG_FUNCTION_INFO_V1(uint2toint4);

/**
 * Cast an int4 value into a uint2 value.
 * This function throws an error if the int4 value is out-of-range
 * for the uint2 value.
 *
 * @param  num The int4 value.
 * @return     The Datum containing the uint2 value.
 */
Datum
int4touint2(PG_FUNCTION_ARGS)
{
   int32 num = PG_GETARG_INT32(0);

   if(unlikely(num < 0 || num > USHRT_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                      errmsg("unsigned smallint out of range")));
   }

   PG_RETURN_UINT16((uint16) num);
}

/**
 * Cast a uint2 value into an int4 value.
 *
 * @param  num The uint2 value.
 * @return     The Datum containing the int4 value.
 */
Datum
uint2toint4(PG_FUNCTION_ARGS)
{
   uint16 num = PG_GETARG_UINT16(0);

   PG_RETURN_INT32((int32) num);
}



/*
 *  ==================
 *  UINT4 DECLARATIONS
 *  ==================
 */
Datum uint4in(PG_FUNCTION_ARGS);
Datum uint4out(PG_FUNCTION_ARGS);
Datum uint4recv(PG_FUNCTION_ARGS);
Datum uint4send(PG_FUNCTION_ARGS);
Datum btuint4cmp(PG_FUNCTION_ARGS);
Datum uint4eq(PG_FUNCTION_ARGS);
Datum uint4ne(PG_FUNCTION_ARGS);
Datum uint4lt(PG_FUNCTION_ARGS);
Datum uint4le(PG_FUNCTION_ARGS);
Datum uint4gt(PG_FUNCTION_ARGS);
Datum uint4ge(PG_FUNCTION_ARGS);
Datum int4uint4eq(PG_FUNCTION_ARGS);
Datum int4uint4ne(PG_FUNCTION_ARGS);
Datum int4uint4lt(PG_FUNCTION_ARGS);
Datum int4uint4le(PG_FUNCTION_ARGS);
Datum int4uint4gt(PG_FUNCTION_ARGS);
Datum int4uint4ge(PG_FUNCTION_ARGS);
Datum uint4int4eq(PG_FUNCTION_ARGS);
Datum uint4int4ne(PG_FUNCTION_ARGS);
Datum uint4int4lt(PG_FUNCTION_ARGS);
Datum uint4int4le(PG_FUNCTION_ARGS);
Datum uint4int4gt(PG_FUNCTION_ARGS);
Datum uint4int4ge(PG_FUNCTION_ARGS);
Datum uint4and(PG_FUNCTION_ARGS);
Datum uint4or(PG_FUNCTION_ARGS);
Datum uint4xor(PG_FUNCTION_ARGS);
Datum uint4not(PG_FUNCTION_ARGS);
Datum uint4shl(PG_FUNCTION_ARGS);
Datum uint4shr(PG_FUNCTION_ARGS);
Datum hashuint4(PG_FUNCTION_ARGS);
Datum hashuint4_from_int4(PG_FUNCTION_ARGS);
Datum uint4toint4(PG_FUNCTION_ARGS);
Datum int4touint4(PG_FUNCTION_ARGS);
Datum uint4toint8(PG_FUNCTION_ARGS);
Datum int8touint4(PG_FUNCTION_ARGS);


/*
 *  =====================
 *  UINT4 PUBLIC ROUTINES
 *  =====================
 */

PG_FUNCTION_INFO_V1(uint4in);
PG_FUNCTION_INFO_V1(uint4out);
PG_FUNCTION_INFO_V1(uint4recv);
PG_FUNCTION_INFO_V1(uint4send);

/**
 * Convert a c-string into a value suitable for the uint4 datatype.
 *
 * @param  s The c-string representation.
 * @return   The Datum containing the converted uint4 value.
 */
Datum
uint4in(PG_FUNCTION_ARGS)
{
   char *badp;
   unsigned long ul;
   char *s = PG_GETARG_CSTRING(0);

   /* Check for NULL pointer. */
   if(unlikely(s == NULL)) {
      elog(ERROR, "NULL pointer");
   }

   /*
    * Some versions of strtoul treat the empty string as an error, but some
    * seem not to.  Make an explicit test to be sure we catch it.
    */
   if(unlikely(*s == 0)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   errno = 0;
   ul = strtoul(s, &badp, 10);

   /* We made no progress parsing the string, so bail out */
   if(unlikely(s == badp)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   /* Verify value is valid in the uint4 datatype range. */
   if(unlikely(errno == ERANGE || ul < 0UL || ul > UINT_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
              errmsg("value \"%s\" is out of range for type unsigned integer", s)));
   }

   /*
    * Skip any trailing whitespace; if anything but whitespace remains before
    * the terminating character, bail out
    */
   while(*badp && isspace((unsigned char)*badp)) {
      badp++;
   }

   /* Verify the c-string is empty. */
   if(unlikely(*badp)) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
              errmsg("invalid input syntax for unsigned integer: \"%s\"", s)));
   }

   PG_RETURN_UINT32((uint32)ul);
}

/**
 * Convert the uint4 value into a c-string.
 *
 * @param  num The uint4 value.
 * @return     The Datum containing the converted uint4 value.
 */
Datum
uint4out(PG_FUNCTION_ARGS)
{
   uint32 num = PG_GETARG_UINT32(0);
   char *str = (char *) palloc(12);

   snprintf(str, 12, "%u", num);
   PG_RETURN_CSTRING(str);
}

/**
 * Convert the binary represented value into a value suitable for
 * the uint4 datatype.
 *
 * @param  buf The uint4 value.
 * @return     The Datum containing the converted uint4 value.
 */
Datum
uint4recv(PG_FUNCTION_ARGS)
{
   StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
   PG_RETURN_UINT32((uint32) pq_getmsgint(buf, sizeof(uint32)));
}

/**
 * Convert the uint4 datatype into its binary representation.
 *
 * @param  num The uint4 value.
 * @return     The Datum containing the converted uint4 value.
 */
Datum
uint4send(PG_FUNCTION_ARGS)
{
   uint32 num = PG_GETARG_UINT32(0);
   StringInfoData buf;

   pq_begintypsend(&buf);
   pq_sendint(&buf, num, sizeof(uint32));
   PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}


/*
 *   ==================================
 *   UINT4 COMPARISON OPERATOR ROUTINES
 *   ==================================
 */

PG_FUNCTION_INFO_V1(btuint4cmp);

/**
 * Comparison function used by the B-tree index for sorting purposes.
 *
 * It is NOT safe to directly subtract the values in this function
 * because the return value could overflow a signed 32-bit integer.
 *
 * @param  a The first uint1 value.
 * @param  b The second uint1 value.
 * @return The Datum containing the comparison value.
 *         The comparison value is:
 *         -1 if a < b
 *          0 if a == b
 *          1 if a > b
 */
Datum
btuint4cmp(PG_FUNCTION_ARGS)
{
   uint32 a = PG_GETARG_UINT32(0);
   uint32 b = PG_GETARG_UINT32(1);

   if(a > b) {
      PG_RETURN_INT32(1);
   }

   if(a == b) {
      PG_RETURN_INT32(0);
   }

   PG_RETURN_INT32(-1);
}

PG_FUNCTION_INFO_V1(uint4eq);
PG_FUNCTION_INFO_V1(uint4ne);
PG_FUNCTION_INFO_V1(uint4lt);
PG_FUNCTION_INFO_V1(uint4le);
PG_FUNCTION_INFO_V1(uint4gt);
PG_FUNCTION_INFO_V1(uint4ge);

/**
 * This function implements the "equal" (=) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2
 *         false if arg1 != arg2
 */
Datum
uint4eq(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(arg1 == arg2);
}

/**
 * This function implements the "not equal" (<>) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 != arg2
 *         false if arg1 == arg2
 */
Datum
uint4ne(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(arg1 != arg2);
}

/**
 * This function implements the "less than" (<) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 < arg2
 *         false if arg1 >= arg2
 */
Datum
uint4lt(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(arg1 < arg2);
}

/**
 * This function implements the "less than or equal" (<=) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 <= arg2
 *         false if arg1 > arg2
 */
Datum
uint4le(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(arg1 <= arg2);
}

/**
 * This function implements the "greater than" (>) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 > arg2
 *         false if arg1 <= arg2
 */
Datum
uint4gt(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(arg1 > arg2);
}

/**
 * This function implements the "greater than or equal" (>=) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 >= arg2
 *         false if arg1 < arg2
 */
Datum
uint4ge(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(arg1 >= arg2);
}

PG_FUNCTION_INFO_V1(int4uint4eq);
PG_FUNCTION_INFO_V1(int4uint4ne);
PG_FUNCTION_INFO_V1(int4uint4lt);
PG_FUNCTION_INFO_V1(int4uint4le);
PG_FUNCTION_INFO_V1(int4uint4gt);
PG_FUNCTION_INFO_V1(int4uint4ge);


/**
 * Internal function used by the int4uint4 operators.
 * 
 * It is NOT safe to directly subtract the values in this function because
 * the return value can overflow a signed 32-bit integer.
 *
 * @param  a The int4 value.
 * @param  b The uint4 value.
 * @return The Datum containing the comparison value.
 *         The comparison value is:
 *         -1 if a < b
 *          0 if a == b
 *          1 if a > b
 */
static int
int4uint4cmp(int32 a, uint32 b)
{
   if(unlikely(a < 0)) {
      return -1;
   }

   if((uint32)a > b) {
      return 1;
   }

   if((uint32)a < b) {
      return -1;
   }

   return 0;
}

/**
 * This function implements the "equal" (=) operator for the uint4 datatype
 * where the the left argument is an int4 and the right argument is a uint4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2
 *         false if arg1 != arg2
 */
Datum
int4uint4eq(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(int4uint4cmp(arg1, arg2) == 0);
}

/**
 * This function implements the "not equal" (<>) operator for the uint4 datatype
 * where the the left argument is an int4 and the right argument is a uint4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 != arg2
 *         false if arg1 == arg2
 */
Datum
int4uint4ne(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(int4uint4cmp(arg1, arg2) != 0);
}

/**
 * This function implements the "less than" (<) operator for the uint4 datatype
 * where the the left argument is an int4 and the right argument is a uint4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 < arg2
 *         false if arg1 >= arg2
 */
Datum
int4uint4lt(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(int4uint4cmp(arg1, arg2) < 0);
}

/**
 * This function implements the "less than or equal" (<=) operator for the uint4 datatype
 * where the the left argument is an int4 and the right argument is a uint4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 <= arg2
 *         false if arg1 > arg2
 */
Datum
int4uint4le(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(int4uint4cmp(arg1, arg2) <= 0);
}

/**
 * This function implements the "greater than" (>) operator for the uint4 datatype
 * where the the left argument is an int4 and the right argument is a uint4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 > arg2
 *         false if arg1 <= arg2
 */
Datum
int4uint4gt(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(int4uint4cmp(arg1, arg2) > 0);
}

/**
 * This function implements the "greater than or equal" (>=) operator for the uint4 datatype
 * where the the left argument is an int4 and the right argument is a uint4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 >= arg2
 *         false if arg1 < arg2
 */
Datum
int4uint4ge(PG_FUNCTION_ARGS)
{
   int32 arg1 = PG_GETARG_INT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_BOOL(int4uint4cmp(arg1, arg2) >= 0);
}

PG_FUNCTION_INFO_V1(uint4int4eq);
PG_FUNCTION_INFO_V1(uint4int4ne);
PG_FUNCTION_INFO_V1(uint4int4lt);
PG_FUNCTION_INFO_V1(uint4int4le);
PG_FUNCTION_INFO_V1(uint4int4gt);
PG_FUNCTION_INFO_V1(uint4int4ge);

/**
 * Internal function used by the uint4int4 operators.
 *
 * It is NOT safe to directly subtract the values in this function because
 * the return value can overflow a signed 32-bit integer.
 *
 * @param  a The uint4 value.
 * @param  b The int4 value.
 * @return The Datum containing the comparison value.
 *         The comparison value is:
 *         -1 if a < b
 *          0 if a == b
 *          1 if a > b
 */
static int
uint4int4cmp(uint32 a, int32 b)
{
   if(unlikely(b < 0)) {
      return 1;
   }

   if((uint32)a > b) {
      return 1;
   }

   if((uint32)a < b) {
      return -1;
   }

   return 0;
}

/**
 * This function implements the "equal" (=) operator for the uint4 datatype
 * where the the left argument is a uint4 and the right argument is an int4.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The int4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 == arg2
 *         false if arg1 != arg2
 */
Datum
uint4int4eq(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_BOOL(uint4int4cmp(arg1, arg2) == 0);
}

/**
 * This function implements the "not equal" (<>) operator for the uint4 datatype
 * where the the left argument is a uint4 and the right argument is an int4.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The int4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 != arg2
 *         false if arg1 == arg2
 */
Datum
uint4int4ne(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_BOOL(uint4int4cmp(arg1, arg2) != 0);
}

/**
 * This function implements the "less than" (<) operator for the uint4 datatype
 * where the the left argument is a uint4 and the right argument is an int4.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The int4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 < arg2
 *         false if arg1 >= arg2
 */
Datum
uint4int4lt(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_BOOL(uint4int4cmp(arg1, arg2) < 0);
}

/**
 * This function implements the "less than or equal" (<=) operator for the uint4 datatype
 * where the the left argument is a uint4 and the right argument is an int4.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The int4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 <= arg2
 *         false if arg1 > arg2
 */
Datum
uint4int4le(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_BOOL(uint4int4cmp(arg1, arg2) <= 0);
}

/**
 * This function implements the "greater than" (>) operator for the uint4 datatype
 * where the the left argument is a uint4 and the right argument is an int4.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The int4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 > arg2
 *         false if arg1 <= arg2
 */
Datum
uint4int4gt(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_BOOL(uint4int4cmp(arg1, arg2) > 0);
}

/**
 * This function implements the "greater than or equal" (>=) operator for the uint4 datatype
 * where the the left argument is a uint4 and the right argument is an int4.
 *
 * @param  arg1 The int4 value.
 * @param  arg2 The uint4 value.
 * @return The Datum containing the boolean operator value.
 *         The operator value is:
 *         true if arg1 >= arg2
 *         false if arg1 < arg2
 */
Datum
uint4int4ge(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_BOOL(uint4int4cmp(arg1, arg2) >= 0);
}


/*
 *  ============================
 *  UINT4 BIT OPERATION ROUTINES
 *  ============================
 */
PG_FUNCTION_INFO_V1(uint4and);
PG_FUNCTION_INFO_V1(uint4or);
PG_FUNCTION_INFO_V1(uint4xor);
PG_FUNCTION_INFO_V1(uint4not);
PG_FUNCTION_INFO_V1(uint4shl);
PG_FUNCTION_INFO_V1(uint4shr);

/**
 * This function implements the bit-wise AND (&) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the new value.
 */
Datum
uint4and(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_UINT32(arg1 & arg2);
}

/**
 * This function implements the bit-wise OR (|) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the new value.
 */
Datum
uint4or(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_UINT32(arg1 | arg2);
}

/**
 * This function implements the bit-wise XOR (#) operator for the uint4 datatype.
 *
 * This function only supports the operator function when both arguments
 * are uint4 datatypes.
 *
 * @param  arg1 The first uint4 value.
 * @param  arg2 The second uint4 value.
 * @return The Datum containing the new value.
 */
Datum
uint4xor(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   uint32 arg2 = PG_GETARG_UINT32(1);

   PG_RETURN_UINT32(arg1 ^ arg2);
}

/**
 * This function implements the compliment (~) operator for the uint4 datatype.
 *
 * @param  arg1 The uint4 value.
 * @return The Datum containing the new value.
 */
Datum
uint4not(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);

   PG_RETURN_UINT32(~arg1);
}

/**
 * This function implements the "shift left" (<<) operator for the uint4 datatype.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The number of bits to shift.
 * @return The Datum containing the new value.
 */
Datum
uint4shl(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_UINT32(arg1 << arg2);
}

/**
 * This function implements the "shift right" (>>) operator for the uint4 datatype.
 *
 * @param  arg1 The uint4 value.
 * @param  arg2 The number of bits to shift.
 * @return The Datum containing the new value.
 */
Datum
uint4shr(PG_FUNCTION_ARGS)
{
   uint32 arg1 = PG_GETARG_UINT32(0);
   int32 arg2 = PG_GETARG_INT32(1);

   PG_RETURN_UINT32(arg1 >> arg2);
}


/*
 *  ============================
 *  UINT4 HASH OPERATOR ROUTINES
 *  ============================
 */
PG_FUNCTION_INFO_V1(hashuint4);
PG_FUNCTION_INFO_V1(hashuint4_from_int4);

/**
 * This function returns a hash value suitable for the hash index.
 *
 * @param  arg1 The uint4 value.
 * @return      The Datum containing the hash value.
 */
Datum
hashuint4(PG_FUNCTION_ARGS)
{
   return hash_uint32(PG_GETARG_UINT32(0));
}

/**
 * This function returns a hash value suitable for the hash index.
 *
 * @param  arg1 The int4 value.
 * @return      The Datum containing the hash value.
 */
Datum
hashuint4_from_int4(PG_FUNCTION_ARGS)
{
   return hash_uint32((uint32)PG_GETARG_INT32(0));
}


/*
 *   =========================
 *   UINT4 CONVERSION ROUTINES
 *   =========================
 */
PG_FUNCTION_INFO_V1(uint4toint4);
PG_FUNCTION_INFO_V1(int4touint4);
PG_FUNCTION_INFO_V1(uint4toint8);
PG_FUNCTION_INFO_V1(int8touint4);

/**
 * Cast a uint4 value into an int1 value.
 * This function throws an error if the uint4 value is out-of-range
 * for the int4 value.
 *
 * @param  num The int4 value.
 * @return     The Datum containing the uint1 value.
 */
Datum
uint4toint4(PG_FUNCTION_ARGS)
{
   uint32 num = PG_GETARG_UINT32(0);

   if(unlikely(num > INT_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                      errmsg("integer out of range")));
   }

   PG_RETURN_INT32((uint32) num);
}

/**
 * Cast an int4 value into a uint4 value.
 * This function throws an error if the int4 value is out-of-range
 * for the uint4 value.
 *
 * @param  num The int4 value.
 * @return     The Datum containing the uint4 value.
 */
Datum
int4touint4(PG_FUNCTION_ARGS)
{
   int32 num = PG_GETARG_INT32(0);

   if(unlikely(num < 0)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                      errmsg("unsigned integer out of range")));
   }

   PG_RETURN_UINT32((uint32) num);
}

/**
 * Cast a uint4 value into a int8 value.
 *
 * @param  num The int4 value.
 * @return     The Datum containing the int8 value.
 */
Datum
uint4toint8(PG_FUNCTION_ARGS)
{
   uint32 num = PG_GETARG_UINT32(0);

   PG_RETURN_INT64((int64) num);
}

/**
 * Cast an int8 value into a uint4 value.
 * This function throws an error if the int8 value is out-of-range
 * for the uint4 value.
 *
 * @param  num The int4 value.
 * @return     The Datum containing the uint4 value.
 */
Datum
int8touint4(PG_FUNCTION_ARGS)
{
   int64 num = PG_GETARG_INT64(0);

   if(unlikely(num < 0 || num > UINT_MAX)) {
      ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                      errmsg("unsigned integer out of range")));
   }

   PG_RETURN_UINT32((uint32) num);
}


/*
 *   ===============================
 *   SELECTIVITY ESTIMATION ROUTINES
 *   ===============================
 */

Datum int4ltsel(PG_FUNCTION_ARGS);
Datum int4gtsel(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(int4ltsel);
PG_FUNCTION_INFO_V1(int4gtsel);

static double
convert_int4_to_double(Datum value)
{
   return (double)DatumGetInt32(value);
}

static double
convert_uint4_to_double(Datum value)
{
   return (double)DatumGetUInt32(value);
}

/*
 * uint_histogram_selectivity  - Examine the histogram for scalarineqsel
 *
 * Determine the fraction of the variable's histogram population that
 * satisfies the inequality condition, ie, VAR < CONST or VAR > CONST.
 *
 * Returns zero if there is no histogram (valid results will always be
 * greater than zero).
 *
 * Note that the result disregards both the most-common-values (if any) and
 * null entries.  The caller is expected to combine this result with
 * statistics for those portions of the column population.
 */
static double
uint_histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
                           bool isgt, Datum constval,
                           double (*convert_value)(Datum),
                           double (*convert_stats)(Datum))
{
   double hist_selec;
   Datum *values;
   int nvalues;

   hist_selec = 0.0;

   /*
    * Someday, ANALYZE might store more than one histogram per rel/att,
    * corresponding to more than one possible sort ordering defined for the
    * column type.  However, to make that work we will need to figure out
    * which staop to search for --- it's not necessarily the one we have at
    * hand!  (For example, we might have a '<=' operator rather than the '<'
    * operator that will appear in staop.)  For now, assume that whatever
    * appears in pg_statistic is sorted the same way our operator sorts, or
    * the reverse way if isgt is TRUE.
    */
   if(HeapTupleIsValid(vardata->statsTuple) &&
      get_attstatsslot(vardata->statsTuple, vardata->atttype,
                       vardata->atttypmod, STATISTIC_KIND_HISTOGRAM,
                       InvalidOid, &values, &nvalues, NULL, NULL))
   {
      if(nvalues > 1) {
         /*
          * Use binary search to find proper location, ie, the first slot
          * at which the comparison fails.  (If the given operator isn't
          * actually sort-compatible with the histogram, you'll get garbage
          * results ... but probably not any more garbage-y than you would
          * from the old linear search.)
          */
         double histfrac;
         int lobound = 0;        /* first possible slot to search */
         int hibound = nvalues;  /* last+1 slot to search */

         while(lobound < hibound) {
            int probe = (lobound + hibound) / 2;
            bool ltcmp;

            ltcmp = DatumGetBool(FunctionCall2(opproc, values[probe], constval));
            if(isgt)
               ltcmp = !ltcmp;
 
            if(ltcmp)
               lobound = probe + 1;
            else
               hibound = probe;
         }

         if(lobound >= nvalues) {
            /* Constant is above upper histogram boundary. */
            histfrac = 1.0;
         }
         else
         {
            int i = lobound;
            double val, high, low;
            double binfrac;

            /*
             * We have values[i-1] < constant < values[i].
             *
             * Convert the constant and the two nearest bin boundary
             * values to a uniform comparison scale, and do a linear
             * interpolation within this bin.
             */

            val = (*convert_value)(constval);
            low = (*convert_stats)(values[i - 1]);
            high = (*convert_stats)(values[i]);

            if(high <= low)
               binfrac = 0.5; /* cope if bin boundaries appear identical */
            else if (val <= low)
               binfrac = 0.0;
            else if (val >= high)
               binfrac = 1.0;
            else {
               binfrac = (val - low) / (high - low);

              /*
               * Watch out for the possibility that we got a NaN or
               * Infinity from the division.  This can happen
               * despite the previous checks, if for example "low"
               * is -Infinity.
               */
              if(isnan(binfrac) || binfrac < 0.0 || binfrac > 1.0)
                 binfrac = 0.5;
            }

            /*
             * Now, compute the overall selectivity across the values
             * represented by the histogram.  We have i-1 full bins and
             * binfrac partial bin below the constant.
             */
            histfrac = (double) (i - 1) + binfrac;
            histfrac /= (double) (nvalues - 1);
         }

         /*
          * Now histfrac = fraction of histogram entries below the
          * constant.
          *
          * Account for "<" vs ">"
          */
         hist_selec = isgt ? (1.0 - histfrac) : histfrac;

         /*
          * The histogram boundaries are only approximate to begin with,
          * and may well be out of date anyway.  Therefore, don't believe
          * extremely small or large selectivity estimates.
          */
         if(hist_selec < 0.0001)
            hist_selec = 0.0001;
         else if (hist_selec > 0.9999)
            hist_selec = 0.9999;
      }
      free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
   }
   return hist_selec;
}

static double
uintrestrictsel(VariableStatData *vardata, FmgrInfo opproc, Datum constval,
                bool isgt, double (*convert_value)(Datum), double (*convert_stats)(Datum))
{
   Form_pg_statistic stats;
   double selec, mcv_selec, sumcommon, hist_selec;

   /*
    * If we have most-common-values info, add up the fractions of the MCV
    * entries that satisfy MCV OP CONST.  These fractions contribute directly
    * to the result selectivity.  Also add up the total fraction represented
    * by MCV entries.
    */
   mcv_selec = mcv_selectivity(vardata, &opproc, constval, true, &sumcommon);
   hist_selec = uint_histogram_selectivity(vardata, &opproc, isgt, constval,
                                           convert_value, convert_stats); 

   stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);

   /*
    * Now merge the results from the MCV and histogram calculations,
    * realizing that the histogram covers only the non-null values that are
    * not listed in MCV.
    */
   selec = 1.0 - stats->stanullfrac - sumcommon;

   if(hist_selec > 0.0)
      selec *= hist_selec;
   else
   {
      /*
       * If no histogram but there are values not accounted for by MCV,
       * arbitrarily assume half of them will match.
       */
      selec *= 0.5;
   }

   selec += mcv_selec;

   /* result should be in range, but make sure... */
   CLAMP_PROBABILITY(selec);
   return selec;
}

Datum
int4ltsel(PG_FUNCTION_ARGS)
{
   PlannerInfo *root = (PlannerInfo *)PG_GETARG_POINTER(0);
   Oid operator = PG_GETARG_OID(1);
   List *args = (List *) PG_GETARG_POINTER(2);
   int varRelid = PG_GETARG_INT32(3);
   VariableStatData vardata;
   Node *other;
   bool varonleft;
   bool isgt = false;
   FmgrInfo opproc;
   Datum constval;
   double selec;

   /*
    * If expression is not variable op something or something op variable,
    * then punt and return a default estimate.
    */
   if(!get_restriction_variable(root, args, varRelid, &vardata, &other, &varonleft)) {
      PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
   }

   /*
    * Can't do anything useful if the something is not a constant, either.
    */
   if(!IsA(other, Const)) {
      ReleaseVariableStats(vardata);
      PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
   }

   /* Can't do anything useful if stats are not available. */
   if(unlikely(!HeapTupleIsValid(vardata.statsTuple))) {
      ReleaseVariableStats(vardata);
      PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
   }

   /*
    * If the constant is NULL, assume operator is strict and return zero.
    * ie. operator will never return TRUE.
    */
   if(((Const *)other)->constisnull) {
       ReleaseVariableStats(vardata);
       PG_RETURN_FLOAT8(0.0);
   }

   /* Force the var to be on the left. */
   if(!varonleft) {
      /* we have other < var, commute to make var > other */
      operator = get_commutator(operator);
      Assert(operator != InvalidOid);
      isgt = true;
   }

   constval = ((Const *)other)->constvalue;
   fmgr_info(get_opcode(operator), &opproc);

   selec = uintrestrictsel(&vardata, opproc, isgt, constval,
                           &convert_uint4_to_double, 
                           &convert_int4_to_double);

   ReleaseVariableStats(vardata);
   PG_RETURN_FLOAT8((float8)selec);
} 

Datum
int4gtsel(PG_FUNCTION_ARGS)
{
   PlannerInfo *root = (PlannerInfo *)PG_GETARG_POINTER(0);
   Oid operator = PG_GETARG_OID(1);
   List *args = (List *) PG_GETARG_POINTER(2);
   int varRelid = PG_GETARG_INT32(3);
   VariableStatData vardata;
   Node *other;
   bool varonleft;
   bool isgt = true;
   FmgrInfo opproc;
   Datum constval;
   double selec;

   /*
    * If expression is not variable op something or something op variable,
    * then punt and return a default estimate.
    */
   if(!get_restriction_variable(root, args, varRelid, &vardata, &other, &varonleft)) {
      PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
   }

   /*
    * Can't do anything useful if the something is not a constant, either.
    */
   if(!IsA(other, Const)) {
      ReleaseVariableStats(vardata);
      PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
   }

   /* Can't do anything useful if stats are not available. */
   if(unlikely(!HeapTupleIsValid(vardata.statsTuple))) {
      ReleaseVariableStats(vardata);
      PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
   }

   /*
    * If the constant is NULL, assume operator is strict and return zero.
    * ie. operator will never return TRUE.
    */
   if(((Const *)other)->constisnull) {
       ReleaseVariableStats(vardata);
       PG_RETURN_FLOAT8(0.0);
   }

   /* Force the var to be on the left.  */
   if(!varonleft) {
      /* we have other < var, commute to make var > other */
      operator = get_commutator(operator);
      Assert(operator != InvalidOid);
      isgt = false;
   }

   constval = ((Const *)other)->constvalue;
   fmgr_info(get_opcode(operator), &opproc);

   selec = uintrestrictsel(&vardata, opproc, isgt, constval,
                           &convert_uint4_to_double,
                           &convert_int4_to_double);

   ReleaseVariableStats(vardata);
   PG_RETURN_FLOAT8((float8)selec);
}