1 /*-------------------------------------------------------------------------
4 * I/O functions, operators, aggregates etc for enum types
6 * Copyright (c) 2006-2009, PostgreSQL Global Development Group
10 * $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.8 2009/12/19 00:47:57 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include "catalog/pg_enum.h"
18 #include "utils/array.h"
19 #include "utils/builtins.h"
20 #include "utils/lsyscache.h"
21 #include "utils/syscache.h"
22 #include "libpq/pqformat.h"
23 #include "miscadmin.h"
26 static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper);
27 static int enum_elem_cmp(const void *left, const void *right);
30 /* Basic I/O support */
33 enum_in(PG_FUNCTION_ARGS)
35 char *name = PG_GETARG_CSTRING(0);
36 Oid enumtypoid = PG_GETARG_OID(1);
40 /* must check length to prevent Assert failure within SearchSysCache */
41 if (strlen(name) >= NAMEDATALEN)
43 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
44 errmsg("invalid input value for enum %s: \"%s\"",
45 format_type_be(enumtypoid),
48 tup = SearchSysCache(ENUMTYPOIDNAME,
49 ObjectIdGetDatum(enumtypoid),
50 CStringGetDatum(name),
52 if (!HeapTupleIsValid(tup))
54 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
55 errmsg("invalid input value for enum %s: \"%s\"",
56 format_type_be(enumtypoid),
60 * This comes from pg_enum.oid and stores system oids in user tables.
61 * This oid must be preserved by binary upgrades.
63 enumoid = HeapTupleGetOid(tup);
67 PG_RETURN_OID(enumoid);
71 enum_out(PG_FUNCTION_ARGS)
73 Oid enumval = PG_GETARG_OID(0);
78 tup = SearchSysCache(ENUMOID,
79 ObjectIdGetDatum(enumval),
81 if (!HeapTupleIsValid(tup))
83 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
84 errmsg("invalid internal value for enum: %u",
86 en = (Form_pg_enum) GETSTRUCT(tup);
88 result = pstrdup(NameStr(en->enumlabel));
92 PG_RETURN_CSTRING(result);
95 /* Binary I/O support */
97 enum_recv(PG_FUNCTION_ARGS)
99 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
100 Oid enumtypoid = PG_GETARG_OID(1);
106 name = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
108 /* must check length to prevent Assert failure within SearchSysCache */
109 if (strlen(name) >= NAMEDATALEN)
111 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
112 errmsg("invalid input value for enum %s: \"%s\"",
113 format_type_be(enumtypoid),
116 tup = SearchSysCache(ENUMTYPOIDNAME,
117 ObjectIdGetDatum(enumtypoid),
118 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 = SearchSysCache(ENUMOID,
145 ObjectIdGetDatum(enumval),
147 if (!HeapTupleIsValid(tup))
149 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
150 errmsg("invalid internal value for enum: %u",
152 en = (Form_pg_enum) GETSTRUCT(tup);
154 pq_begintypsend(&buf);
155 pq_sendtext(&buf, NameStr(en->enumlabel), strlen(NameStr(en->enumlabel)));
157 ReleaseSysCache(tup);
159 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
162 /* Comparison functions and related */
165 enum_lt(PG_FUNCTION_ARGS)
167 Oid a = PG_GETARG_OID(0);
168 Oid b = PG_GETARG_OID(1);
170 PG_RETURN_BOOL(a < b);
174 enum_le(PG_FUNCTION_ARGS)
176 Oid a = PG_GETARG_OID(0);
177 Oid b = PG_GETARG_OID(1);
179 PG_RETURN_BOOL(a <= b);
183 enum_eq(PG_FUNCTION_ARGS)
185 Oid a = PG_GETARG_OID(0);
186 Oid b = PG_GETARG_OID(1);
188 PG_RETURN_BOOL(a == b);
192 enum_ne(PG_FUNCTION_ARGS)
194 Oid a = PG_GETARG_OID(0);
195 Oid b = PG_GETARG_OID(1);
197 PG_RETURN_BOOL(a != b);
201 enum_ge(PG_FUNCTION_ARGS)
203 Oid a = PG_GETARG_OID(0);
204 Oid b = PG_GETARG_OID(1);
206 PG_RETURN_BOOL(a >= b);
210 enum_gt(PG_FUNCTION_ARGS)
212 Oid a = PG_GETARG_OID(0);
213 Oid b = PG_GETARG_OID(1);
215 PG_RETURN_BOOL(a > b);
219 enum_smaller(PG_FUNCTION_ARGS)
221 Oid a = PG_GETARG_OID(0);
222 Oid b = PG_GETARG_OID(1);
224 PG_RETURN_OID(a <= b ? a : b);
228 enum_larger(PG_FUNCTION_ARGS)
230 Oid a = PG_GETARG_OID(0);
231 Oid b = PG_GETARG_OID(1);
233 PG_RETURN_OID(a >= b ? a : b);
237 enum_cmp(PG_FUNCTION_ARGS)
239 Oid a = PG_GETARG_OID(0);
240 Oid b = PG_GETARG_OID(1);
250 /* Enum programming support functions */
253 enum_first(PG_FUNCTION_ARGS)
256 Oid min = InvalidOid;
262 * We rely on being able to get the specific enum type from the calling
263 * expression tree. Notice that the actual value of the argument isn't
264 * examined at all; in particular it might be NULL.
266 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
267 if (enumtypoid == InvalidOid)
269 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
270 errmsg("could not determine actual enum type")));
272 list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
273 ObjectIdGetDatum(enumtypoid),
275 num = list->n_members;
276 for (i = 0; i < num; i++)
278 Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data);
280 if (!OidIsValid(min) || valoid < min)
284 ReleaseCatCacheList(list);
286 if (!OidIsValid(min)) /* should not happen */
287 elog(ERROR, "no values found for enum %s",
288 format_type_be(enumtypoid));
294 enum_last(PG_FUNCTION_ARGS)
297 Oid max = InvalidOid;
303 * We rely on being able to get the specific enum type from the calling
304 * expression tree. Notice that the actual value of the argument isn't
305 * examined at all; in particular it might be NULL.
307 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
308 if (enumtypoid == InvalidOid)
310 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
311 errmsg("could not determine actual enum type")));
313 list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
314 ObjectIdGetDatum(enumtypoid),
316 num = list->n_members;
317 for (i = 0; i < num; i++)
319 Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data);
321 if (!OidIsValid(max) || valoid > max)
325 ReleaseCatCacheList(list);
327 if (!OidIsValid(max)) /* should not happen */
328 elog(ERROR, "no values found for enum %s",
329 format_type_be(enumtypoid));
334 /* 2-argument variant of enum_range */
336 enum_range_bounds(PG_FUNCTION_ARGS)
345 lower = PG_GETARG_OID(0);
349 upper = PG_GETARG_OID(1);
352 * We rely on being able to get the specific enum type from the calling
353 * expression tree. The generic type mechanism should have ensured that
354 * both are of the same type.
356 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
357 if (enumtypoid == InvalidOid)
359 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
360 errmsg("could not determine actual enum type")));
362 PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
365 /* 1-argument variant of enum_range */
367 enum_range_all(PG_FUNCTION_ARGS)
372 * We rely on being able to get the specific enum type from the calling
373 * expression tree. Notice that the actual value of the argument isn't
374 * examined at all; in particular it might be NULL.
376 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
377 if (enumtypoid == InvalidOid)
379 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
380 errmsg("could not determine actual enum type")));
382 PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid,
383 InvalidOid, InvalidOid));
387 enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
396 list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
397 ObjectIdGetDatum(enumtypoid),
399 total = list->n_members;
401 elems = (Datum *) palloc(total * sizeof(Datum));
404 for (i = 0; i < total; i++)
406 Oid val = HeapTupleGetOid(&(list->members[i]->tuple));
408 if ((!OidIsValid(lower) || lower <= val) &&
409 (!OidIsValid(upper) || val <= upper))
410 elems[j++] = ObjectIdGetDatum(val);
413 /* shouldn't need the cache anymore */
414 ReleaseCatCacheList(list);
416 /* sort results into OID order */
417 qsort(elems, j, sizeof(Datum), enum_elem_cmp);
419 /* note this hardwires some details about the representation of Oid */
420 result = construct_array(elems, j, enumtypoid, sizeof(Oid), true, 'i');
427 /* qsort comparison function for Datums that are OIDs */
429 enum_elem_cmp(const void *left, const void *right)
431 Oid l = DatumGetObjectId(*((const Datum *) left));
432 Oid r = DatumGetObjectId(*((const Datum *) right));