Skip to content
Snippets Groups Projects
int.c 28 KiB
Newer Older
/*-------------------------------------------------------------------------
 *
 *	  Functions for the built-in integer types (except int8).
PostgreSQL Daemon's avatar
 
PostgreSQL Daemon committed
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
Bruce Momjian's avatar
Bruce Momjian committed
 * Portions Copyright (c) 1994, Regents of the University of California
 *	  $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.65 2005/02/27 08:31:30 neilc Exp $
 *
 *-------------------------------------------------------------------------
 */
/*
 * OLD COMMENTS
 *		 int2in, int2out, int2recv, int2send
 *		 int4in, int4out, int4recv, int4send
 *		 int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend
 *		 itoi, int2_text, int4_text
 *		Boolean operators:
 *		 inteq, intne, intlt, intle, intgt, intge
 *		Arithmetic operators:
 *		 intpl, intmi, int4mul, intdiv
 *		Arithmetic operators:
Bruce Momjian's avatar
Bruce Momjian committed
#include "postgres.h"
Bruce Momjian's avatar
Bruce Momjian committed
#include "utils/builtins.h"
#ifndef SHRT_MAX
#define SHRT_MAX (0x7FFF)
#endif
#ifndef SHRT_MIN
#define SHRT_MIN (-0x8000)
#endif

#define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))

typedef struct
{
	int32		current;
	int32		finish;
	int32		step;
Bruce Momjian's avatar
Bruce Momjian committed
} generate_series_fctx;
/*****************************************************************************
 *	 USER I/O ROUTINES														 *
 *****************************************************************************/

/*
 *		int2in			- converts "num" to short
	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' */
/*
 *		int2recv			- converts external binary format to int2
 */
Datum
int2recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INT16((int16) pq_getmsgint(buf, sizeof(int16)));
}

/*
 *		int2send			- converts int2 to binary format
 */
Datum
int2send(PG_FUNCTION_ARGS)
{
	int16		arg1 = PG_GETARG_INT16(0);
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendint(&buf, arg1, sizeof(int16));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

 *		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))
		while (*intString && !isspace((unsigned char) *intString))
			intString++;
	while (*intString && isspace((unsigned char) *intString))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("int2vector has too many elements")));

	while (slot < INDEX_MAX_KEYS)
		result[slot++] = 0;

 *		int2vectorout		- converts internal form to "num num ..."
Datum
int2vectorout(PG_FUNCTION_ARGS)
	int16	   *int2Array = (int16 *) PG_GETARG_POINTER(0);
	/* 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++)
/*
 *		int2vectorrecv			- converts external binary format to int2vector
 */
Datum
int2vectorrecv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	int16	   *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS]));
	int			slot;

	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
		result[slot] = (int16) pq_getmsgint(buf, sizeof(int16));
	PG_RETURN_POINTER(result);
}

/*
 *		int2vectorsend			- converts int2vector to binary format
 */
Datum
int2vectorsend(PG_FUNCTION_ARGS)
{
	int16	   *int2Array = (int16 *) PG_GETARG_POINTER(0);
	StringInfoData buf;
	int			slot;

	pq_begintypsend(&buf);
	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
		pq_sendint(&buf, int2Array[slot], sizeof(int16));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

/*
 * 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
	char	   *num = PG_GETARG_CSTRING(0);

	PG_RETURN_INT32(pg_atoi(num, sizeof(int32), '\0'));
 *		int4out			- converts int4 to "num"
	int32		arg1 = PG_GETARG_INT32(0);
	char	   *result = (char *) palloc(12);	/* sign, 10 digits, '\0' */
/*
 *		int4recv			- converts external binary format to int4
 */
Datum
int4recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INT32((int32) pq_getmsgint(buf, sizeof(int32)));
}

/*
 *		int4send			- converts int4 to binary format
 */
Datum
int4send(PG_FUNCTION_ARGS)
{
	int32		arg1 = PG_GETARG_INT32(0);
	StringInfoData buf;

	pq_begintypsend(&buf);
	pq_sendint(&buf, arg1, sizeof(int32));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

 *		===================
 *		CONVERSION ROUTINES
 *		===================
	int16		arg1 = PG_GETARG_INT16(0);

	PG_RETURN_INT32((int32) arg1);
	int32		arg1 = PG_GETARG_INT32(0);

	if (arg1 < SHRT_MIN || arg1 > SHRT_MAX)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	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));
Jan Wieck's avatar
Jan Wieck committed
	VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;
Datum
text_int2(PG_FUNCTION_ARGS)
	text	   *string = PG_GETARG_TEXT_P(0);
	Datum		result;
	len = VARSIZE(string) - VARHDRSZ;
	memcpy(str, VARDATA(string), len);
	result = DirectFunctionCall1(int2in, CStringGetDatum(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));
Jan Wieck's avatar
Jan Wieck committed
	VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;
Datum
text_int4(PG_FUNCTION_ARGS)
	text	   *string = PG_GETARG_TEXT_P(0);
	Datum		result;
	len = VARSIZE(string) - VARHDRSZ;
	memcpy(str, VARDATA(string), len);
	result = DirectFunctionCall1(int4in, CStringGetDatum(str));
	return result;
/* Cast int4 -> bool */
Datum
int4_bool(PG_FUNCTION_ARGS)
{
	if (PG_GETARG_INT32(0) == 0)
		PG_RETURN_BOOL(false);
	else
		PG_RETURN_BOOL(true);
}

/* Cast bool -> int4 */
Datum
bool_int4(PG_FUNCTION_ARGS)
{
	if (PG_GETARG_BOOL(0) == false)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(1);
}
 *		============================
 *		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
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 == arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 != arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 < arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 <= arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 > arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 >= arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 == arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 != arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 < arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 <= arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 > arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 >= arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 == arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 != arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 < arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 <= arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 > arg2);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(arg1 >= arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 == arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 != arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 < arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 <= arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(arg1 > arg2);
	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
	int32		arg = PG_GETARG_INT32(0);
	result = -arg;
	/* overflow check (needed for INT_MIN) */
	if (arg != 0 && SAMESIGN(result, arg))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
Datum
int4up(PG_FUNCTION_ARGS)
{
	int32		arg = PG_GETARG_INT32(0);

	PG_RETURN_INT32(arg);
}

	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);
	int32		result;

	result = arg1 + arg2;
	/*
	 * Overflow check.  If the inputs are of different signs then their sum
	 * cannot overflow.  If the inputs are of the same sign, their sum
	 * had better be that sign too.
	 */
	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);
	int32		result;

	result = arg1 - arg2;
	/*
	 * Overflow check.  If the inputs are of the same sign then their
	 * difference cannot overflow.  If they are of different signs then
	 * the result should be of the same sign as the first input.
	 */
	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);
	int32		result;

	result = arg1 * arg2;
	/*
	 * Overflow check.  We basically check to see if result / arg2 gives
	 * arg1 again.  There are two cases where this fails: arg2 = 0 (which
	 * cannot overflow) and arg1 = INT_MIN, arg2 = -1 (where the division
	 * itself will overflow and thus incorrectly match).
	 *
	 * Since the division is likely much more expensive than the actual
	 * multiplication, we'd like to skip it where possible.  The best
	 * bang for the buck seems to be to check whether both inputs are in
	 * the int16 range; if so, no overflow is possible.
	 */
	if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX &&
		  arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
		arg2 != 0 &&
		(result/arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
	int32		arg1 = PG_GETARG_INT32(0);
	int32		arg2 = PG_GETARG_INT32(1);
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
	result = arg1 / arg2;
	/*
	 * Overflow check.  The only possible overflow case is for
	 * arg1 = INT_MIN, arg2 = -1, where the correct result is -INT_MIN,
	 * which can't be represented on a two's-complement machine.
	 */
	if (arg2 == -1 && arg1 < 0 && result < 0)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
	int32		arg = PG_GETARG_INT32(0);
	result = arg + 1;
	/* Overflow check */
	if (arg > 0 && result < 0)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));

	PG_RETURN_INT32(result);
	int16		arg = PG_GETARG_INT16(0);
	result = -arg;
	/* overflow check (needed for SHRT_MIN) */
	if (arg != 0 && SAMESIGN(result, arg))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(result);
Datum
int2up(PG_FUNCTION_ARGS)
{
	int16		arg = PG_GETARG_INT16(0);

	PG_RETURN_INT16(arg);
}

	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);
	int16		result;

	result = arg1 + arg2;
	/*
	 * Overflow check.  If the inputs are of different signs then their sum
	 * cannot overflow.  If the inputs are of the same sign, their sum
	 * had better be that sign too.
	 */
	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(result);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);
	int16		result;

	result = arg1 - arg2;
	/*
	 * Overflow check.  If the inputs are of the same sign then their
	 * difference cannot overflow.  If they are of different signs then
	 * the result should be of the same sign as the first input.
	 */
	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(result);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);
	int32		result32;

	/*
	 * The most practical way to detect overflow is to do the arithmetic
	 * in int32 (so that the result can't overflow) and then do a range
	 * check.
	 */
	result32 = (int32) arg1 * (int32) arg2;
	if (result32 < SHRT_MIN || result32 > SHRT_MAX)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16((int16) result32);
	int16		arg1 = PG_GETARG_INT16(0);
	int16		arg2 = PG_GETARG_INT16(1);
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
	result = arg1 / arg2;
	/*
	 * Overflow check.  The only possible overflow case is for
	 * arg1 = SHRT_MIN, arg2 = -1, where the correct result is -SHRT_MIN,
	 * which can't be represented on a two's-complement machine.
	 */
	if (arg2 == -1 && arg1 < 0 && result < 0)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));
	PG_RETURN_INT16(result);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);
	int32		result;

	result = arg1 + arg2;
	/*
	 * Overflow check.  If the inputs are of different signs then their sum
	 * cannot overflow.  If the inputs are of the same sign, their sum
	 * had better be that sign too.
	 */
	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);
	int32		result;

	result = arg1 - arg2;
	/*
	 * Overflow check.  If the inputs are of the same sign then their
	 * difference cannot overflow.  If they are of different signs then
	 * the result should be of the same sign as the first input.
	 */
	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
Datum
int24mul(PG_FUNCTION_ARGS)
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);
	int32		result;

	result = arg1 * arg2;
	/*
	 * Overflow check.  We basically check to see if result / arg2 gives
	 * arg1 again.  There is one case where this fails: arg2 = 0 (which
	 * cannot overflow).
	 *
	 * Since the division is likely much more expensive than the actual
	 * multiplication, we'd like to skip it where possible.  The best
	 * bang for the buck seems to be to check whether both inputs are in
	 * the int16 range; if so, no overflow is possible.
	 */
	if (!(arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
		result/arg2 != arg1)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
Datum
int24div(PG_FUNCTION_ARGS)
	int16		arg1 = PG_GETARG_INT16(0);
	int32		arg2 = PG_GETARG_INT32(1);

		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
	/* No overflow is possible */
	PG_RETURN_INT32((int32) arg1 / arg2);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);
	int32		result;

	result = arg1 + arg2;
	/*
	 * Overflow check.  If the inputs are of different signs then their sum
	 * cannot overflow.  If the inputs are of the same sign, their sum
	 * had better be that sign too.
	 */
	if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);
	int32		result;

	result = arg1 - arg2;
	/*
	 * Overflow check.  If the inputs are of the same sign then their
	 * difference cannot overflow.  If they are of different signs then
	 * the result should be of the same sign as the first input.
	 */
	if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));
	PG_RETURN_INT32(result);
Datum
int42mul(PG_FUNCTION_ARGS)
	int32		arg1 = PG_GETARG_INT32(0);
	int16		arg2 = PG_GETARG_INT16(1);
	int32		result;

	result = arg1 * arg2;
	/*
	 * Overflow check.  We basically check to see if result / arg1 gives
	 * arg2 again.  There is one case where this fails: arg1 = 0 (which
	 * cannot overflow).
	 *
	 * Since the division is likely much more expensive than the actual
	 * multiplication, we'd like to skip it where possible.  The best
	 * bang for the buck seems to be to check whether both inputs are in
	 * the int16 range; if so, no overflow is possible.