/*------------------------------------------------------------------------- * * int.c * Functions for the built-in integer types (except int8). * * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/utils/adt/int.c * *------------------------------------------------------------------------- */ /* * OLD COMMENTS * I/O routines: * int2in, int2out, int2recv, int2send * int4in, int4out, int4recv, int4send * int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend * Boolean operators: * inteq, intne, intlt, intle, intgt, intge * Arithmetic operators: * intpl, intmi, int4mul, intdiv * * Arithmetic operators: * intmod */ #include "postgres.h" #include #include #include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "utils/array.h" #include "utils/builtins.h" #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) #define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16)) typedef struct { int32 current; int32 finish; int32 step; } generate_series_fctx; /***************************************************************************** * 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); } /* * 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)); } /* * construct int2vector given a raw array of int2s * * If int2s is NULL then caller must fill values[] afterward */ int2vector * buildint2vector(const int16 *int2s, int n) { int2vector *result; result = (int2vector *) palloc0(Int2VectorSize(n)); if (n > 0 && int2s) memcpy(result->values, int2s, n * sizeof(int16)); /* * Attach standard array header. For historical reasons, we set the index * lower bound to 0 not 1. */ SET_VARSIZE(result, Int2VectorSize(n)); result->ndim = 1; result->dataoffset = 0; /* never any nulls */ result->elemtype = INT2OID; result->dim1 = n; result->lbound1 = 0; return result; } /* * int2vectorin - converts "num num ..." to internal form */ Datum int2vectorin(PG_FUNCTION_ARGS) { char *intString = PG_GETARG_CSTRING(0); int2vector *result; int n; result = (int2vector *) palloc0(Int2VectorSize(FUNC_MAX_ARGS)); for (n = 0; *intString && n < FUNC_MAX_ARGS; n++) { while (*intString && isspace((unsigned char) *intString)) intString++; if (*intString == '\0') break; result->values[n] = pg_atoi(intString, sizeof(int16), ' '); while (*intString && !isspace((unsigned char) *intString)) intString++; } while (*intString && isspace((unsigned char) *intString)) intString++; if (*intString) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("int2vector has too many elements"))); SET_VARSIZE(result, Int2VectorSize(n)); result->ndim = 1; result->dataoffset = 0; /* never any nulls */ result->elemtype = INT2OID; result->dim1 = n; result->lbound1 = 0; PG_RETURN_POINTER(result); } /* * int2vectorout - converts internal form to "num num ..." */ Datum int2vectorout(PG_FUNCTION_ARGS) { int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0); int num, nnums = int2Array->dim1; char *rp; char *result; /* assumes sign, 5 digits, ' ' */ rp = result = (char *) palloc(nnums * 7 + 1); for (num = 0; num < nnums; num++) { if (num != 0) *rp++ = ' '; pg_itoa(int2Array->values[num], rp); while (*++rp != '\0') ; } *rp = '\0'; PG_RETURN_CSTRING(result); } /* * int2vectorrecv - converts external binary format to int2vector */ Datum int2vectorrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); FunctionCallInfoData locfcinfo; int2vector *result; /* * Normally one would call array_recv() using DirectFunctionCall3, but * that does not work since array_recv wants to cache some data using * fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo * parameter. */ InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3, InvalidOid, NULL, NULL); locfcinfo.arg[0] = PointerGetDatum(buf); locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID); locfcinfo.arg[2] = Int32GetDatum(-1); locfcinfo.argnull[0] = false; locfcinfo.argnull[1] = false; locfcinfo.argnull[2] = false; result = (int2vector *) DatumGetPointer(array_recv(&locfcinfo)); Assert(!locfcinfo.isnull); /* sanity checks: int2vector must be 1-D, 0-based, no nulls */ if (ARR_NDIM(result) != 1 || ARR_HASNULL(result) || ARR_ELEMTYPE(result) != INT2OID || ARR_LBOUND(result)[0] != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid int2vector data"))); /* check length for consistency with int2vectorin() */ if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("oidvector has too many elements"))); PG_RETURN_POINTER(result); } /* * int2vectorsend - converts int2vector to binary format */ Datum int2vectorsend(PG_FUNCTION_ARGS) { return array_send(fcinfo); } /* * We don't have a complete set of int2vector support routines, * but we need int2vectoreq for catcache indexing. */ Datum int2vectoreq(PG_FUNCTION_ARGS) { int2vector *a = (int2vector *) PG_GETARG_POINTER(0); int2vector *b = (int2vector *) PG_GETARG_POINTER(1); if (a->dim1 != b->dim1) PG_RETURN_BOOL(false); PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * 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); } /* * 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 * =================== */ 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 || arg1 > SHRT_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); PG_RETURN_INT16((int16) arg1); } /* 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 */ 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); int32 result; 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); } Datum int4pl(PG_FUNCTION_ARGS) { 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); } Datum int4mi(PG_FUNCTION_ARGS) { 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); } Datum int4mul(PG_FUNCTION_ARGS) { 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 && ((arg2 == -1 && arg1 < 0 && result < 0) || result / arg2 != arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT32(result); } Datum int4div(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); int32 arg2 = PG_GETARG_INT32(1); int32 result; if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* ensure compiler realizes we mustn't reach the division (gcc bug) */ PG_RETURN_NULL(); } /* * INT_MIN / -1 is problematic, since the result can't be represented on a * two's-complement machine. Some machines produce INT_MIN, some produce * zero, some throw an exception. We can dodge the problem by recognizing * that division by -1 is the same as negation. */ if (arg2 == -1) { result = -arg1; /* overflow check (needed for INT_MIN) */ if (arg1 != 0 && SAMESIGN(result, arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT32(result); } /* No overflow is possible */ result = arg1 / arg2; PG_RETURN_INT32(result); } Datum int4inc(PG_FUNCTION_ARGS) { int32 arg = PG_GETARG_INT32(0); int32 result; 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); } Datum int2um(PG_FUNCTION_ARGS) { int16 arg = PG_GETARG_INT16(0); int16 result; 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); } Datum int2pl(PG_FUNCTION_ARGS) { 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); } Datum int2mi(PG_FUNCTION_ARGS) { 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); } Datum int2mul(PG_FUNCTION_ARGS) { 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); } Datum int2div(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); int16 arg2 = PG_GETARG_INT16(1); int16 result; if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* ensure compiler realizes we mustn't reach the division (gcc bug) */ PG_RETURN_NULL(); } /* * SHRT_MIN / -1 is problematic, since the result can't be represented on * a two's-complement machine. Some machines produce SHRT_MIN, some * produce zero, some throw an exception. We can dodge the problem by * recognizing that division by -1 is the same as negation. */ if (arg2 == -1) { result = -arg1; /* overflow check (needed for SHRT_MIN) */ if (arg1 != 0 && SAMESIGN(result, arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); PG_RETURN_INT16(result); } /* No overflow is possible */ result = arg1 / arg2; PG_RETURN_INT16(result); } Datum int24pl(PG_FUNCTION_ARGS) { 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); } Datum int24mi(PG_FUNCTION_ARGS) { 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); if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* ensure compiler realizes we mustn't reach the division (gcc bug) */ PG_RETURN_NULL(); } /* No overflow is possible */ PG_RETURN_INT32((int32) arg1 / arg2); } Datum int42pl(PG_FUNCTION_ARGS) { 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); } Datum int42mi(PG_FUNCTION_ARGS) { 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. */ if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX) && result / arg1 != arg2) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT32(result); } Datum int42div(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); int16 arg2 = PG_GETARG_INT16(1); int32 result; if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* ensure compiler realizes we mustn't reach the division (gcc bug) */ PG_RETURN_NULL(); } /* * INT_MIN / -1 is problematic, since the result can't be represented on a * two's-complement machine. Some machines produce INT_MIN, some produce * zero, some throw an exception. We can dodge the problem by recognizing * that division by -1 is the same as negation. */ if (arg2 == -1) { result = -arg1; /* overflow check (needed for INT_MIN) */ if (arg1 != 0 && SAMESIGN(result, arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT32(result); } /* No overflow is possible */ result = arg1 / arg2; PG_RETURN_INT32(result); } Datum int4mod(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); int32 arg2 = PG_GETARG_INT32(1); if (arg2 == 0) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* ensure compiler realizes we mustn't reach the division (gcc bug) */ PG_RETURN_NULL(); } /* * Some machines throw a floating-point exception for INT_MIN % -1, which * is a bit silly since the correct answer is perfectly well-defined, * namely zero. */ if (arg2 == -1) PG_RETURN_INT32(0); /* No overflow is possible */ 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) { ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* ensure compiler realizes we mustn't reach the division (gcc bug) */ PG_RETURN_NULL(); } /* * Some machines throw a floating-point exception for INT_MIN % -1, which * is a bit silly since the correct answer is perfectly well-defined, * namely zero. (It's not clear this ever happens when dealing with * int16, but we might as well have the test for safety.) */ if (arg2 == -1) PG_RETURN_INT16(0); /* No overflow is possible */ PG_RETURN_INT16(arg1 % arg2); } /* int[24]abs() * Absolute value */ Datum int4abs(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); int32 result; result = (arg1 < 0) ? -arg1 : arg1; /* overflow check (needed for INT_MIN) */ if (result < 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT32(result); } Datum int2abs(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); int16 result; result = (arg1 < 0) ? -arg1 : arg1; /* overflow check (needed for SHRT_MIN) */ if (result < 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); PG_RETURN_INT16(result); } 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); } /* * Bit-pushing operators * * 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); } /* * non-persistent numeric series generator */ Datum generate_series_int4(PG_FUNCTION_ARGS) { return generate_series_step_int4(fcinfo); } Datum generate_series_step_int4(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; generate_series_fctx *fctx; int32 result; MemoryContext oldcontext; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { int32 start = PG_GETARG_INT32(0); int32 finish = PG_GETARG_INT32(1); int32 step = 1; /* see if we were given an explicit step size */ if (PG_NARGS() == 3) step = PG_GETARG_INT32(2); if (step == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("step size cannot equal zero"))); /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* allocate memory for user context */ fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx)); /* * Use fctx to keep state from call to call. Seed current with the * original start value */ fctx->current = start; fctx->finish = finish; fctx->step = step; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); /* * get the saved state and use current as the result for this iteration */ fctx = funcctx->user_fctx; result = fctx->current; if ((fctx->step > 0 && fctx->current <= fctx->finish) || (fctx->step < 0 && fctx->current >= fctx->finish)) { /* increment current in preparation for next iteration */ fctx->current += fctx->step; /* if next-value computation overflows, this is the final result */ if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current)) fctx->step = 0; /* do when there is more left to send */ SRF_RETURN_NEXT(funcctx, Int32GetDatum(result)); } else /* do when there is no more left */ SRF_RETURN_DONE(funcctx); }