1 /*-------------------------------------------------------------------------
4 * I/O functions, operators, aggregates etc for enum types
6 * Copyright (c) 2006-2009, PostgreSQL Global Development Group
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
),
59 enumoid
= HeapTupleGetOid(tup
);
63 PG_RETURN_OID(enumoid
);
67 enum_out(PG_FUNCTION_ARGS
)
69 Oid enumval
= PG_GETARG_OID(0);
74 tup
= SearchSysCache(ENUMOID
,
75 ObjectIdGetDatum(enumval
),
77 if (!HeapTupleIsValid(tup
))
79 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION
),
80 errmsg("invalid internal value for enum: %u",
82 en
= (Form_pg_enum
) GETSTRUCT(tup
);
84 result
= pstrdup(NameStr(en
->enumlabel
));
88 PG_RETURN_CSTRING(result
);
91 /* Binary I/O support */
93 enum_recv(PG_FUNCTION_ARGS
)
95 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
96 Oid enumtypoid
= PG_GETARG_OID(1);
102 name
= pq_getmsgtext(buf
, buf
->len
- buf
->cursor
, &nbytes
);
104 /* must check length to prevent Assert failure within SearchSysCache */
105 if (strlen(name
) >= NAMEDATALEN
)
107 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
108 errmsg("invalid input value for enum %s: \"%s\"",
109 format_type_be(enumtypoid
),
112 tup
= SearchSysCache(ENUMTYPOIDNAME
,
113 ObjectIdGetDatum(enumtypoid
),
114 CStringGetDatum(name
),
116 if (!HeapTupleIsValid(tup
))
118 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
119 errmsg("invalid input value for enum %s: \"%s\"",
120 format_type_be(enumtypoid
),
123 enumoid
= HeapTupleGetOid(tup
);
125 ReleaseSysCache(tup
);
129 PG_RETURN_OID(enumoid
);
133 enum_send(PG_FUNCTION_ARGS
)
135 Oid enumval
= PG_GETARG_OID(0);
140 tup
= SearchSysCache(ENUMOID
,
141 ObjectIdGetDatum(enumval
),
143 if (!HeapTupleIsValid(tup
))
145 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION
),
146 errmsg("invalid internal value for enum: %u",
148 en
= (Form_pg_enum
) GETSTRUCT(tup
);
150 pq_begintypsend(&buf
);
151 pq_sendtext(&buf
, NameStr(en
->enumlabel
), strlen(NameStr(en
->enumlabel
)));
153 ReleaseSysCache(tup
);
155 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
158 /* Comparison functions and related */
161 enum_lt(PG_FUNCTION_ARGS
)
163 Oid a
= PG_GETARG_OID(0);
164 Oid b
= PG_GETARG_OID(1);
166 PG_RETURN_BOOL(a
< b
);
170 enum_le(PG_FUNCTION_ARGS
)
172 Oid a
= PG_GETARG_OID(0);
173 Oid b
= PG_GETARG_OID(1);
175 PG_RETURN_BOOL(a
<= b
);
179 enum_eq(PG_FUNCTION_ARGS
)
181 Oid a
= PG_GETARG_OID(0);
182 Oid b
= PG_GETARG_OID(1);
184 PG_RETURN_BOOL(a
== b
);
188 enum_ne(PG_FUNCTION_ARGS
)
190 Oid a
= PG_GETARG_OID(0);
191 Oid b
= PG_GETARG_OID(1);
193 PG_RETURN_BOOL(a
!= b
);
197 enum_ge(PG_FUNCTION_ARGS
)
199 Oid a
= PG_GETARG_OID(0);
200 Oid b
= PG_GETARG_OID(1);
202 PG_RETURN_BOOL(a
>= b
);
206 enum_gt(PG_FUNCTION_ARGS
)
208 Oid a
= PG_GETARG_OID(0);
209 Oid b
= PG_GETARG_OID(1);
211 PG_RETURN_BOOL(a
> b
);
215 enum_smaller(PG_FUNCTION_ARGS
)
217 Oid a
= PG_GETARG_OID(0);
218 Oid b
= PG_GETARG_OID(1);
220 PG_RETURN_OID(a
<= b
? a
: b
);
224 enum_larger(PG_FUNCTION_ARGS
)
226 Oid a
= PG_GETARG_OID(0);
227 Oid b
= PG_GETARG_OID(1);
229 PG_RETURN_OID(a
>= b
? a
: b
);
233 enum_cmp(PG_FUNCTION_ARGS
)
235 Oid a
= PG_GETARG_OID(0);
236 Oid b
= PG_GETARG_OID(1);
246 /* Enum programming support functions */
249 enum_first(PG_FUNCTION_ARGS
)
252 Oid min
= InvalidOid
;
258 * We rely on being able to get the specific enum type from the calling
259 * expression tree. Notice that the actual value of the argument isn't
260 * examined at all; in particular it might be NULL.
262 enumtypoid
= get_fn_expr_argtype(fcinfo
->flinfo
, 0);
263 if (enumtypoid
== InvalidOid
)
265 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
266 errmsg("could not determine actual enum type")));
268 list
= SearchSysCacheList(ENUMTYPOIDNAME
, 1,
269 ObjectIdGetDatum(enumtypoid
),
271 num
= list
->n_members
;
272 for (i
= 0; i
< num
; i
++)
274 Oid valoid
= HeapTupleHeaderGetOid(list
->members
[i
]->tuple
.t_data
);
276 if (!OidIsValid(min
) || valoid
< min
)
280 ReleaseCatCacheList(list
);
282 if (!OidIsValid(min
)) /* should not happen */
283 elog(ERROR
, "no values found for enum %s",
284 format_type_be(enumtypoid
));
290 enum_last(PG_FUNCTION_ARGS
)
293 Oid max
= InvalidOid
;
299 * We rely on being able to get the specific enum type from the calling
300 * expression tree. Notice that the actual value of the argument isn't
301 * examined at all; in particular it might be NULL.
303 enumtypoid
= get_fn_expr_argtype(fcinfo
->flinfo
, 0);
304 if (enumtypoid
== InvalidOid
)
306 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
307 errmsg("could not determine actual enum type")));
309 list
= SearchSysCacheList(ENUMTYPOIDNAME
, 1,
310 ObjectIdGetDatum(enumtypoid
),
312 num
= list
->n_members
;
313 for (i
= 0; i
< num
; i
++)
315 Oid valoid
= HeapTupleHeaderGetOid(list
->members
[i
]->tuple
.t_data
);
317 if (!OidIsValid(max
) || valoid
> max
)
321 ReleaseCatCacheList(list
);
323 if (!OidIsValid(max
)) /* should not happen */
324 elog(ERROR
, "no values found for enum %s",
325 format_type_be(enumtypoid
));
330 /* 2-argument variant of enum_range */
332 enum_range_bounds(PG_FUNCTION_ARGS
)
341 lower
= PG_GETARG_OID(0);
345 upper
= PG_GETARG_OID(1);
348 * We rely on being able to get the specific enum type from the calling
349 * expression tree. The generic type mechanism should have ensured that
350 * both are of the same type.
352 enumtypoid
= get_fn_expr_argtype(fcinfo
->flinfo
, 0);
353 if (enumtypoid
== InvalidOid
)
355 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
356 errmsg("could not determine actual enum type")));
358 PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid
, lower
, upper
));
361 /* 1-argument variant of enum_range */
363 enum_range_all(PG_FUNCTION_ARGS
)
368 * We rely on being able to get the specific enum type from the calling
369 * expression tree. Notice that the actual value of the argument isn't
370 * examined at all; in particular it might be NULL.
372 enumtypoid
= get_fn_expr_argtype(fcinfo
->flinfo
, 0);
373 if (enumtypoid
== InvalidOid
)
375 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
376 errmsg("could not determine actual enum type")));
378 PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid
,
379 InvalidOid
, InvalidOid
));
383 enum_range_internal(Oid enumtypoid
, Oid lower
, Oid upper
)
392 list
= SearchSysCacheList(ENUMTYPOIDNAME
, 1,
393 ObjectIdGetDatum(enumtypoid
),
395 total
= list
->n_members
;
397 elems
= (Datum
*) palloc(total
* sizeof(Datum
));
400 for (i
= 0; i
< total
; i
++)
402 Oid val
= HeapTupleGetOid(&(list
->members
[i
]->tuple
));
404 if ((!OidIsValid(lower
) || lower
<= val
) &&
405 (!OidIsValid(upper
) || val
<= upper
))
406 elems
[j
++] = ObjectIdGetDatum(val
);
409 /* shouldn't need the cache anymore */
410 ReleaseCatCacheList(list
);
412 /* sort results into OID order */
413 qsort(elems
, j
, sizeof(Datum
), enum_elem_cmp
);
415 /* note this hardwires some details about the representation of Oid */
416 result
= construct_array(elems
, j
, enumtypoid
, sizeof(Oid
), true, 'i');
423 /* qsort comparison function for Datums that are OIDs */
425 enum_elem_cmp(const void *left
, const void *right
)
427 Oid l
= DatumGetObjectId(*((const Datum
*) left
));
428 Oid r
= DatumGetObjectId(*((const Datum
*) right
));