2007-04-02 05:49:42 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* enum.c
|
2007-11-15 22:14:46 +01:00
|
|
|
* I/O functions, operators, aggregates etc for enum types
|
2007-04-02 05:49:42 +02:00
|
|
|
*
|
2015-01-06 17:43:47 +01:00
|
|
|
* Copyright (c) 2006-2015, PostgreSQL Global Development Group
|
2007-04-02 05:49:42 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/enum.c
|
2007-04-02 05:49:42 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
#include "access/genam.h"
|
|
|
|
#include "access/heapam.h"
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2010-10-25 05:04:37 +02:00
|
|
|
#include "catalog/indexing.h"
|
2007-04-02 05:49:42 +02:00
|
|
|
#include "catalog/pg_enum.h"
|
2010-10-25 05:04:37 +02:00
|
|
|
#include "libpq/pqformat.h"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "utils/array.h"
|
2007-04-02 05:49:42 +02:00
|
|
|
#include "utils/builtins.h"
|
2010-10-25 05:04:37 +02:00
|
|
|
#include "utils/fmgroids.h"
|
|
|
|
#include "utils/snapmgr.h"
|
2007-04-02 05:49:42 +02:00
|
|
|
#include "utils/syscache.h"
|
2010-10-25 05:04:37 +02:00
|
|
|
#include "utils/typcache.h"
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
static Oid enum_endpoint(Oid enumtypoid, ScanDirection direction);
|
2007-04-02 05:49:42 +02:00
|
|
|
static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper);
|
|
|
|
|
|
|
|
|
|
|
|
/* Basic I/O support */
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_in(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char *name = PG_GETARG_CSTRING(0);
|
|
|
|
Oid enumtypoid = PG_GETARG_OID(1);
|
|
|
|
Oid enumoid;
|
|
|
|
HeapTuple tup;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2007-04-03 00:14:17 +02:00
|
|
|
/* must check length to prevent Assert failure within SearchSysCache */
|
|
|
|
if (strlen(name) >= NAMEDATALEN)
|
2007-06-05 23:31:09 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input value for enum %s: \"%s\"",
|
2007-04-03 00:14:17 +02:00
|
|
|
format_type_be(enumtypoid),
|
2007-06-05 23:31:09 +02:00
|
|
|
name)));
|
2007-04-03 00:14:17 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache2(ENUMTYPOIDNAME,
|
|
|
|
ObjectIdGetDatum(enumtypoid),
|
|
|
|
CStringGetDatum(name));
|
2007-06-05 23:31:09 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input value for enum %s: \"%s\"",
|
2007-04-02 05:49:42 +02:00
|
|
|
format_type_be(enumtypoid),
|
2007-06-05 23:31:09 +02:00
|
|
|
name)));
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2009-12-19 01:47:57 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* This comes from pg_enum.oid and stores system oids in user tables. This
|
|
|
|
* oid must be preserved by binary upgrades.
|
2009-12-19 01:47:57 +01:00
|
|
|
*/
|
2007-04-02 05:49:42 +02:00
|
|
|
enumoid = HeapTupleGetOid(tup);
|
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
2007-06-05 23:31:09 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(enumoid);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid enumval = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
HeapTuple tup;
|
2007-04-02 05:49:42 +02:00
|
|
|
Form_pg_enum en;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enumval));
|
2007-06-05 23:31:09 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
|
|
errmsg("invalid internal value for enum: %u",
|
|
|
|
enumval)));
|
2007-04-02 05:49:42 +02:00
|
|
|
en = (Form_pg_enum) GETSTRUCT(tup);
|
|
|
|
|
2007-06-05 23:31:09 +02:00
|
|
|
result = pstrdup(NameStr(en->enumlabel));
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
2007-06-05 23:31:09 +02:00
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
2007-09-04 18:41:43 +02:00
|
|
|
/* Binary I/O support */
|
|
|
|
Datum
|
|
|
|
enum_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
Oid enumtypoid = PG_GETARG_OID(1);
|
|
|
|
Oid enumoid;
|
|
|
|
HeapTuple tup;
|
|
|
|
char *name;
|
|
|
|
int nbytes;
|
2007-09-04 18:41:43 +02:00
|
|
|
|
|
|
|
name = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
|
|
|
|
|
|
|
|
/* must check length to prevent Assert failure within SearchSysCache */
|
|
|
|
if (strlen(name) >= NAMEDATALEN)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input value for enum %s: \"%s\"",
|
|
|
|
format_type_be(enumtypoid),
|
|
|
|
name)));
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache2(ENUMTYPOIDNAME,
|
|
|
|
ObjectIdGetDatum(enumtypoid),
|
|
|
|
CStringGetDatum(name));
|
2007-09-04 18:41:43 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input value for enum %s: \"%s\"",
|
|
|
|
format_type_be(enumtypoid),
|
|
|
|
name)));
|
|
|
|
|
|
|
|
enumoid = HeapTupleGetOid(tup);
|
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
pfree(name);
|
|
|
|
|
|
|
|
PG_RETURN_OID(enumoid);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid enumval = PG_GETARG_OID(0);
|
2007-09-04 18:41:43 +02:00
|
|
|
StringInfoData buf;
|
2007-11-15 22:14:46 +01:00
|
|
|
HeapTuple tup;
|
2007-09-04 18:41:43 +02:00
|
|
|
Form_pg_enum en;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enumval));
|
2007-09-04 18:41:43 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
|
|
errmsg("invalid internal value for enum: %u",
|
|
|
|
enumval)));
|
|
|
|
en = (Form_pg_enum) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendtext(&buf, NameStr(en->enumlabel), strlen(NameStr(en->enumlabel)));
|
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
/* Comparison functions and related */
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
/*
|
|
|
|
* enum_cmp_internal is the common engine for all the visible comparison
|
|
|
|
* functions, except for enum_eq and enum_ne which can just check for OID
|
|
|
|
* equality directly.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
enum_cmp_internal(Oid arg1, Oid arg2, FunctionCallInfo fcinfo)
|
|
|
|
{
|
|
|
|
TypeCacheEntry *tcache;
|
|
|
|
|
|
|
|
/* Equal OIDs are equal no matter what */
|
|
|
|
if (arg1 == arg2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Fast path: even-numbered Oids are known to compare correctly */
|
|
|
|
if ((arg1 & 1) == 0 && (arg2 & 1) == 0)
|
|
|
|
{
|
|
|
|
if (arg1 < arg2)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Locate the typcache entry for the enum type */
|
|
|
|
tcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
|
|
|
if (tcache == NULL)
|
|
|
|
{
|
|
|
|
HeapTuple enum_tup;
|
|
|
|
Form_pg_enum en;
|
|
|
|
Oid typeoid;
|
|
|
|
|
|
|
|
/* Get the OID of the enum type containing arg1 */
|
|
|
|
enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(arg1));
|
|
|
|
if (!HeapTupleIsValid(enum_tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
|
|
errmsg("invalid internal value for enum: %u",
|
|
|
|
arg1)));
|
|
|
|
en = (Form_pg_enum) GETSTRUCT(enum_tup);
|
|
|
|
typeoid = en->enumtypid;
|
|
|
|
ReleaseSysCache(enum_tup);
|
|
|
|
/* Now locate and remember the typcache entry */
|
|
|
|
tcache = lookup_type_cache(typeoid, 0);
|
|
|
|
fcinfo->flinfo->fn_extra = (void *) tcache;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The remaining comparison logic is in typcache.c */
|
|
|
|
return compare_values_of_enum(tcache, arg1, arg2);
|
|
|
|
}
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
Datum
|
|
|
|
enum_lt(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) < 0);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_le(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) <= 0);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_eq(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(a == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_ne(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
PG_RETURN_BOOL(a != b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_ge(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) >= 0);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_gt(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) > 0);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_smaller(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
PG_RETURN_OID(enum_cmp_internal(a, b, fcinfo) < 0 ? a : b);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_larger(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
PG_RETURN_OID(enum_cmp_internal(a, b, fcinfo) > 0 ? a : b);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid a = PG_GETARG_OID(0);
|
|
|
|
Oid b = PG_GETARG_OID(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
if (a == b)
|
2007-04-02 05:49:42 +02:00
|
|
|
PG_RETURN_INT32(0);
|
2010-10-25 05:04:37 +02:00
|
|
|
else if (enum_cmp_internal(a, b, fcinfo) > 0)
|
|
|
|
PG_RETURN_INT32(1);
|
2007-04-02 05:49:42 +02:00
|
|
|
else
|
|
|
|
PG_RETURN_INT32(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enum programming support functions */
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
/*
|
|
|
|
* enum_endpoint: common code for enum_first/enum_last
|
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
enum_endpoint(Oid enumtypoid, ScanDirection direction)
|
|
|
|
{
|
|
|
|
Relation enum_rel;
|
|
|
|
Relation enum_idx;
|
|
|
|
SysScanDesc enum_scan;
|
|
|
|
HeapTuple enum_tuple;
|
|
|
|
ScanKeyData skey;
|
|
|
|
Oid minmax;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the first/last enum member using pg_enum_typid_sortorder_index.
|
|
|
|
* Note we must not use the syscache, and must use an MVCC snapshot here.
|
|
|
|
* See comments for RenumberEnumType in catalog/pg_enum.c for more info.
|
|
|
|
*/
|
|
|
|
ScanKeyInit(&skey,
|
|
|
|
Anum_pg_enum_enumtypid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(enumtypoid));
|
|
|
|
|
|
|
|
enum_rel = heap_open(EnumRelationId, AccessShareLock);
|
|
|
|
enum_idx = index_open(EnumTypIdSortOrderIndexId, AccessShareLock);
|
|
|
|
enum_scan = systable_beginscan_ordered(enum_rel, enum_idx,
|
|
|
|
GetTransactionSnapshot(),
|
|
|
|
1, &skey);
|
|
|
|
|
|
|
|
enum_tuple = systable_getnext_ordered(enum_scan, direction);
|
|
|
|
if (HeapTupleIsValid(enum_tuple))
|
|
|
|
minmax = HeapTupleGetOid(enum_tuple);
|
|
|
|
else
|
|
|
|
minmax = InvalidOid;
|
|
|
|
|
|
|
|
systable_endscan_ordered(enum_scan);
|
|
|
|
index_close(enum_idx, AccessShareLock);
|
|
|
|
heap_close(enum_rel, AccessShareLock);
|
|
|
|
|
|
|
|
return minmax;
|
|
|
|
}
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
Datum
|
|
|
|
enum_first(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid enumtypoid;
|
2010-10-25 05:04:37 +02:00
|
|
|
Oid min;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We rely on being able to get the specific enum type from the calling
|
|
|
|
* expression tree. Notice that the actual value of the argument isn't
|
|
|
|
* examined at all; in particular it might be NULL.
|
|
|
|
*/
|
|
|
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
|
|
|
if (enumtypoid == InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("could not determine actual enum type")));
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
/* Get the OID using the index */
|
|
|
|
min = enum_endpoint(enumtypoid, ForwardScanDirection);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
if (!OidIsValid(min))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("enum %s contains no values",
|
|
|
|
format_type_be(enumtypoid))));
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(min);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
enum_last(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid enumtypoid;
|
2010-10-25 05:04:37 +02:00
|
|
|
Oid max;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We rely on being able to get the specific enum type from the calling
|
|
|
|
* expression tree. Notice that the actual value of the argument isn't
|
|
|
|
* examined at all; in particular it might be NULL.
|
|
|
|
*/
|
|
|
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
|
|
|
if (enumtypoid == InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("could not determine actual enum type")));
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
/* Get the OID using the index */
|
|
|
|
max = enum_endpoint(enumtypoid, BackwardScanDirection);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
if (!OidIsValid(max))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("enum %s contains no values",
|
|
|
|
format_type_be(enumtypoid))));
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2007-06-05 23:31:09 +02:00
|
|
|
PG_RETURN_OID(max);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 2-argument variant of enum_range */
|
|
|
|
Datum
|
|
|
|
enum_range_bounds(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid lower;
|
|
|
|
Oid upper;
|
|
|
|
Oid enumtypoid;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
if (PG_ARGISNULL(0))
|
|
|
|
lower = InvalidOid;
|
|
|
|
else
|
|
|
|
lower = PG_GETARG_OID(0);
|
|
|
|
if (PG_ARGISNULL(1))
|
|
|
|
upper = InvalidOid;
|
|
|
|
else
|
|
|
|
upper = PG_GETARG_OID(1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We rely on being able to get the specific enum type from the calling
|
|
|
|
* expression tree. The generic type mechanism should have ensured that
|
|
|
|
* both are of the same type.
|
|
|
|
*/
|
|
|
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
|
|
|
if (enumtypoid == InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("could not determine actual enum type")));
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 1-argument variant of enum_range */
|
|
|
|
Datum
|
|
|
|
enum_range_all(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid enumtypoid;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We rely on being able to get the specific enum type from the calling
|
|
|
|
* expression tree. Notice that the actual value of the argument isn't
|
|
|
|
* examined at all; in particular it might be NULL.
|
|
|
|
*/
|
|
|
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
|
|
|
if (enumtypoid == InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("could not determine actual enum type")));
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid,
|
|
|
|
InvalidOid, InvalidOid));
|
|
|
|
}
|
|
|
|
|
|
|
|
static ArrayType *
|
|
|
|
enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
ArrayType *result;
|
2010-10-25 05:04:37 +02:00
|
|
|
Relation enum_rel;
|
|
|
|
Relation enum_idx;
|
|
|
|
SysScanDesc enum_scan;
|
|
|
|
HeapTuple enum_tuple;
|
|
|
|
ScanKeyData skey;
|
2007-11-15 22:14:46 +01:00
|
|
|
Datum *elems;
|
2010-10-25 05:04:37 +02:00
|
|
|
int max,
|
|
|
|
cnt;
|
2011-04-10 17:42:00 +02:00
|
|
|
bool left_found;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
/*
|
|
|
|
* Scan the enum members in order using pg_enum_typid_sortorder_index.
|
|
|
|
* Note we must not use the syscache, and must use an MVCC snapshot here.
|
|
|
|
* See comments for RenumberEnumType in catalog/pg_enum.c for more info.
|
|
|
|
*/
|
|
|
|
ScanKeyInit(&skey,
|
|
|
|
Anum_pg_enum_enumtypid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(enumtypoid));
|
|
|
|
|
|
|
|
enum_rel = heap_open(EnumRelationId, AccessShareLock);
|
|
|
|
enum_idx = index_open(EnumTypIdSortOrderIndexId, AccessShareLock);
|
|
|
|
enum_scan = systable_beginscan_ordered(enum_rel, enum_idx,
|
|
|
|
GetTransactionSnapshot(),
|
|
|
|
1, &skey);
|
|
|
|
|
|
|
|
max = 64;
|
|
|
|
elems = (Datum *) palloc(max * sizeof(Datum));
|
|
|
|
cnt = 0;
|
|
|
|
left_found = !OidIsValid(lower);
|
|
|
|
|
|
|
|
while (HeapTupleIsValid(enum_tuple = systable_getnext_ordered(enum_scan, ForwardScanDirection)))
|
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
Oid enum_oid = HeapTupleGetOid(enum_tuple);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
if (!left_found && lower == enum_oid)
|
|
|
|
left_found = true;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
if (left_found)
|
|
|
|
{
|
|
|
|
if (cnt >= max)
|
|
|
|
{
|
|
|
|
max *= 2;
|
|
|
|
elems = (Datum *) repalloc(elems, max * sizeof(Datum));
|
|
|
|
}
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
elems[cnt++] = ObjectIdGetDatum(enum_oid);
|
|
|
|
}
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
if (OidIsValid(upper) && upper == enum_oid)
|
|
|
|
break;
|
|
|
|
}
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
systable_endscan_ordered(enum_scan);
|
|
|
|
index_close(enum_idx, AccessShareLock);
|
|
|
|
heap_close(enum_rel, AccessShareLock);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
/* and build the result array */
|
2007-04-02 05:49:42 +02:00
|
|
|
/* note this hardwires some details about the representation of Oid */
|
2010-10-25 05:04:37 +02:00
|
|
|
result = construct_array(elems, cnt, enumtypoid, sizeof(Oid), true, 'i');
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
pfree(elems);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|