Don't use 'return' where you should use 'PG_RETURN_xxx'.
[PostgreSQL.git] / src / backend / utils / adt / enum.c
blob00569cb1cbdfa7fb160ea520a5a7387737dfa875
1 /*-------------------------------------------------------------------------
3 * enum.c
4 * I/O functions, operators, aggregates etc for enum types
6 * Copyright (c) 2006-2009, PostgreSQL Global Development Group
9 * IDENTIFICATION
10 * $PostgreSQL$
12 *-------------------------------------------------------------------------
14 #include "postgres.h"
16 #include "catalog/pg_enum.h"
17 #include "fmgr.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 */
32 Datum
33 enum_in(PG_FUNCTION_ARGS)
35 char *name = PG_GETARG_CSTRING(0);
36 Oid enumtypoid = PG_GETARG_OID(1);
37 Oid enumoid;
38 HeapTuple tup;
40 /* must check length to prevent Assert failure within SearchSysCache */
41 if (strlen(name) >= NAMEDATALEN)
42 ereport(ERROR,
43 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
44 errmsg("invalid input value for enum %s: \"%s\"",
45 format_type_be(enumtypoid),
46 name)));
48 tup = SearchSysCache(ENUMTYPOIDNAME,
49 ObjectIdGetDatum(enumtypoid),
50 CStringGetDatum(name),
51 0, 0);
52 if (!HeapTupleIsValid(tup))
53 ereport(ERROR,
54 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
55 errmsg("invalid input value for enum %s: \"%s\"",
56 format_type_be(enumtypoid),
57 name)));
59 enumoid = HeapTupleGetOid(tup);
61 ReleaseSysCache(tup);
63 PG_RETURN_OID(enumoid);
66 Datum
67 enum_out(PG_FUNCTION_ARGS)
69 Oid enumval = PG_GETARG_OID(0);
70 char *result;
71 HeapTuple tup;
72 Form_pg_enum en;
74 tup = SearchSysCache(ENUMOID,
75 ObjectIdGetDatum(enumval),
76 0, 0, 0);
77 if (!HeapTupleIsValid(tup))
78 ereport(ERROR,
79 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
80 errmsg("invalid internal value for enum: %u",
81 enumval)));
82 en = (Form_pg_enum) GETSTRUCT(tup);
84 result = pstrdup(NameStr(en->enumlabel));
86 ReleaseSysCache(tup);
88 PG_RETURN_CSTRING(result);
91 /* Binary I/O support */
92 Datum
93 enum_recv(PG_FUNCTION_ARGS)
95 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
96 Oid enumtypoid = PG_GETARG_OID(1);
97 Oid enumoid;
98 HeapTuple tup;
99 char *name;
100 int nbytes;
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)
106 ereport(ERROR,
107 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
108 errmsg("invalid input value for enum %s: \"%s\"",
109 format_type_be(enumtypoid),
110 name)));
112 tup = SearchSysCache(ENUMTYPOIDNAME,
113 ObjectIdGetDatum(enumtypoid),
114 CStringGetDatum(name),
115 0, 0);
116 if (!HeapTupleIsValid(tup))
117 ereport(ERROR,
118 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
119 errmsg("invalid input value for enum %s: \"%s\"",
120 format_type_be(enumtypoid),
121 name)));
123 enumoid = HeapTupleGetOid(tup);
125 ReleaseSysCache(tup);
127 pfree(name);
129 PG_RETURN_OID(enumoid);
132 Datum
133 enum_send(PG_FUNCTION_ARGS)
135 Oid enumval = PG_GETARG_OID(0);
136 StringInfoData buf;
137 HeapTuple tup;
138 Form_pg_enum en;
140 tup = SearchSysCache(ENUMOID,
141 ObjectIdGetDatum(enumval),
142 0, 0, 0);
143 if (!HeapTupleIsValid(tup))
144 ereport(ERROR,
145 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
146 errmsg("invalid internal value for enum: %u",
147 enumval)));
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 */
160 Datum
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);
169 Datum
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);
178 Datum
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);
187 Datum
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);
196 Datum
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);
205 Datum
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);
214 Datum
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);
223 Datum
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);
232 Datum
233 enum_cmp(PG_FUNCTION_ARGS)
235 Oid a = PG_GETARG_OID(0);
236 Oid b = PG_GETARG_OID(1);
238 if (a > b)
239 PG_RETURN_INT32(1);
240 else if (a == b)
241 PG_RETURN_INT32(0);
242 else
243 PG_RETURN_INT32(-1);
246 /* Enum programming support functions */
248 Datum
249 enum_first(PG_FUNCTION_ARGS)
251 Oid enumtypoid;
252 Oid min = InvalidOid;
253 CatCList *list;
254 int num,
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)
264 ereport(ERROR,
265 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
266 errmsg("could not determine actual enum type")));
268 list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
269 ObjectIdGetDatum(enumtypoid),
270 0, 0, 0);
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)
277 min = valoid;
280 ReleaseCatCacheList(list);
282 if (!OidIsValid(min)) /* should not happen */
283 elog(ERROR, "no values found for enum %s",
284 format_type_be(enumtypoid));
286 PG_RETURN_OID(min);
289 Datum
290 enum_last(PG_FUNCTION_ARGS)
292 Oid enumtypoid;
293 Oid max = InvalidOid;
294 CatCList *list;
295 int num,
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)
305 ereport(ERROR,
306 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
307 errmsg("could not determine actual enum type")));
309 list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
310 ObjectIdGetDatum(enumtypoid),
311 0, 0, 0);
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)
318 max = valoid;
321 ReleaseCatCacheList(list);
323 if (!OidIsValid(max)) /* should not happen */
324 elog(ERROR, "no values found for enum %s",
325 format_type_be(enumtypoid));
327 PG_RETURN_OID(max);
330 /* 2-argument variant of enum_range */
331 Datum
332 enum_range_bounds(PG_FUNCTION_ARGS)
334 Oid lower;
335 Oid upper;
336 Oid enumtypoid;
338 if (PG_ARGISNULL(0))
339 lower = InvalidOid;
340 else
341 lower = PG_GETARG_OID(0);
342 if (PG_ARGISNULL(1))
343 upper = InvalidOid;
344 else
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)
354 ereport(ERROR,
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 */
362 Datum
363 enum_range_all(PG_FUNCTION_ARGS)
365 Oid enumtypoid;
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)
374 ereport(ERROR,
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));
382 static ArrayType *
383 enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
385 ArrayType *result;
386 CatCList *list;
387 int total,
390 Datum *elems;
392 list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
393 ObjectIdGetDatum(enumtypoid),
394 0, 0, 0);
395 total = list->n_members;
397 elems = (Datum *) palloc(total * sizeof(Datum));
399 j = 0;
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');
418 pfree(elems);
420 return result;
423 /* qsort comparison function for Datums that are OIDs */
424 static int
425 enum_elem_cmp(const void *left, const void *right)
427 Oid l = DatumGetObjectId(*((const Datum *) left));
428 Oid r = DatumGetObjectId(*((const Datum *) right));
430 if (l < r)
431 return -1;
432 if (l > r)
433 return 1;
434 return 0;