00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "access/genam.h"
00017 #include "access/heapam.h"
00018 #include "access/htup_details.h"
00019 #include "catalog/indexing.h"
00020 #include "catalog/pg_enum.h"
00021 #include "libpq/pqformat.h"
00022 #include "utils/array.h"
00023 #include "utils/builtins.h"
00024 #include "utils/fmgroids.h"
00025 #include "utils/snapmgr.h"
00026 #include "utils/syscache.h"
00027 #include "utils/typcache.h"
00028
00029
00030 static Oid enum_endpoint(Oid enumtypoid, ScanDirection direction);
00031 static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper);
00032
00033
00034
00035
00036 Datum
00037 enum_in(PG_FUNCTION_ARGS)
00038 {
00039 char *name = PG_GETARG_CSTRING(0);
00040 Oid enumtypoid = PG_GETARG_OID(1);
00041 Oid enumoid;
00042 HeapTuple tup;
00043
00044
00045 if (strlen(name) >= NAMEDATALEN)
00046 ereport(ERROR,
00047 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00048 errmsg("invalid input value for enum %s: \"%s\"",
00049 format_type_be(enumtypoid),
00050 name)));
00051
00052 tup = SearchSysCache2(ENUMTYPOIDNAME,
00053 ObjectIdGetDatum(enumtypoid),
00054 CStringGetDatum(name));
00055 if (!HeapTupleIsValid(tup))
00056 ereport(ERROR,
00057 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00058 errmsg("invalid input value for enum %s: \"%s\"",
00059 format_type_be(enumtypoid),
00060 name)));
00061
00062
00063
00064
00065
00066 enumoid = HeapTupleGetOid(tup);
00067
00068 ReleaseSysCache(tup);
00069
00070 PG_RETURN_OID(enumoid);
00071 }
00072
00073 Datum
00074 enum_out(PG_FUNCTION_ARGS)
00075 {
00076 Oid enumval = PG_GETARG_OID(0);
00077 char *result;
00078 HeapTuple tup;
00079 Form_pg_enum en;
00080
00081 tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enumval));
00082 if (!HeapTupleIsValid(tup))
00083 ereport(ERROR,
00084 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00085 errmsg("invalid internal value for enum: %u",
00086 enumval)));
00087 en = (Form_pg_enum) GETSTRUCT(tup);
00088
00089 result = pstrdup(NameStr(en->enumlabel));
00090
00091 ReleaseSysCache(tup);
00092
00093 PG_RETURN_CSTRING(result);
00094 }
00095
00096
00097 Datum
00098 enum_recv(PG_FUNCTION_ARGS)
00099 {
00100 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
00101 Oid enumtypoid = PG_GETARG_OID(1);
00102 Oid enumoid;
00103 HeapTuple tup;
00104 char *name;
00105 int nbytes;
00106
00107 name = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
00108
00109
00110 if (strlen(name) >= NAMEDATALEN)
00111 ereport(ERROR,
00112 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00113 errmsg("invalid input value for enum %s: \"%s\"",
00114 format_type_be(enumtypoid),
00115 name)));
00116
00117 tup = SearchSysCache2(ENUMTYPOIDNAME,
00118 ObjectIdGetDatum(enumtypoid),
00119 CStringGetDatum(name));
00120 if (!HeapTupleIsValid(tup))
00121 ereport(ERROR,
00122 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00123 errmsg("invalid input value for enum %s: \"%s\"",
00124 format_type_be(enumtypoid),
00125 name)));
00126
00127 enumoid = HeapTupleGetOid(tup);
00128
00129 ReleaseSysCache(tup);
00130
00131 pfree(name);
00132
00133 PG_RETURN_OID(enumoid);
00134 }
00135
00136 Datum
00137 enum_send(PG_FUNCTION_ARGS)
00138 {
00139 Oid enumval = PG_GETARG_OID(0);
00140 StringInfoData buf;
00141 HeapTuple tup;
00142 Form_pg_enum en;
00143
00144 tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(enumval));
00145 if (!HeapTupleIsValid(tup))
00146 ereport(ERROR,
00147 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00148 errmsg("invalid internal value for enum: %u",
00149 enumval)));
00150 en = (Form_pg_enum) GETSTRUCT(tup);
00151
00152 pq_begintypsend(&buf);
00153 pq_sendtext(&buf, NameStr(en->enumlabel), strlen(NameStr(en->enumlabel)));
00154
00155 ReleaseSysCache(tup);
00156
00157 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167 static int
00168 enum_cmp_internal(Oid arg1, Oid arg2, FunctionCallInfo fcinfo)
00169 {
00170 TypeCacheEntry *tcache;
00171
00172
00173 if (arg1 == arg2)
00174 return 0;
00175
00176
00177 if ((arg1 & 1) == 0 && (arg2 & 1) == 0)
00178 {
00179 if (arg1 < arg2)
00180 return -1;
00181 else
00182 return 1;
00183 }
00184
00185
00186 tcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
00187 if (tcache == NULL)
00188 {
00189 HeapTuple enum_tup;
00190 Form_pg_enum en;
00191 Oid typeoid;
00192
00193
00194 enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(arg1));
00195 if (!HeapTupleIsValid(enum_tup))
00196 ereport(ERROR,
00197 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00198 errmsg("invalid internal value for enum: %u",
00199 arg1)));
00200 en = (Form_pg_enum) GETSTRUCT(enum_tup);
00201 typeoid = en->enumtypid;
00202 ReleaseSysCache(enum_tup);
00203
00204 tcache = lookup_type_cache(typeoid, 0);
00205 fcinfo->flinfo->fn_extra = (void *) tcache;
00206 }
00207
00208
00209 return compare_values_of_enum(tcache, arg1, arg2);
00210 }
00211
00212 Datum
00213 enum_lt(PG_FUNCTION_ARGS)
00214 {
00215 Oid a = PG_GETARG_OID(0);
00216 Oid b = PG_GETARG_OID(1);
00217
00218 PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) < 0);
00219 }
00220
00221 Datum
00222 enum_le(PG_FUNCTION_ARGS)
00223 {
00224 Oid a = PG_GETARG_OID(0);
00225 Oid b = PG_GETARG_OID(1);
00226
00227 PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) <= 0);
00228 }
00229
00230 Datum
00231 enum_eq(PG_FUNCTION_ARGS)
00232 {
00233 Oid a = PG_GETARG_OID(0);
00234 Oid b = PG_GETARG_OID(1);
00235
00236 PG_RETURN_BOOL(a == b);
00237 }
00238
00239 Datum
00240 enum_ne(PG_FUNCTION_ARGS)
00241 {
00242 Oid a = PG_GETARG_OID(0);
00243 Oid b = PG_GETARG_OID(1);
00244
00245 PG_RETURN_BOOL(a != b);
00246 }
00247
00248 Datum
00249 enum_ge(PG_FUNCTION_ARGS)
00250 {
00251 Oid a = PG_GETARG_OID(0);
00252 Oid b = PG_GETARG_OID(1);
00253
00254 PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) >= 0);
00255 }
00256
00257 Datum
00258 enum_gt(PG_FUNCTION_ARGS)
00259 {
00260 Oid a = PG_GETARG_OID(0);
00261 Oid b = PG_GETARG_OID(1);
00262
00263 PG_RETURN_BOOL(enum_cmp_internal(a, b, fcinfo) > 0);
00264 }
00265
00266 Datum
00267 enum_smaller(PG_FUNCTION_ARGS)
00268 {
00269 Oid a = PG_GETARG_OID(0);
00270 Oid b = PG_GETARG_OID(1);
00271
00272 PG_RETURN_OID(enum_cmp_internal(a, b, fcinfo) < 0 ? a : b);
00273 }
00274
00275 Datum
00276 enum_larger(PG_FUNCTION_ARGS)
00277 {
00278 Oid a = PG_GETARG_OID(0);
00279 Oid b = PG_GETARG_OID(1);
00280
00281 PG_RETURN_OID(enum_cmp_internal(a, b, fcinfo) > 0 ? a : b);
00282 }
00283
00284 Datum
00285 enum_cmp(PG_FUNCTION_ARGS)
00286 {
00287 Oid a = PG_GETARG_OID(0);
00288 Oid b = PG_GETARG_OID(1);
00289
00290 if (a == b)
00291 PG_RETURN_INT32(0);
00292 else if (enum_cmp_internal(a, b, fcinfo) > 0)
00293 PG_RETURN_INT32(1);
00294 else
00295 PG_RETURN_INT32(-1);
00296 }
00297
00298
00299
00300
00301
00302
00303 static Oid
00304 enum_endpoint(Oid enumtypoid, ScanDirection direction)
00305 {
00306 Relation enum_rel;
00307 Relation enum_idx;
00308 SysScanDesc enum_scan;
00309 HeapTuple enum_tuple;
00310 ScanKeyData skey;
00311 Oid minmax;
00312
00313
00314
00315
00316
00317
00318 ScanKeyInit(&skey,
00319 Anum_pg_enum_enumtypid,
00320 BTEqualStrategyNumber, F_OIDEQ,
00321 ObjectIdGetDatum(enumtypoid));
00322
00323 enum_rel = heap_open(EnumRelationId, AccessShareLock);
00324 enum_idx = index_open(EnumTypIdSortOrderIndexId, AccessShareLock);
00325 enum_scan = systable_beginscan_ordered(enum_rel, enum_idx,
00326 GetTransactionSnapshot(),
00327 1, &skey);
00328
00329 enum_tuple = systable_getnext_ordered(enum_scan, direction);
00330 if (HeapTupleIsValid(enum_tuple))
00331 minmax = HeapTupleGetOid(enum_tuple);
00332 else
00333 minmax = InvalidOid;
00334
00335 systable_endscan_ordered(enum_scan);
00336 index_close(enum_idx, AccessShareLock);
00337 heap_close(enum_rel, AccessShareLock);
00338
00339 return minmax;
00340 }
00341
00342 Datum
00343 enum_first(PG_FUNCTION_ARGS)
00344 {
00345 Oid enumtypoid;
00346 Oid min;
00347
00348
00349
00350
00351
00352
00353 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
00354 if (enumtypoid == InvalidOid)
00355 ereport(ERROR,
00356 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00357 errmsg("could not determine actual enum type")));
00358
00359
00360 min = enum_endpoint(enumtypoid, ForwardScanDirection);
00361
00362 if (!OidIsValid(min))
00363 ereport(ERROR,
00364 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00365 errmsg("enum %s contains no values",
00366 format_type_be(enumtypoid))));
00367
00368 PG_RETURN_OID(min);
00369 }
00370
00371 Datum
00372 enum_last(PG_FUNCTION_ARGS)
00373 {
00374 Oid enumtypoid;
00375 Oid max;
00376
00377
00378
00379
00380
00381
00382 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
00383 if (enumtypoid == InvalidOid)
00384 ereport(ERROR,
00385 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00386 errmsg("could not determine actual enum type")));
00387
00388
00389 max = enum_endpoint(enumtypoid, BackwardScanDirection);
00390
00391 if (!OidIsValid(max))
00392 ereport(ERROR,
00393 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00394 errmsg("enum %s contains no values",
00395 format_type_be(enumtypoid))));
00396
00397 PG_RETURN_OID(max);
00398 }
00399
00400
00401 Datum
00402 enum_range_bounds(PG_FUNCTION_ARGS)
00403 {
00404 Oid lower;
00405 Oid upper;
00406 Oid enumtypoid;
00407
00408 if (PG_ARGISNULL(0))
00409 lower = InvalidOid;
00410 else
00411 lower = PG_GETARG_OID(0);
00412 if (PG_ARGISNULL(1))
00413 upper = InvalidOid;
00414 else
00415 upper = PG_GETARG_OID(1);
00416
00417
00418
00419
00420
00421
00422 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
00423 if (enumtypoid == InvalidOid)
00424 ereport(ERROR,
00425 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00426 errmsg("could not determine actual enum type")));
00427
00428 PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
00429 }
00430
00431
00432 Datum
00433 enum_range_all(PG_FUNCTION_ARGS)
00434 {
00435 Oid enumtypoid;
00436
00437
00438
00439
00440
00441
00442 enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
00443 if (enumtypoid == InvalidOid)
00444 ereport(ERROR,
00445 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00446 errmsg("could not determine actual enum type")));
00447
00448 PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid,
00449 InvalidOid, InvalidOid));
00450 }
00451
00452 static ArrayType *
00453 enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
00454 {
00455 ArrayType *result;
00456 Relation enum_rel;
00457 Relation enum_idx;
00458 SysScanDesc enum_scan;
00459 HeapTuple enum_tuple;
00460 ScanKeyData skey;
00461 Datum *elems;
00462 int max,
00463 cnt;
00464 bool left_found;
00465
00466
00467
00468
00469
00470
00471 ScanKeyInit(&skey,
00472 Anum_pg_enum_enumtypid,
00473 BTEqualStrategyNumber, F_OIDEQ,
00474 ObjectIdGetDatum(enumtypoid));
00475
00476 enum_rel = heap_open(EnumRelationId, AccessShareLock);
00477 enum_idx = index_open(EnumTypIdSortOrderIndexId, AccessShareLock);
00478 enum_scan = systable_beginscan_ordered(enum_rel, enum_idx,
00479 GetTransactionSnapshot(),
00480 1, &skey);
00481
00482 max = 64;
00483 elems = (Datum *) palloc(max * sizeof(Datum));
00484 cnt = 0;
00485 left_found = !OidIsValid(lower);
00486
00487 while (HeapTupleIsValid(enum_tuple = systable_getnext_ordered(enum_scan, ForwardScanDirection)))
00488 {
00489 Oid enum_oid = HeapTupleGetOid(enum_tuple);
00490
00491 if (!left_found && lower == enum_oid)
00492 left_found = true;
00493
00494 if (left_found)
00495 {
00496 if (cnt >= max)
00497 {
00498 max *= 2;
00499 elems = (Datum *) repalloc(elems, max * sizeof(Datum));
00500 }
00501
00502 elems[cnt++] = ObjectIdGetDatum(enum_oid);
00503 }
00504
00505 if (OidIsValid(upper) && upper == enum_oid)
00506 break;
00507 }
00508
00509 systable_endscan_ordered(enum_scan);
00510 index_close(enum_idx, AccessShareLock);
00511 heap_close(enum_rel, AccessShareLock);
00512
00513
00514
00515 result = construct_array(elems, cnt, enumtypoid, sizeof(Oid), true, 'i');
00516
00517 pfree(elems);
00518
00519 return result;
00520 }