X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fadt%2Fint8.c;h=6707b79e5485cc65b86ad7f29e57cebd34937b3a;hb=901be0fad4034c9cf8a3588fd6cf2ece82e4b8ce;hp=018352df1ad7b8dd53aa31aedb782fac9e28b080;hpb=52f77df613cea1803ce86321c37229626d9f213c;p=postgresql diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 018352df1a..6707b79e54 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -3,35 +3,36 @@ * int8.c * Internal 64-bit integer operations * + * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.77 2010/01/07 04:53:34 tgl Exp $ + * *------------------------------------------------------------------------- */ -#include -#include -#include -#include - #include "postgres.h" -#ifdef HAVE_LIMITS_H +#include #include -#endif +#include +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "nodes/nodes.h" #include "utils/int8.h" + #define MAXINT8LEN 25 -#ifndef INT_MAX -#define INT_MAX (0x7FFFFFFFL) -#endif -#ifndef INT_MIN -#define INT_MIN (-INT_MAX-1) -#endif -#ifndef SHRT_MAX -#define SHRT_MAX (0x7FFF) -#endif -#ifndef SHRT_MIN -#define SHRT_MIN (-SHRT_MAX-1) -#endif +#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) + +typedef struct +{ + int64 current; + int64 finish; + int64 step; +} generate_series_fctx; /*********************************************************************** @@ -44,651 +45,1363 @@ * Formatting and conversion routines. *---------------------------------------------------------*/ -/* int8in() +/* + * scanint8 --- try to parse a string into an int8. + * + * If errorOK is false, ereport a useful error message if the string is bad. + * If errorOK is true, just return "false" for bad input. */ -int64 * -int8in(char *str) +bool +scanint8(const char *str, bool errorOK, int64 *result) { - int64 *result = palloc(sizeof(int64)); - char *ptr = str; + const char *ptr = str; int64 tmp = 0; int sign = 1; - if (!PointerIsValid(str)) - elog(ERROR, "Bad (null) int8 external representation"); - /* - * Do our own scan, rather than relying on sscanf which might be - * broken for long long. + * Do our own scan, rather than relying on sscanf which might be broken + * for long long. */ - while (*ptr && isspace(*ptr)) /* skip leading spaces */ + + /* skip leading spaces */ + while (*ptr && isspace((unsigned char) *ptr)) ptr++; - if (*ptr == '-') /* handle sign */ - sign = -1, ptr++; + + /* handle sign */ + if (*ptr == '-') + { + ptr++; + + /* + * Do an explicit check for INT64_MIN. Ugly though this is, it's + * cleaner than trying to get the loop below to handle it portably. + */ + if (strncmp(ptr, "9223372036854775808", 19) == 0) + { + tmp = -INT64CONST(0x7fffffffffffffff) - 1; + ptr += 19; + goto gotdigits; + } + sign = -1; + } else if (*ptr == '+') ptr++; - if (!isdigit(*ptr)) /* require at least one digit */ - elog(ERROR, "Bad int8 external representation \"%s\"", str); - while (*ptr && isdigit(*ptr)) /* process digits */ + + /* require at least one digit */ + if (!isdigit((unsigned char) *ptr)) + { + if (errorOK) + return false; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for integer: \"%s\"", + str))); + } + + /* process digits */ + while (*ptr && isdigit((unsigned char) *ptr)) { int64 newtmp = tmp * 10 + (*ptr++ - '0'); if ((newtmp / 10) != tmp) /* overflow? */ - elog(ERROR, "int8 value out of range: \"%s\"", str); + { + if (errorOK) + return false; + else + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type bigint", + str))); + } tmp = newtmp; } - if (*ptr) /* trailing junk? */ - elog(ERROR, "Bad int8 external representation \"%s\"", str); + +gotdigits: + + /* allow trailing whitespace, but not other trailing chars */ + while (*ptr != '\0' && isspace((unsigned char) *ptr)) + ptr++; + + if (*ptr != '\0') + { + if (errorOK) + return false; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for integer: \"%s\"", + str))); + } *result = (sign < 0) ? -tmp : tmp; - return result; -} /* int8in() */ + return true; +} + +/* int8in() + */ +Datum +int8in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + int64 result; + + (void) scanint8(str, false, &result); + PG_RETURN_INT64(result); +} /* int8out() */ -char * -int8out(int64 *val) +Datum +int8out(PG_FUNCTION_ARGS) { + int64 val = PG_GETARG_INT64(0); char *result; - int len; char buf[MAXINT8LEN + 1]; - if (!PointerIsValid(val)) - return NULL; + if ((len = snprintf(buf, MAXINT8LEN, INT64_FORMAT, val)) < 0) + elog(ERROR, "could not format int8"); + + result = pstrdup(buf); + PG_RETURN_CSTRING(result); +} - if ((len = snprintf(buf, MAXINT8LEN, INT64_FORMAT, *val)) < 0) - elog(ERROR, "Unable to format int8"); +/* + * int8recv - converts external binary format to int8 + */ +Datum +int8recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - result = palloc(len + 1); + PG_RETURN_INT64(pq_getmsgint64(buf)); +} - strcpy(result, buf); +/* + * int8send - converts int8 to binary format + */ +Datum +int8send(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + StringInfoData buf; - return result; -} /* int8out() */ + pq_begintypsend(&buf); + pq_sendint64(&buf, arg1); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} /*---------------------------------------------------------- - * Relational operators for int8s. + * Relational operators for int8s, including cross-data-type comparisons. *---------------------------------------------------------*/ /* int8relop() * Is val1 relop val2? */ -bool -int8eq(int64 *val1, int64 *val2) +Datum +int8eq(PG_FUNCTION_ARGS) { - if (!val1 || !val2) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); - return *val1 == *val2; -} /* int8eq() */ + PG_RETURN_BOOL(val1 == val2); +} -bool -int8ne(int64 *val1, int64 *val2) +Datum +int8ne(PG_FUNCTION_ARGS) { - if (!val1 || !val2) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); - return *val1 != *val2; -} /* int8ne() */ + PG_RETURN_BOOL(val1 != val2); +} -bool -int8lt(int64 *val1, int64 *val2) +Datum +int8lt(PG_FUNCTION_ARGS) { - if (!val1 || !val2) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); - return *val1 < *val2; -} /* int8lt() */ + PG_RETURN_BOOL(val1 < val2); +} -bool -int8gt(int64 *val1, int64 *val2) +Datum +int8gt(PG_FUNCTION_ARGS) { - if (!val1 || !val2) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); - return *val1 > *val2; -} /* int8gt() */ + PG_RETURN_BOOL(val1 > val2); +} -bool -int8le(int64 *val1, int64 *val2) +Datum +int8le(PG_FUNCTION_ARGS) { - if (!val1 || !val2) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); - return *val1 <= *val2; -} /* int8le() */ + PG_RETURN_BOOL(val1 <= val2); +} -bool -int8ge(int64 *val1, int64 *val2) +Datum +int8ge(PG_FUNCTION_ARGS) { - if (!val1 || !val2) - return 0; - - return *val1 >= *val2; -} /* int8ge() */ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + PG_RETURN_BOOL(val1 >= val2); +} /* int84relop() * Is 64-bit val1 relop 32-bit val2? */ -bool -int84eq(int64 *val1, int32 val2) +Datum +int84eq(PG_FUNCTION_ARGS) { - if (!val1) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int32 val2 = PG_GETARG_INT32(1); - return *val1 == val2; -} /* int84eq() */ + PG_RETURN_BOOL(val1 == val2); +} -bool -int84ne(int64 *val1, int32 val2) +Datum +int84ne(PG_FUNCTION_ARGS) { - if (!val1) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int32 val2 = PG_GETARG_INT32(1); - return *val1 != val2; -} /* int84ne() */ + PG_RETURN_BOOL(val1 != val2); +} -bool -int84lt(int64 *val1, int32 val2) +Datum +int84lt(PG_FUNCTION_ARGS) { - if (!val1) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int32 val2 = PG_GETARG_INT32(1); - return *val1 < val2; -} /* int84lt() */ + PG_RETURN_BOOL(val1 < val2); +} -bool -int84gt(int64 *val1, int32 val2) +Datum +int84gt(PG_FUNCTION_ARGS) { - if (!val1) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int32 val2 = PG_GETARG_INT32(1); - return *val1 > val2; -} /* int84gt() */ + PG_RETURN_BOOL(val1 > val2); +} -bool -int84le(int64 *val1, int32 val2) +Datum +int84le(PG_FUNCTION_ARGS) { - if (!val1) - return 0; + int64 val1 = PG_GETARG_INT64(0); + int32 val2 = PG_GETARG_INT32(1); - return *val1 <= val2; -} /* int84le() */ + PG_RETURN_BOOL(val1 <= val2); +} -bool -int84ge(int64 *val1, int32 val2) +Datum +int84ge(PG_FUNCTION_ARGS) { - if (!val1) - return 0; - - return *val1 >= val2; -} /* int84ge() */ + int64 val1 = PG_GETARG_INT64(0); + int32 val2 = PG_GETARG_INT32(1); + PG_RETURN_BOOL(val1 >= val2); +} /* int48relop() * Is 32-bit val1 relop 64-bit val2? */ -bool -int48eq(int32 val1, int64 *val2) +Datum +int48eq(PG_FUNCTION_ARGS) { - if (!val2) - return 0; + int32 val1 = PG_GETARG_INT32(0); + int64 val2 = PG_GETARG_INT64(1); - return val1 == *val2; -} /* int48eq() */ + PG_RETURN_BOOL(val1 == val2); +} -bool -int48ne(int32 val1, int64 *val2) +Datum +int48ne(PG_FUNCTION_ARGS) { - if (!val2) - return 0; + int32 val1 = PG_GETARG_INT32(0); + int64 val2 = PG_GETARG_INT64(1); - return val1 != *val2; -} /* int48ne() */ + PG_RETURN_BOOL(val1 != val2); +} -bool -int48lt(int32 val1, int64 *val2) +Datum +int48lt(PG_FUNCTION_ARGS) { - if (!val2) - return 0; + int32 val1 = PG_GETARG_INT32(0); + int64 val2 = PG_GETARG_INT64(1); - return val1 < *val2; -} /* int48lt() */ + PG_RETURN_BOOL(val1 < val2); +} -bool -int48gt(int32 val1, int64 *val2) +Datum +int48gt(PG_FUNCTION_ARGS) { - if (!val2) - return 0; + int32 val1 = PG_GETARG_INT32(0); + int64 val2 = PG_GETARG_INT64(1); - return val1 > *val2; -} /* int48gt() */ + PG_RETURN_BOOL(val1 > val2); +} -bool -int48le(int32 val1, int64 *val2) +Datum +int48le(PG_FUNCTION_ARGS) { - if (!val2) - return 0; + int32 val1 = PG_GETARG_INT32(0); + int64 val2 = PG_GETARG_INT64(1); - return val1 <= *val2; -} /* int48le() */ + PG_RETURN_BOOL(val1 <= val2); +} -bool -int48ge(int32 val1, int64 *val2) +Datum +int48ge(PG_FUNCTION_ARGS) { - if (!val2) - return 0; + int32 val1 = PG_GETARG_INT32(0); + int64 val2 = PG_GETARG_INT64(1); - return val1 >= *val2; -} /* int48ge() */ + PG_RETURN_BOOL(val1 >= val2); +} +/* int82relop() + * Is 64-bit val1 relop 16-bit val2? + */ +Datum +int82eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int16 val2 = PG_GETARG_INT16(1); -/*---------------------------------------------------------- - * Arithmetic operators on 64-bit integers. - *---------------------------------------------------------*/ + PG_RETURN_BOOL(val1 == val2); +} -int64 * -int8um(int64 *val) +Datum +int82ne(PG_FUNCTION_ARGS) { - int64 temp = 0; - int64 *result = palloc(sizeof(int64)); + int64 val1 = PG_GETARG_INT64(0); + int16 val2 = PG_GETARG_INT16(1); - if (!PointerIsValid(val)) - return NULL; + PG_RETURN_BOOL(val1 != val2); +} - result = int8mi(&temp, val); +Datum +int82lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int16 val2 = PG_GETARG_INT16(1); - return result; -} /* int8um() */ + PG_RETURN_BOOL(val1 < val2); +} +Datum +int82gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int16 val2 = PG_GETARG_INT16(1); -int64 * -int8pl(int64 *val1, int64 *val2) + PG_RETURN_BOOL(val1 > val2); +} + +Datum +int82le(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 val1 = PG_GETARG_INT64(0); + int16 val2 = PG_GETARG_INT16(1); - if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) - return NULL; + PG_RETURN_BOOL(val1 <= val2); +} - *result = *val1 + *val2; +Datum +int82ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int16 val2 = PG_GETARG_INT16(1); - return result; -} /* int8pl() */ + PG_RETURN_BOOL(val1 >= val2); +} -int64 * -int8mi(int64 *val1, int64 *val2) +/* int28relop() + * Is 16-bit val1 relop 64-bit val2? + */ +Datum +int28eq(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int16 val1 = PG_GETARG_INT16(0); + int64 val2 = PG_GETARG_INT64(1); - if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) - return NULL; + PG_RETURN_BOOL(val1 == val2); +} - *result = *val1 - *val2; +Datum +int28ne(PG_FUNCTION_ARGS) +{ + int16 val1 = PG_GETARG_INT16(0); + int64 val2 = PG_GETARG_INT64(1); - return result; -} /* int8mi() */ + PG_RETURN_BOOL(val1 != val2); +} -int64 * -int8mul(int64 *val1, int64 *val2) +Datum +int28lt(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int16 val1 = PG_GETARG_INT16(0); + int64 val2 = PG_GETARG_INT64(1); - if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) - return NULL; + PG_RETURN_BOOL(val1 < val2); +} - *result = *val1 * *val2; +Datum +int28gt(PG_FUNCTION_ARGS) +{ + int16 val1 = PG_GETARG_INT16(0); + int64 val2 = PG_GETARG_INT64(1); - return result; -} /* int8mul() */ + PG_RETURN_BOOL(val1 > val2); +} -int64 * -int8div(int64 *val1, int64 *val2) +Datum +int28le(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int16 val1 = PG_GETARG_INT16(0); + int64 val2 = PG_GETARG_INT64(1); - if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) - return NULL; + PG_RETURN_BOOL(val1 <= val2); +} - *result = *val1 / *val2; +Datum +int28ge(PG_FUNCTION_ARGS) +{ + int16 val1 = PG_GETARG_INT16(0); + int64 val2 = PG_GETARG_INT64(1); - return result; -} /* int8div() */ + PG_RETURN_BOOL(val1 >= val2); +} -/* int8abs() - * Absolute value - */ -int64 * -int8abs(int64 *arg1) + +/*---------------------------------------------------------- + * Arithmetic operators on 64-bit integers. + *---------------------------------------------------------*/ + +Datum +int8um(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + int64 result; + + result = -arg; + /* overflow check (needed for INT64_MIN) */ + if (arg != 0 && SAMESIGN(result, arg)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int8up(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + + PG_RETURN_INT64(arg); +} + +Datum +int8pl(PG_FUNCTION_ARGS) { - int64 *result; + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 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("bigint out of range"))); + PG_RETURN_INT64(result); +} - if (!PointerIsValid(arg1)) - return NULL; +Datum +int8mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; - result = palloc(sizeof(*result)); + result = arg1 - arg2; - *result = ((*arg1 < 0) ? -*arg1 : *arg1); + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} - return result; +Datum +int8mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 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 = INT64_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 int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) || arg2 != (int64) ((int32) arg2)) + { + if (arg2 != 0 && + (result / arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + } + PG_RETURN_INT64(result); +} + +Datum +int8div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + if (arg2 == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + + result = arg1 / arg2; + + /* + * Overflow check. The only possible overflow case is for arg1 = + * INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN, which + * can't be represented on a two's-complement machine. Most machines + * produce INT64_MIN but it seems some produce zero. + */ + if (arg2 == -1 && arg1 < 0 && result <= 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +/* int8abs() + * Absolute value + */ +Datum +int8abs(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 result; + + result = (arg1 < 0) ? -arg1 : arg1; + /* overflow check (needed for INT64_MIN) */ + if (result < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); } /* int8mod() * Modulo operation. */ -int64 * -int8mod(int64 *val1, int64 *val2) +Datum +int8mod(PG_FUNCTION_ARGS) { - int64 *result; + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + + if (arg2 == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* No overflow is possible */ + + PG_RETURN_INT64(arg1 % arg2); +} - /* use the divide operation to check params and allocate storage */ - result = int8div(val1, val2); - *result *= *val2; - *result = *val1 - *result; - return result; -} /* int8mod() */ +Datum +int8inc(PG_FUNCTION_ARGS) +{ + /* + * When int8 is pass-by-reference, we provide this special case to avoid + * palloc overhead for COUNT(): when called from nodeAgg, we know that the + * argument is modifiable local storage, so just update it in-place. (If + * int8 is pass-by-value, then of course this is useless as well as + * incorrect, so just ifdef it out.) + */ +#ifndef USE_FLOAT8_BYVAL /* controls int8 too */ + if (fcinfo->context && + (IsA(fcinfo->context, AggState) || + IsA(fcinfo->context, WindowAggState))) + { + int64 *arg = (int64 *) PG_GETARG_POINTER(0); + int64 result; + + result = *arg + 1; + /* Overflow check */ + if (result < 0 && *arg > 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + + *arg = result; + PG_RETURN_POINTER(arg); + } + else +#endif + { + /* Not called by nodeAgg, so just do it the dumb way */ + int64 arg = PG_GETARG_INT64(0); + int64 result; + + result = arg + 1; + /* Overflow check */ + if (result < 0 && arg > 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + + PG_RETURN_INT64(result); + } +} -/* int8fac() - * Factorial +/* + * These functions are exactly like int8inc but are used for aggregates that + * count only non-null values. Since the functions are declared strict, + * the null checks happen before we ever get here, and all we need do is + * increment the state value. We could actually make these pg_proc entries + * point right at int8inc, but then the opr_sanity regression test would + * complain about mismatched entries for a built-in function. */ -int64 * -int8fac(int64 *arg1) + +Datum +int8inc_any(PG_FUNCTION_ARGS) { - int64 *result; - int64 i; + return int8inc(fcinfo); +} - if (!PointerIsValid(arg1)) - return NULL; +Datum +int8inc_float8_float8(PG_FUNCTION_ARGS) +{ + return int8inc(fcinfo); +} - result = palloc(sizeof(*result)); - if (*arg1 < 1) - *result = 0; - else - for (i = *arg1, *result = 1; i > 0; --i) - *result *= i; +Datum +int8larger(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = ((arg1 > arg2) ? arg1 : arg2); - return result; + PG_RETURN_INT64(result); } -int64 * -int8larger(int64 *val1, int64 *val2) +Datum +int8smaller(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = ((arg1 < arg2) ? arg1 : arg2); + + PG_RETURN_INT64(result); +} - if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) - return NULL; +Datum +int84pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; - *result = ((*val1 > *val2) ? *val1 : *val2); + result = arg1 + arg2; - return result; -} /* int8larger() */ + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} -int64 * -int8smaller(int64 *val1, int64 *val2) +Datum +int84mi(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; + + result = arg1 - arg2; - if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) - return NULL; + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} - *result = ((*val1 < *val2) ? *val1 : *val2); +Datum +int84mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; - return result; -} /* int8smaller() */ + 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 int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} -int64 * -int84pl(int64 *val1, int32 val2) +Datum +int84div(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; - if (!PointerIsValid(val1)) - return NULL; + if (arg2 == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); - *result = *val1 + (int64) val2; + result = arg1 / arg2; - return result; -} /* int84pl() */ + /* + * Overflow check. The only possible overflow case is for arg1 = + * INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN, which + * can't be represented on a two's-complement machine. Most machines + * produce INT64_MIN but it seems some produce zero. + */ + if (arg2 == -1 && arg1 < 0 && result <= 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} -int64 * -int84mi(int64 *val1, int32 val2) +Datum +int48pl(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int32 arg1 = PG_GETARG_INT32(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; - if (!PointerIsValid(val1)) - return NULL; + result = arg1 + arg2; - *result = *val1 - (int64) val2; + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int48mi(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; - return result; -} /* int84mi() */ + result = arg1 - arg2; -int64 * -int84mul(int64 *val1, int32 val2) + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int48mul(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int32 arg1 = PG_GETARG_INT32(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = arg1 * arg2; - if (!PointerIsValid(val1)) - return NULL; + /* + * 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 int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != arg1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int48div(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int64 arg2 = PG_GETARG_INT64(1); - *result = *val1 * (int64) val2; + 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(); + } - return result; -} /* int84mul() */ + /* No overflow is possible */ + PG_RETURN_INT64((int64) arg1 / arg2); +} -int64 * -int84div(int64 *val1, int32 val2) +Datum +int82pl(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; - if (!PointerIsValid(val1)) - return NULL; + result = arg1 + arg2; - *result = *val1 / (int64) val2; + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int82mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; - return result; -} /* int84div() */ + 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("bigint out of range"))); + PG_RETURN_INT64(result); +} -int64 * -int48pl(int32 val1, int64 *val2) +Datum +int82mul(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; - if (!PointerIsValid(val2)) - return NULL; + result = arg1 * arg2; - *result = (int64) val1 + *val2; + /* + * 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 int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} - return result; -} /* int48pl() */ +Datum +int82div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; -int64 * -int48mi(int32 val1, int64 *val2) + if (arg2 == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + + result = arg1 / arg2; + + /* + * Overflow check. The only possible overflow case is for arg1 = + * INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN, which + * can't be represented on a two's-complement machine. Most machines + * produce INT64_MIN but it seems some produce zero. + */ + if (arg2 == -1 && arg1 < 0 && result <= 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int28pl(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; - if (!PointerIsValid(val2)) - return NULL; + result = arg1 + arg2; - *result = (int64) val1 - *val2; + /* + * 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("bigint out of range"))); + PG_RETURN_INT64(result); +} - return result; -} /* int48mi() */ +Datum +int28mi(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 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("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int28mul(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 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 int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != arg1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} -int64 * -int48mul(int32 val1, int64 *val2) +Datum +int28div(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); - if (!PointerIsValid(val2)) - return NULL; + 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(); + } - *result = (int64) val1 **val2; + /* No overflow is possible */ + PG_RETURN_INT64((int64) arg1 / arg2); +} - return result; -} /* int48mul() */ +/* Binary arithmetics + * + * int8and - returns arg1 & arg2 + * int8or - returns arg1 | arg2 + * int8xor - returns arg1 # arg2 + * int8not - returns ~arg1 + * int8shl - returns arg1 << arg2 + * int8shr - returns arg1 >> arg2 + */ -int64 * -int48div(int32 val1, int64 *val2) +Datum +int8and(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); - if (!PointerIsValid(val2)) - return NULL; + PG_RETURN_INT64(arg1 & arg2); +} - *result = (int64) val1 / *val2; +Datum +int8or(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); - return result; -} /* int48div() */ + PG_RETURN_INT64(arg1 | arg2); +} + +Datum +int8xor(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + + PG_RETURN_INT64(arg1 ^ arg2); +} +Datum +int8not(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + + PG_RETURN_INT64(~arg1); +} + +Datum +int8shl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_INT64(arg1 << arg2); +} + +Datum +int8shr(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_INT64(arg1 >> arg2); +} /*---------------------------------------------------------- * Conversion operators. *---------------------------------------------------------*/ -int64 * -int48(int32 val) +Datum +int48(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); - - *result = val; + int32 arg = PG_GETARG_INT32(0); - return result; -} /* int48() */ + PG_RETURN_INT64((int64) arg); +} -int32 -int84(int64 *val) +Datum +int84(PG_FUNCTION_ARGS) { + int64 arg = PG_GETARG_INT64(0); int32 result; - if (!PointerIsValid(val)) - elog(ERROR, "Invalid (null) int64, can't convert int8 to int4"); + result = (int32) arg; + + /* Test for overflow by reverse-conversion. */ + if ((int64) result != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); - if ((*val < INT_MIN) || (*val > INT_MAX)) - elog(ERROR, "int8 conversion to int4 is out of range"); + PG_RETURN_INT32(result); +} - result = *val; +Datum +int28(PG_FUNCTION_ARGS) +{ + int16 arg = PG_GETARG_INT16(0); - return result; -} /* int84() */ + PG_RETURN_INT64((int64) arg); +} -#if NOT_USED -int64 * -int2vector (int16 val) +Datum +int82(PG_FUNCTION_ARGS) { - int64 *result; + int64 arg = PG_GETARG_INT64(0); + int16 result; - result = palloc(sizeof(int64)); + result = (int16) arg; - *result = val; + /* Test for overflow by reverse-conversion. */ + if ((int64) result != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("smallint out of range"))); - return result; -} /* int2vector() */ + PG_RETURN_INT16(result); +} -int16 -int82(int64 *val) +Datum +i8tod(PG_FUNCTION_ARGS) { - int16 result; + int64 arg = PG_GETARG_INT64(0); + float8 result; + + result = arg; - if (!PointerIsValid(val)) - elog(ERROR, "Invalid (null) int8, can't convert to int2"); + PG_RETURN_FLOAT8(result); +} + +/* dtoi8() + * Convert float8 to 8-byte integer. + */ +Datum +dtoi8(PG_FUNCTION_ARGS) +{ + float8 arg = PG_GETARG_FLOAT8(0); + int64 result; - if ((*val < SHRT_MIN) || (*val > SHRT_MAX)) - elog(ERROR, "int8 conversion to int2 is out of range"); + /* Round arg to nearest integer (but it's still in float form) */ + arg = rint(arg); - result = *val; + /* + * Does it fit in an int64? Avoid assuming that we have handy constants + * defined for the range boundaries, instead test for overflow by + * reverse-conversion. + */ + result = (int64) arg; - return result; -} /* int82() */ + if ((float8) result != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); -#endif + PG_RETURN_INT64(result); +} -float64 -i8tod(int64 *val) +Datum +i8tof(PG_FUNCTION_ARGS) { - float64 result = palloc(sizeof(float64data)); - - if (!PointerIsValid(val)) - elog(ERROR, "Invalid (null) int8, can't convert to float8"); + int64 arg = PG_GETARG_INT64(0); + float4 result; - *result = *val; + result = arg; - return result; -} /* i8tod() */ + PG_RETURN_FLOAT4(result); +} -/* dtoi8() - * Convert double float to 8-byte integer. - * Do a range check before the conversion. - * Note that the comparison probably isn't quite right - * since we only have ~52 bits of precision in a double float - * and so subtracting one from a large number gives the large - * number exactly. However, for some reason the comparison below - * does the right thing on my i686/linux-rh4.2 box. - * - thomas 1998-06-16 +/* ftoi8() + * Convert float4 to 8-byte integer. */ -int64 * -dtoi8(float64 val) +Datum +ftoi8(PG_FUNCTION_ARGS) { - int64 *result = palloc(sizeof(int64)); + float4 arg = PG_GETARG_FLOAT4(0); + int64 result; + float8 darg; - if (!PointerIsValid(val)) - elog(ERROR, "Invalid (null) float8, can't convert to int8"); + /* Round arg to nearest integer (but it's still in float form) */ + darg = rint(arg); - if ((*val < (-pow(2, 63) + 1)) || (*val > (pow(2, 63) - 1))) - elog(ERROR, "Floating point conversion to int64 is out of range"); + /* + * Does it fit in an int64? Avoid assuming that we have handy constants + * defined for the range boundaries, instead test for overflow by + * reverse-conversion. + */ + result = (int64) darg; - *result = *val; + if ((float8) result != darg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); - return result; -} /* dtoi8() */ + PG_RETURN_INT64(result); +} -/* text_int8() - */ -int64 * -text_int8(text *str) +Datum +i8tooid(PG_FUNCTION_ARGS) { - int len; - char *s; + int64 arg = PG_GETARG_INT64(0); + Oid result; + + result = (Oid) arg; - if (!PointerIsValid(str)) - elog(ERROR, "Bad (null) int8 external representation"); + /* Test for overflow by reverse-conversion. */ + if ((int64) result != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("OID out of range"))); - len = (VARSIZE(str) - VARHDRSZ); - s = palloc(len + 1); - memmove(s, VARDATA(str), len); - *(s + len) = '\0'; + PG_RETURN_OID(result); +} - return int8in(s); -} /* text_int8() */ +Datum +oidtoi8(PG_FUNCTION_ARGS) +{ + Oid arg = PG_GETARG_OID(0); + PG_RETURN_INT64((int64) arg); +} -/* int8_text() +/* + * non-persistent numeric series generator */ -text * -int8_text(int64 *val) +Datum +generate_series_int8(PG_FUNCTION_ARGS) { - text *result; + return generate_series_step_int8(fcinfo); +} - int len; - char *s; +Datum +generate_series_step_int8(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + generate_series_fctx *fctx; + int64 result; + MemoryContext oldcontext; - if (!PointerIsValid(val)) - return NULL; + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + int64 start = PG_GETARG_INT64(0); + int64 finish = PG_GETARG_INT64(1); + int64 step = 1; + + /* see if we were given an explicit step size */ + if (PG_NARGS() == 3) + step = PG_GETARG_INT64(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); + } - s = int8out(val); - len = strlen(s); + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); - result = palloc(VARHDRSZ + len); + /* + * get the saved state and use current as the result for this iteration + */ + fctx = funcctx->user_fctx; + result = fctx->current; - VARSIZE(result) = len + VARHDRSZ; - memmove(VARDATA(result), s, len); + 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; - return result; -} /* int8_text() */ + /* do when there is more left to send */ + SRF_RETURN_NEXT(funcctx, Int64GetDatum(result)); + } + else + /* do when there is no more left */ + SRF_RETURN_DONE(funcctx); +}