1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00
Files
postgres/src/backend/utils/adt/int.c
Tom Lane 31e69ccb21 Add explicit tests for division by zero to all user-accessible integer
division and modulo functions, to avoid problems on OS X (which fails to
trap 0 divide at all) and Windows (which traps it in some bizarre
nonstandard fashion).  Standardize on 'division by zero' as the one true
spelling of this error message.  Add regression tests as suggested by
Neil Conway.
2003-03-11 21:01:33 +00:00

955 lines
16 KiB
C

/*-------------------------------------------------------------------------
*
* int.c
* Functions for the built-in integer types (except int8).
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.53 2003/03/11 21:01:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
* I/O routines:
* int2in, int2out, int2vectorin, int2vectorout, int4in, int4out
* Conversion routines:
* itoi, int2_text, int4_text
* Boolean operators:
* inteq, intne, intlt, intle, intgt, intge
* Arithmetic operators:
* intpl, intmi, int4mul, intdiv
*
* Arithmetic operators:
* intmod, int4fac
*/
#include "postgres.h"
#include <ctype.h>
#include <limits.h>
#include "utils/builtins.h"
#ifndef SHRT_MAX
#define SHRT_MAX (0x7FFF)
#endif
#ifndef SHRT_MIN
#define SHRT_MIN (-0x8000)
#endif
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* int2in - converts "num" to short
*/
Datum
int2in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
PG_RETURN_INT16(pg_atoi(num, sizeof(int16), '\0'));
}
/*
* int2out - converts short to "num"
*/
Datum
int2out(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
char *result = (char *) palloc(7); /* sign, 5 digits, '\0' */
pg_itoa(arg1, result);
PG_RETURN_CSTRING(result);
}
/*
* int2vectorin - converts "num num ..." to internal form
*
* Note: Fills any missing slots with zeroes.
*/
Datum
int2vectorin(PG_FUNCTION_ARGS)
{
char *intString = PG_GETARG_CSTRING(0);
int16 *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS]));
int slot;
for (slot = 0; *intString && slot < INDEX_MAX_KEYS; slot++)
{
if (sscanf(intString, "%hd", &result[slot]) != 1)
break;
while (*intString && isspace((unsigned char) *intString))
intString++;
while (*intString && !isspace((unsigned char) *intString))
intString++;
}
while (*intString && isspace((unsigned char) *intString))
intString++;
if (*intString)
elog(ERROR, "int2vector value has too many values");
while (slot < INDEX_MAX_KEYS)
result[slot++] = 0;
PG_RETURN_POINTER(result);
}
/*
* int2vectorout - converts internal form to "num num ..."
*/
Datum
int2vectorout(PG_FUNCTION_ARGS)
{
int16 *int2Array = (int16 *) PG_GETARG_POINTER(0);
int num,
maxnum;
char *rp;
char *result;
/* find last non-zero value in vector */
for (maxnum = INDEX_MAX_KEYS - 1; maxnum >= 0; maxnum--)
if (int2Array[maxnum] != 0)
break;
/* assumes sign, 5 digits, ' ' */
rp = result = (char *) palloc((maxnum + 1) * 7 + 1);
for (num = 0; num <= maxnum; num++)
{
if (num != 0)
*rp++ = ' ';
pg_itoa(int2Array[num], rp);
while (*++rp != '\0')
;
}
*rp = '\0';
PG_RETURN_CSTRING(result);
}
/*
* We don't have a complete set of int2vector support routines,
* but we need int2vectoreq for catcache indexing.
*/
Datum
int2vectoreq(PG_FUNCTION_ARGS)
{
int16 *arg1 = (int16 *) PG_GETARG_POINTER(0);
int16 *arg2 = (int16 *) PG_GETARG_POINTER(1);
PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(int16)) == 0);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
/*
* int4in - converts "num" to int4
*/
Datum
int4in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
PG_RETURN_INT32(pg_atoi(num, sizeof(int32), '\0'));
}
/*
* int4out - converts int4 to "num"
*/
Datum
int4out(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */
pg_ltoa(arg1, result);
PG_RETURN_CSTRING(result);
}
/*
* ===================
* CONVERSION ROUTINES
* ===================
*/
Datum
i2toi4(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
PG_RETURN_INT32((int32) arg1);
}
Datum
i4toi2(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
if (arg1 < SHRT_MIN)
elog(ERROR, "i4toi2: '%d' causes int2 underflow", arg1);
if (arg1 > SHRT_MAX)
elog(ERROR, "i4toi2: '%d' causes int2 overflow", arg1);
PG_RETURN_INT16((int16) arg1);
}
Datum
int2_text(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
text *result = (text *) palloc(7 + VARHDRSZ); /* sign,5 digits, '\0' */
pg_itoa(arg1, VARDATA(result));
VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;
PG_RETURN_TEXT_P(result);
}
Datum
text_int2(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(int2in, CStringGetDatum(str));
pfree(str);
return result;
}
Datum
int4_text(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
text *result = (text *) palloc(12 + VARHDRSZ); /* sign,10 digits,'\0' */
pg_ltoa(arg1, VARDATA(result));
VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;
PG_RETURN_TEXT_P(result);
}
Datum
text_int4(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(int4in, CStringGetDatum(str));
pfree(str);
return result;
}
/*
* ============================
* COMPARISON OPERATOR ROUTINES
* ============================
*/
/*
* inteq - returns 1 iff arg1 == arg2
* intne - returns 1 iff arg1 != arg2
* intlt - returns 1 iff arg1 < arg2
* intle - returns 1 iff arg1 <= arg2
* intgt - returns 1 iff arg1 > arg2
* intge - returns 1 iff arg1 >= arg2
*/
Datum
int4eq(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 == arg2);
}
Datum
int4ne(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 != arg2);
}
Datum
int4lt(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 < arg2);
}
Datum
int4le(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 <= arg2);
}
Datum
int4gt(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 > arg2);
}
Datum
int4ge(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 >= arg2);
}
Datum
int2eq(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 == arg2);
}
Datum
int2ne(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 != arg2);
}
Datum
int2lt(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 < arg2);
}
Datum
int2le(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 <= arg2);
}
Datum
int2gt(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 > arg2);
}
Datum
int2ge(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 >= arg2);
}
Datum
int24eq(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 == arg2);
}
Datum
int24ne(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 != arg2);
}
Datum
int24lt(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 < arg2);
}
Datum
int24le(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 <= arg2);
}
Datum
int24gt(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 > arg2);
}
Datum
int24ge(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_BOOL(arg1 >= arg2);
}
Datum
int42eq(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 == arg2);
}
Datum
int42ne(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 != arg2);
}
Datum
int42lt(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 < arg2);
}
Datum
int42le(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 <= arg2);
}
Datum
int42gt(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 > arg2);
}
Datum
int42ge(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_BOOL(arg1 >= arg2);
}
/*
* int[24]pl - returns arg1 + arg2
* int[24]mi - returns arg1 - arg2
* int[24]mul - returns arg1 * arg2
* int[24]div - returns arg1 / arg2
*/
Datum
int4um(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(-arg);
}
Datum
int4up(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg);
}
Datum
int4pl(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 + arg2);
}
Datum
int4mi(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 - arg2);
}
Datum
int4mul(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 * arg2);
}
Datum
int4div(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT32(arg1 / arg2);
}
Datum
int4inc(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg + 1);
}
Datum
int2um(PG_FUNCTION_ARGS)
{
int16 arg = PG_GETARG_INT16(0);
PG_RETURN_INT16(-arg);
}
Datum
int2up(PG_FUNCTION_ARGS)
{
int16 arg = PG_GETARG_INT16(0);
PG_RETURN_INT16(arg);
}
Datum
int2pl(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16(arg1 + arg2);
}
Datum
int2mi(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16(arg1 - arg2);
}
Datum
int2mul(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16(arg1 * arg2);
}
Datum
int2div(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT16(arg1 / arg2);
}
Datum
int24pl(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 + arg2);
}
Datum
int24mi(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 - arg2);
}
Datum
int24mul(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 * arg2);
}
Datum
int24div(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT32(arg1 / arg2);
}
Datum
int42pl(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT32(arg1 + arg2);
}
Datum
int42mi(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT32(arg1 - arg2);
}
Datum
int42mul(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT32(arg1 * arg2);
}
Datum
int42div(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT32(arg1 / arg2);
}
Datum
int4mod(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT32(arg1 % arg2);
}
Datum
int2mod(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT16(arg1 % arg2);
}
Datum
int24mod(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT32(arg1 % arg2);
}
Datum
int42mod(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
if (arg2 == 0)
elog(ERROR, "division by zero");
PG_RETURN_INT32(arg1 % arg2);
}
/* int[24]fac()
* Factorial
*/
Datum
int4fac(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 result;
if (arg1 == 0)
result = 1;
else if (arg1 < 0)
result = 0;
else
for (result = 1; arg1 > 0; --arg1)
result *= arg1;
PG_RETURN_INT32(result);
}
Datum
int2fac(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 result;
if (arg1 == 0)
result = 1;
else if (arg1 < 0)
result = 0;
else
for (result = 1; arg1 > 0; --arg1)
result *= arg1;
PG_RETURN_INT32(result);
}
/* int[24]abs()
* Absolute value
*/
Datum
int4abs(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
PG_RETURN_INT32((arg1 < 0) ? -arg1 : arg1);
}
Datum
int2abs(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
PG_RETURN_INT16((arg1 < 0) ? -arg1 : arg1);
}
Datum
int2larger(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16((arg1 > arg2) ? arg1 : arg2);
}
Datum
int2smaller(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16((arg1 < arg2) ? arg1 : arg2);
}
Datum
int4larger(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32((arg1 > arg2) ? arg1 : arg2);
}
Datum
int4smaller(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32((arg1 < arg2) ? arg1 : arg2);
}
/* Binary arithmetics
*
* int[24]and - returns arg1 & arg2
* int[24]or - returns arg1 | arg2
* int[24]xor - returns arg1 # arg2
* int[24]not - returns ~arg1
* int[24]shl - returns arg1 << arg2
* int[24]shr - returns arg1 >> arg2
*/
Datum
int4and(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 & arg2);
}
Datum
int4or(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 | arg2);
}
Datum
int4xor(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 ^ arg2);
}
Datum
int4shl(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 << arg2);
}
Datum
int4shr(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 >> arg2);
}
Datum
int4not(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
PG_RETURN_INT32(~arg1);
}
Datum
int2and(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16(arg1 & arg2);
}
Datum
int2or(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16(arg1 | arg2);
}
Datum
int2xor(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
PG_RETURN_INT16(arg1 ^ arg2);
}
Datum
int2not(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
PG_RETURN_INT16(~arg1);
}
Datum
int2shl(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT16(arg1 << arg2);
}
Datum
int2shr(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT16(arg1 >> arg2);
}