mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-07-18 05:21:10 +02:00
These functions were originally added in commit d8cedf67a
to support
use of int2vector columns as catcache lookup keys. However, there are
no catcaches that use such columns. (Indeed I now think it must always
have been dead code: a catcache with such a key column would need an
underlying unique index on the column, but we've never had an int2vector
btree opclass.)
Getting rid of the int2vector-specific operator and function does not
lose any functionality, because operations on int2vectors will now fall
back to the generic anyarray support. This avoids a wart that a btree
index on an int2vector column (made using anyarray_ops) would fail to
match equality searches, because int2vectoreq wasn't a member of the
opclass. We don't really care much about that, since int2vector is not
meant as a type for users to use, but it's silly to have extra code and
less functionality.
If we ever do want a catcache to be indexed by an int2vector column,
we'd need to put back full btree and hash opclasses for int2vector,
comparable to the support for oidvector. (The anyarray code can't be
used at such a low level, because it needs to do catcache lookups.)
But we'll deal with that if/when the need arises.
Also worth noting is that removal of the hash int2vector_ops opclass will
break any user-created hash indexes on int2vector columns. While hash
anyarray_ops would serve the same purpose, it would probably not compute
the same hash values and thus wouldn't be on-disk-compatible. Given that
int2vector isn't a user-facing type and we're planning other incompatible
changes in hash indexes for v10 anyway, this doesn't seem like something
to worry about, but it's probably worth mentioning here.
Amit Langote
Discussion: <d9bb74f8-b194-7307-9ebd-90645d377e45@lab.ntt.co.jp>
1398 lines
29 KiB
C
1398 lines
29 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* int.c
|
|
* Functions for the built-in integer types (except int8).
|
|
*
|
|
* Portions Copyright (c) 1996-2016, 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 <ctype.h>
|
|
#include <limits.h>
|
|
|
|
#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);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* 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);
|
|
}
|