diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/multirangetypes.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index fbcc27d0726..fbbda4af36d 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -34,6 +34,7 @@ #include "access/tupmacs.h" #include "common/hashfn.h" +#include "funcapi.h" #include "lib/stringinfo.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -1068,6 +1069,39 @@ multirange_constructor0(PG_FUNCTION_ARGS) PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL)); } +/* + * Cast multirange to an array of ranges. + */ +Datum +multirange_to_array(PG_FUNCTION_ARGS) +{ + ArrayBuildState *astate = NULL; + MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0); + TypeCacheEntry *typcache; + int i; + + typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); + + astate = initArrayResult(typcache->rngtype->type_id, + CurrentMemoryContext, + false); + + for (i = 0; i < mr->rangeCount; i++) + { + RangeType *r; + + r = multirange_get_range(typcache->rngtype, mr, i); + astate = accumArrayResult(astate, + RangeTypePGetDatum(r), + false, + typcache->rngtype->type_id, + CurrentMemoryContext); + } + + PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext)); +} + + /* multirange, multirange -> multirange type functions */ @@ -2645,6 +2679,78 @@ range_merge_from_multirange(PG_FUNCTION_ARGS) PG_RETURN_RANGE_P(result); } +/* Turn multirange into a set of ranges */ +Datum +multirange_unnest(PG_FUNCTION_ARGS) +{ + typedef struct + { + MultirangeType *mr; + TypeCacheEntry *typcache; + int index; + } multirange_unnest_fctx; + + FuncCallContext *funcctx; + multirange_unnest_fctx *fctx; + MemoryContext oldcontext; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + MultirangeType *mr; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* + * switch to memory context appropriate for multiple function calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* + * Get the multirange value and detoast if needed. We can't do this + * earlier because if we have to detoast, we want the detoasted copy + * to be in multi_call_memory_ctx, so it will go away when we're done + * and not before. (If no detoast happens, we assume the originally + * passed multirange will stick around till then.) + */ + mr = PG_GETARG_MULTIRANGE_P(0); + + /* allocate memory for user context */ + fctx = (multirange_unnest_fctx *) palloc(sizeof(multirange_unnest_fctx)); + + /* initialize state */ + fctx->mr = mr; + fctx->index = 0; + fctx->typcache = lookup_type_cache(MultirangeTypeGetOid(mr), + TYPECACHE_MULTIRANGE_INFO); + + funcctx->user_fctx = fctx; + MemoryContextSwitchTo(oldcontext); + } + + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); + fctx = funcctx->user_fctx; + + if (fctx->index < fctx->mr->rangeCount) + { + RangeType *range; + + range = multirange_get_range(fctx->typcache->rngtype, + fctx->mr, + fctx->index); + fctx->index++; + + SRF_RETURN_NEXT(funcctx, RangeTypePGetDatum(range)); + } + else + { + /* do when there is no more left */ + SRF_RETURN_DONE(funcctx); + } +} + /* Hash support */ /* hash a multirange value */ |