1
/*-------------------------------------------------------------------------
4
* I/O functions, operators, aggregates etc for enum types
6
* Copyright (c) 2006-2011, PostgreSQL Global Development Group
10
* src/backend/utils/adt/enum.c
12
*-------------------------------------------------------------------------
16
#include "access/genam.h"
17
#include "access/heapam.h"
18
#include "catalog/indexing.h"
19
#include "catalog/pg_enum.h"
21
#include "libpq/pqformat.h"
22
#include "utils/array.h"
23
#include "utils/builtins.h"
24
#include "utils/fmgroids.h"
25
#include "utils/snapmgr.h"
26
#include "utils/syscache.h"
27
#include "utils/typcache.h"
30
static Oid enum_endpoint(Oid enumtypoid, ScanDirection direction);
31
static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper);
34
/* Basic I/O support */
37
enum_in(PG_FUNCTION_ARGS)
39
char *name = PG_GETARG_CSTRING(0);
40
Oid enumtypoid = PG_GETARG_OID(1);
44
/* must check length to prevent Assert failure within SearchSysCache */
45
if (strlen(name) >= NAMEDATALEN)
47
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
48
errmsg("invalid input value for enum %s: \"%s\"",
49
format_type_be(enumtypoid),
52
tup = SearchSysCache2(ENUMTYPOIDNAME,
53
ObjectIdGetDatum(enumtypoid),
54
CStringGetDatum(name));
55
if (!HeapTupleIsValid(tup))
57
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
58
errmsg("invalid input value for enum %s: \"%s\"",
59
format_type_be(enumtypoid),
63
* This comes from pg_enum.oid and stores system oids in user tables. This
64
* oid must be preserved by binary upgrades.
66
enumoid = HeapTupleGetOid(tup);
70
PG_RETURN_OID(enumoid);
74
enum_out(PG_FUNCTION_ARGS)
76
Oid enumval = PG_GETARG_OID(0);
81
tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enumval));
82
if (!HeapTupleIsValid(tup))
84
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
85
errmsg("invalid internal value for enum: %u",
87
en = (Form_pg_enum) GETSTRUCT(tup);
89
result = pstrdup(NameStr(en->enumlabel));
93
PG_RETURN_CSTRING(result);
96
/* Binary I/O support */
98
enum_recv(PG_FUNCTION_ARGS)
100
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
101
Oid enumtypoid = PG_GETARG_OID(1);
107
name = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
109
/* must check length to prevent Assert failure within SearchSysCache */
110
if (strlen(name) >= NAMEDATALEN)
112
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
113
errmsg("invalid input value for enum %s: \"%s\"",
114
format_type_be(enumtypoid),
117
tup = SearchSysCache2(ENUMTYPOIDNAME,
118
ObjectIdGetDatum(enumtypoid),
119
CStringGetDatum(name));
120
if (!HeapTupleIsValid(tup))
122
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
123
errmsg("invalid input value for enum %s: \"%s\"",
124
format_type_be(enumtypoid),
127
enumoid = HeapTupleGetOid(tup);
129
ReleaseSysCache(tup);
133
PG_RETURN_OID(enumoid);
137
enum_send(PG_FUNCTION_ARGS)
139
Oid enumval = PG_GETARG_OID(0);
144
tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enumval));
145
if (!HeapTupleIsValid(tup))
147
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
148
errmsg("invalid internal value for enum: %u",
150
en = (Form_pg_enum) GETSTRUCT(tup);
152
pq_begintypsend(&buf);
153
pq_sendtext(&buf, NameStr(en->enumlabel), strlen(NameStr(en->enumlabel)));
155
ReleaseSysCache(tup);
157
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
160
/* Comparison functions and related */
163
* enum_cmp_internal is the common engine for all the visible comparison
164
* functions, except for enum_eq and enum_ne which can just check for OID
168
enum_cmp_internal(Oid arg1, Oid arg2, FunctionCallInfo fcinfo)
170
TypeCacheEntry *tcache;
172
/* Equal OIDs are equal no matter what */
176
/* Fast path: even-numbered Oids are known to compare correctly */
177
if ((arg1 & 1) == 0 && (arg2 & 1) == 0)
185
/* Locate the typcache entry for the enum type */
186
tcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
193
/* Get the OID of the enum type containing arg1 */
194
enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(arg1));
195
if (!HeapTupleIsValid(enum_tup))
197
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
198
errmsg("invalid internal value for enum: %u",
200
en = (Form_pg_enum) GETSTRUCT(enum_tup);
201
typeoid = en->enumtypid;
202
ReleaseSysCache(enum_tup);
203
/* Now locate and remember the typcache entry */
204
tcache = lookup_type_cache(typeoid, 0);
205
fcinfo->flinfo->fn_extra = (void *) tcache;
208
/* The remaining comparison logic is in typcache.c */
209
return compare_values_of_enum(tcache, arg1, arg2);
213
enum_lt(PG_FUNCTION_ARGS)
215
Oid a = PG_GETARG_OID(0);
216
Oid b = PG_GETARG_OID(1);
218
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) < 0);
222
enum_le(PG_FUNCTION_ARGS)
224
Oid a = PG_GETARG_OID(0);
225
Oid b = PG_GETARG_OID(1);
227
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) <= 0);
231
enum_eq(PG_FUNCTION_ARGS)
233
Oid a = PG_GETARG_OID(0);
234
Oid b = PG_GETARG_OID(1);
236
PG_RETURN_BOOL(a == b);
240
enum_ne(PG_FUNCTION_ARGS)
242
Oid a = PG_GETARG_OID(0);
243
Oid b = PG_GETARG_OID(1);
245
PG_RETURN_BOOL(a != b);
249
enum_ge(PG_FUNCTION_ARGS)
251
Oid a = PG_GETARG_OID(0);
252
Oid b = PG_GETARG_OID(1);
254
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) >= 0);
258
enum_gt(PG_FUNCTION_ARGS)
260
Oid a = PG_GETARG_OID(0);
261
Oid b = PG_GETARG_OID(1);
263
PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) > 0);
267
enum_smaller(PG_FUNCTION_ARGS)
269
Oid a = PG_GETARG_OID(0);
270
Oid b = PG_GETARG_OID(1);
272
PG_RETURN_OID(enum_cmp_internal(a, b, fcinfo) < 0 ? a : b);
276
enum_larger(PG_FUNCTION_ARGS)
278
Oid a = PG_GETARG_OID(0);
279
Oid b = PG_GETARG_OID(1);
281
PG_RETURN_OID(enum_cmp_internal(a, b, fcinfo) > 0 ? a : b);
285
enum_cmp(PG_FUNCTION_ARGS)
287
Oid a = PG_GETARG_OID(0);
288
Oid b = PG_GETARG_OID(1);
292
else if (enum_cmp_internal(a, b, fcinfo) > 0)
298
/* Enum programming support functions */
301
* enum_endpoint: common code for enum_first/enum_last
304
enum_endpoint(Oid enumtypoid, ScanDirection direction)
308
SysScanDesc enum_scan;
309
HeapTuple enum_tuple;
314
* Find the first/last enum member using pg_enum_typid_sortorder_index.
315
* Note we must not use the syscache, and must use an MVCC snapshot here.
316
* See comments for RenumberEnumType in catalog/pg_enum.c for more info.
319
Anum_pg_enum_enumtypid,
320
BTEqualStrategyNumber, F_OIDEQ,
321
ObjectIdGetDatum(enumtypoid));
323
enum_rel = heap_open(EnumRelationId, AccessShareLock);
324
enum_idx = index_open(EnumTypIdSortOrderIndexId, AccessShareLock);
325
enum_scan = systable_beginscan_ordered(enum_rel, enum_idx,
326
GetTransactionSnapshot(),
329
enum_tuple = systable_getnext_ordered(enum_scan, direction);
330
if (HeapTupleIsValid(enum_tuple))
331
minmax = HeapTupleGetOid(enum_tuple);
335
systable_endscan_ordered(enum_scan);
336
index_close(enum_idx, AccessShareLock);
337
heap_close(enum_rel, AccessShareLock);
343
enum_first(PG_FUNCTION_ARGS)
349
* We rely on being able to get the specific enum type from the calling
350
* expression tree. Notice that the actual value of the argument isn't
351
* examined at all; in particular it might be NULL.
353
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
354
if (enumtypoid == InvalidOid)
356
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
357
errmsg("could not determine actual enum type")));
359
/* Get the OID using the index */
360
min = enum_endpoint(enumtypoid, ForwardScanDirection);
362
if (!OidIsValid(min))
364
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
365
errmsg("enum %s contains no values",
366
format_type_be(enumtypoid))));
372
enum_last(PG_FUNCTION_ARGS)
378
* We rely on being able to get the specific enum type from the calling
379
* expression tree. Notice that the actual value of the argument isn't
380
* examined at all; in particular it might be NULL.
382
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
383
if (enumtypoid == InvalidOid)
385
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
386
errmsg("could not determine actual enum type")));
388
/* Get the OID using the index */
389
max = enum_endpoint(enumtypoid, BackwardScanDirection);
391
if (!OidIsValid(max))
393
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
394
errmsg("enum %s contains no values",
395
format_type_be(enumtypoid))));
400
/* 2-argument variant of enum_range */
402
enum_range_bounds(PG_FUNCTION_ARGS)
411
lower = PG_GETARG_OID(0);
415
upper = PG_GETARG_OID(1);
418
* We rely on being able to get the specific enum type from the calling
419
* expression tree. The generic type mechanism should have ensured that
420
* both are of the same type.
422
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
423
if (enumtypoid == InvalidOid)
425
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
426
errmsg("could not determine actual enum type")));
428
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
431
/* 1-argument variant of enum_range */
433
enum_range_all(PG_FUNCTION_ARGS)
438
* We rely on being able to get the specific enum type from the calling
439
* expression tree. Notice that the actual value of the argument isn't
440
* examined at all; in particular it might be NULL.
442
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
443
if (enumtypoid == InvalidOid)
445
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
446
errmsg("could not determine actual enum type")));
448
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid,
449
InvalidOid, InvalidOid));
453
enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
458
SysScanDesc enum_scan;
459
HeapTuple enum_tuple;
467
* Scan the enum members in order using pg_enum_typid_sortorder_index.
468
* Note we must not use the syscache, and must use an MVCC snapshot here.
469
* See comments for RenumberEnumType in catalog/pg_enum.c for more info.
472
Anum_pg_enum_enumtypid,
473
BTEqualStrategyNumber, F_OIDEQ,
474
ObjectIdGetDatum(enumtypoid));
476
enum_rel = heap_open(EnumRelationId, AccessShareLock);
477
enum_idx = index_open(EnumTypIdSortOrderIndexId, AccessShareLock);
478
enum_scan = systable_beginscan_ordered(enum_rel, enum_idx,
479
GetTransactionSnapshot(),
483
elems = (Datum *) palloc(max * sizeof(Datum));
485
left_found = !OidIsValid(lower);
487
while (HeapTupleIsValid(enum_tuple = systable_getnext_ordered(enum_scan, ForwardScanDirection)))
489
Oid enum_oid = HeapTupleGetOid(enum_tuple);
491
if (!left_found && lower == enum_oid)
499
elems = (Datum *) repalloc(elems, max * sizeof(Datum));
502
elems[cnt++] = ObjectIdGetDatum(enum_oid);
505
if (OidIsValid(upper) && upper == enum_oid)
509
systable_endscan_ordered(enum_scan);
510
index_close(enum_idx, AccessShareLock);
511
heap_close(enum_rel, AccessShareLock);
513
/* and build the result array */
514
/* note this hardwires some details about the representation of Oid */
515
result = construct_array(elems, cnt, enumtypoid, sizeof(Oid), true, 'i');