diff options
Diffstat (limited to '')
-rw-r--r-- | src/backend/utils/adt/oid.c | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c new file mode 100644 index 0000000..fd94e0c --- /dev/null +++ b/src/backend/utils/adt/oid.c @@ -0,0 +1,471 @@ +/*------------------------------------------------------------------------- + * + * oid.c + * Functions for the built-in type Oid ... also oidvector. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/oid.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <ctype.h> +#include <limits.h> + +#include "catalog/pg_type.h" +#include "libpq/pqformat.h" +#include "nodes/value.h" +#include "utils/array.h" +#include "utils/builtins.h" + + +#define OidVectorSize(n) (offsetof(oidvector, values) + (n) * sizeof(Oid)) + + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +static Oid +oidin_subr(const char *s, char **endloc) +{ + unsigned long cvt; + char *endptr; + Oid result; + + if (*s == '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); + + errno = 0; + cvt = strtoul(s, &endptr, 10); + + /* + * strtoul() normally only sets ERANGE. On some systems it also may set + * EINVAL, which simply means it couldn't parse the input string. This is + * handled by the second "if" consistent across platforms. + */ + if (errno && errno != ERANGE && errno != EINVAL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); + + if (endptr == s && *s != '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); + + if (errno == ERANGE) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + s, "oid"))); + + if (endloc) + { + /* caller wants to deal with rest of string */ + *endloc = endptr; + } + else + { + /* allow only whitespace after number */ + while (*endptr && isspace((unsigned char) *endptr)) + endptr++; + if (*endptr) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); + } + + result = (Oid) cvt; + + /* + * Cope with possibility that unsigned long is wider than Oid, in which + * case strtoul will not raise an error for some values that are out of + * the range of Oid. + * + * For backwards compatibility, we want to accept inputs that are given + * with a minus sign, so allow the input value if it matches after either + * signed or unsigned extension to long. + * + * To ensure consistent results on 32-bit and 64-bit platforms, make sure + * the error message is the same as if strtoul() had returned ERANGE. + */ +#if OID_MAX != ULONG_MAX + if (cvt != (unsigned long) result && + cvt != (unsigned long) ((int) result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + s, "oid"))); +#endif + + return result; +} + +Datum +oidin(PG_FUNCTION_ARGS) +{ + char *s = PG_GETARG_CSTRING(0); + Oid result; + + result = oidin_subr(s, NULL); + PG_RETURN_OID(result); +} + +Datum +oidout(PG_FUNCTION_ARGS) +{ + Oid o = PG_GETARG_OID(0); + char *result = (char *) palloc(12); + + snprintf(result, 12, "%u", o); + PG_RETURN_CSTRING(result); +} + +/* + * oidrecv - converts external binary format to oid + */ +Datum +oidrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + + PG_RETURN_OID((Oid) pq_getmsgint(buf, sizeof(Oid))); +} + +/* + * oidsend - converts oid to binary format + */ +Datum +oidsend(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendint32(&buf, arg1); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + +/* + * construct oidvector given a raw array of Oids + * + * If oids is NULL then caller must fill values[] afterward + */ +oidvector * +buildoidvector(const Oid *oids, int n) +{ + oidvector *result; + + result = (oidvector *) palloc0(OidVectorSize(n)); + + if (n > 0 && oids) + memcpy(result->values, oids, n * sizeof(Oid)); + + /* + * Attach standard array header. For historical reasons, we set the index + * lower bound to 0 not 1. + */ + SET_VARSIZE(result, OidVectorSize(n)); + result->ndim = 1; + result->dataoffset = 0; /* never any nulls */ + result->elemtype = OIDOID; + result->dim1 = n; + result->lbound1 = 0; + + return result; +} + +/* + * oidvectorin - converts "num num ..." to internal form + */ +Datum +oidvectorin(PG_FUNCTION_ARGS) +{ + char *oidString = PG_GETARG_CSTRING(0); + oidvector *result; + int n; + + result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS)); + + for (n = 0; n < FUNC_MAX_ARGS; n++) + { + while (*oidString && isspace((unsigned char) *oidString)) + oidString++; + if (*oidString == '\0') + break; + result->values[n] = oidin_subr(oidString, &oidString); + } + while (*oidString && isspace((unsigned char) *oidString)) + oidString++; + if (*oidString) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("oidvector has too many elements"))); + + SET_VARSIZE(result, OidVectorSize(n)); + result->ndim = 1; + result->dataoffset = 0; /* never any nulls */ + result->elemtype = OIDOID; + result->dim1 = n; + result->lbound1 = 0; + + PG_RETURN_POINTER(result); +} + +/* + * oidvectorout - converts internal form to "num num ..." + */ +Datum +oidvectorout(PG_FUNCTION_ARGS) +{ + oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); + int num, + nnums = oidArray->dim1; + char *rp; + char *result; + + /* assumes sign, 10 digits, ' ' */ + rp = result = (char *) palloc(nnums * 12 + 1); + for (num = 0; num < nnums; num++) + { + if (num != 0) + *rp++ = ' '; + sprintf(rp, "%u", oidArray->values[num]); + while (*++rp != '\0') + ; + } + *rp = '\0'; + PG_RETURN_CSTRING(result); +} + +/* + * oidvectorrecv - converts external binary format to oidvector + */ +Datum +oidvectorrecv(PG_FUNCTION_ARGS) +{ + LOCAL_FCINFO(locfcinfo, 3); + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + oidvector *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->args[0].value = PointerGetDatum(buf); + locfcinfo->args[0].isnull = false; + locfcinfo->args[1].value = ObjectIdGetDatum(OIDOID); + locfcinfo->args[1].isnull = false; + locfcinfo->args[2].value = Int32GetDatum(-1); + locfcinfo->args[2].isnull = false; + + result = (oidvector *) DatumGetPointer(array_recv(locfcinfo)); + + Assert(!locfcinfo->isnull); + + /* sanity checks: oidvector must be 1-D, 0-based, no nulls */ + if (ARR_NDIM(result) != 1 || + ARR_HASNULL(result) || + ARR_ELEMTYPE(result) != OIDOID || + ARR_LBOUND(result)[0] != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid oidvector data"))); + + /* check length for consistency with oidvectorin() */ + 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); +} + +/* + * oidvectorsend - converts oidvector to binary format + */ +Datum +oidvectorsend(PG_FUNCTION_ARGS) +{ + return array_send(fcinfo); +} + +/* + * oidparse - get OID from ICONST/FCONST node + */ +Oid +oidparse(Node *node) +{ + switch (nodeTag(node)) + { + case T_Integer: + return intVal(node); + case T_Float: + + /* + * Values too large for int4 will be represented as Float + * constants by the lexer. Accept these if they are valid OID + * strings. + */ + return oidin_subr(strVal(node), NULL); + default: + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); + } + return InvalidOid; /* keep compiler quiet */ +} + +/* qsort comparison function for Oids */ +int +oid_cmp(const void *p1, const void *p2) +{ + Oid v1 = *((const Oid *) p1); + Oid v2 = *((const Oid *) p2); + + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; +} + + +/***************************************************************************** + * PUBLIC ROUTINES * + *****************************************************************************/ + +Datum +oideq(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_BOOL(arg1 == arg2); +} + +Datum +oidne(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_BOOL(arg1 != arg2); +} + +Datum +oidlt(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_BOOL(arg1 < arg2); +} + +Datum +oidle(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_BOOL(arg1 <= arg2); +} + +Datum +oidge(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_BOOL(arg1 >= arg2); +} + +Datum +oidgt(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_BOOL(arg1 > arg2); +} + +Datum +oidlarger(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2); +} + +Datum +oidsmaller(PG_FUNCTION_ARGS) +{ + Oid arg1 = PG_GETARG_OID(0); + Oid arg2 = PG_GETARG_OID(1); + + PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2); +} + +Datum +oidvectoreq(PG_FUNCTION_ARGS) +{ + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp == 0); +} + +Datum +oidvectorne(PG_FUNCTION_ARGS) +{ + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp != 0); +} + +Datum +oidvectorlt(PG_FUNCTION_ARGS) +{ + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp < 0); +} + +Datum +oidvectorle(PG_FUNCTION_ARGS) +{ + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp <= 0); +} + +Datum +oidvectorge(PG_FUNCTION_ARGS) +{ + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp >= 0); +} + +Datum +oidvectorgt(PG_FUNCTION_ARGS) +{ + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp > 0); +} |