mirror of https://github.com/postgres/postgres
Multiranges are basically sorted arrays of non-overlapping ranges with set-theoretic operations defined over them. Since v14, each range type automatically gets a corresponding multirange datatype. There are both manual and automatic mechanisms for naming multirange types. Once can specify multirange type name using multirange_type_name attribute in CREATE TYPE. Otherwise, a multirange type name is generated automatically. If the range type name contains "range" then we change that to "multirange". Otherwise, we add "_multirange" to the end. Implementation of multiranges comes with a space-efficient internal representation format, which evades extra paddings and duplicated storage of oids. Altogether this format allows fetching a particular range by its index in O(n). Statistic gathering and selectivity estimation are implemented for multiranges. For this purpose, stored multirange is approximated as union range without gaps. This field will likely need improvements in the future. Catversion is bumped. Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0 Author: Paul Jungwirth, revised by me Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston Reviewed-by: Zhihong Yu, Alexander Korotkovpull/59/head
parent
08b01d4dd9
commit
6df7a9698b
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,116 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* multirangetypes.h |
||||
* Declarations for Postgres multirange types. |
||||
* |
||||
* |
||||
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* src/include/utils/multirangetypes.h |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef MULTIRANGETYPES_H |
||||
#define MULTIRANGETYPES_H |
||||
|
||||
#include "utils/typcache.h" |
||||
#include "utils/expandeddatum.h" |
||||
|
||||
|
||||
/*
|
||||
* Multiranges are varlena objects, so must meet the varlena convention that |
||||
* the first int32 of the object contains the total object size in bytes. |
||||
* Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! |
||||
*/ |
||||
typedef struct |
||||
{ |
||||
int32 vl_len_; /* varlena header (do not touch directly!) */ |
||||
Oid multirangetypid; /* multirange type's own OID */ |
||||
uint32 rangeCount; /* the number of ranges */ |
||||
|
||||
/*
|
||||
* Following the count are the range objects themselves, as ShortRangeType |
||||
* structs. Note that ranges are varlena too, depending on whether they |
||||
* have lower/upper bounds and because even their base types can be |
||||
* varlena. So we can't really index into this list. |
||||
*/ |
||||
} MultirangeType; |
||||
|
||||
/* Use these macros in preference to accessing these fields directly */ |
||||
#define MultirangeTypeGetOid(mr) ((mr)->multirangetypid) |
||||
#define MultirangeIsEmpty(mr) ((mr)->rangeCount == 0) |
||||
|
||||
/*
|
||||
* fmgr macros for multirange type objects |
||||
*/ |
||||
#define DatumGetMultirangeTypeP(X) ((MultirangeType *) PG_DETOAST_DATUM(X)) |
||||
#define DatumGetMultirangeTypePCopy(X) ((MultirangeType *) PG_DETOAST_DATUM_COPY(X)) |
||||
#define MultirangeTypePGetDatum(X) PointerGetDatum(X) |
||||
#define PG_GETARG_MULTIRANGE_P(n) DatumGetMultirangeTypeP(PG_GETARG_DATUM(n)) |
||||
#define PG_GETARG_MULTIRANGE_P_COPY(n) DatumGetMultirangeTypePCopy(PG_GETARG_DATUM(n)) |
||||
#define PG_RETURN_MULTIRANGE_P(x) return MultirangeTypePGetDatum(x) |
||||
|
||||
/*
|
||||
* prototypes for functions defined in multirangetypes.c |
||||
*/ |
||||
|
||||
/* internal versions of the above */ |
||||
extern bool multirange_eq_internal(TypeCacheEntry *typcache, MultirangeType *mr1, |
||||
MultirangeType *mr2); |
||||
extern bool multirange_ne_internal(TypeCacheEntry *typcache, MultirangeType *mr1, |
||||
MultirangeType *mr2); |
||||
extern bool multirange_contains_elem_internal(TypeCacheEntry *typcache, MultirangeType *mr, |
||||
Datum elem); |
||||
extern bool multirange_contains_range_internal(TypeCacheEntry *typcache, MultirangeType *mr, |
||||
RangeType *r); |
||||
extern bool multirange_contains_multirange_internal(TypeCacheEntry *typcache, |
||||
MultirangeType *mr1, |
||||
MultirangeType *mr2); |
||||
extern bool range_overlaps_multirange_internal(TypeCacheEntry *typcache, RangeType *r, |
||||
MultirangeType *mr); |
||||
extern bool multirange_overlaps_multirange_internal(TypeCacheEntry *typcache, |
||||
MultirangeType *mr1, |
||||
MultirangeType *mr2); |
||||
extern bool range_before_multirange_internal(TypeCacheEntry *typcache, RangeType *r, |
||||
MultirangeType *mr); |
||||
extern bool range_after_multirange_internal(TypeCacheEntry *typcache, RangeType *r, |
||||
MultirangeType *mr); |
||||
extern bool range_adjacent_multirange_internal(TypeCacheEntry *typcache, RangeType *r, |
||||
MultirangeType *mr); |
||||
extern bool multirange_before_multirange_internal(TypeCacheEntry *typcache, |
||||
MultirangeType *mr1, |
||||
MultirangeType *mr2); |
||||
extern MultirangeType *multirange_minus_internal(Oid mltrngtypoid, |
||||
TypeCacheEntry *rangetyp, |
||||
int32 range_count1, |
||||
RangeType **ranges1, |
||||
int32 range_count2, |
||||
RangeType **ranges2); |
||||
extern MultirangeType *multirange_intersect_internal(Oid mltrngtypoid, |
||||
TypeCacheEntry *rangetyp, |
||||
int32 range_count1, |
||||
RangeType **ranges1, |
||||
int32 range_count2, |
||||
RangeType **ranges2); |
||||
|
||||
/* assorted support functions */ |
||||
extern TypeCacheEntry *multirange_get_typcache(FunctionCallInfo fcinfo, |
||||
Oid mltrngtypid); |
||||
extern void multirange_deserialize(TypeCacheEntry *rangetyp, |
||||
const MultirangeType *range, |
||||
int32 *range_count, |
||||
RangeType ***ranges); |
||||
extern MultirangeType *make_multirange(Oid mltrngtypoid, |
||||
TypeCacheEntry *typcache, |
||||
int32 range_count, RangeType **ranges); |
||||
extern MultirangeType *make_empty_multirange(Oid mltrngtypoid, |
||||
TypeCacheEntry *rangetyp); |
||||
extern void multirange_get_bounds(TypeCacheEntry *rangetyp, |
||||
const MultirangeType *multirange, |
||||
uint32 i, |
||||
RangeBound *lower, RangeBound *upper); |
||||
extern RangeType *multirange_get_range(TypeCacheEntry *rangetyp, |
||||
const MultirangeType *multirange, int i); |
||||
|
||||
#endif /* MULTIRANGETYPES_H */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,677 @@ |
||||
-- Tests for multirange data types. |
||||
|
||||
-- |
||||
-- test input parser |
||||
-- |
||||
|
||||
-- negative tests; should fail |
||||
select ''::textmultirange; |
||||
select '{,}'::textmultirange; |
||||
select '{[a,c),}'::textmultirange; |
||||
select '{,[a,c)}'::textmultirange; |
||||
select '{-[a,z)}'::textmultirange; |
||||
select '{[a,z) - }'::textmultirange; |
||||
select '{(",a)}'::textmultirange; |
||||
select '{(,,a)}'::textmultirange; |
||||
select '{(),a)}'::textmultirange; |
||||
select '{(a,))}'::textmultirange; |
||||
select '{(],a)}'::textmultirange; |
||||
select '{(a,])}'::textmultirange; |
||||
select '{[z,a]}'::textmultirange; |
||||
|
||||
-- should succeed |
||||
select '{}'::textmultirange; |
||||
select ' {} '::textmultirange; |
||||
select ' { empty, empty } '::textmultirange; |
||||
select ' {( " a " " a ", " z " " z " ) }'::textmultirange; |
||||
select '{(,z)}'::textmultirange; |
||||
select '{(a,)}'::textmultirange; |
||||
select '{[,z]}'::textmultirange; |
||||
select '{[a,]}'::textmultirange; |
||||
select '{(,)}'::textmultirange; |
||||
select '{[ , ]}'::textmultirange; |
||||
select '{["",""]}'::textmultirange; |
||||
select '{[",",","]}'::textmultirange; |
||||
select '{["\\","\\"]}'::textmultirange; |
||||
select '{["""","\""]}'::textmultirange; |
||||
select '{(\\,a)}'::textmultirange; |
||||
select '{((,z)}'::textmultirange; |
||||
select '{([,z)}'::textmultirange; |
||||
select '{(!,()}'::textmultirange; |
||||
select '{(!,[)}'::textmultirange; |
||||
select '{[a,a]}'::textmultirange; |
||||
select '{[a,a],[a,b]}'::textmultirange; |
||||
select '{[a,b), [b,e]}'::textmultirange; |
||||
select '{[a,d), [b,f]}'::textmultirange; |
||||
select '{[a,a],[b,b]}'::textmultirange; |
||||
-- without canonicalization, we can't join these: |
||||
select '{[a,a], [b,b]}'::textmultirange; |
||||
-- with canonicalization, we can join these: |
||||
select '{[1,2], [3,4]}'::int4multirange; |
||||
select '{[a,a], [b,b], [c,c]}'::textmultirange; |
||||
select '{[a,d], [b,e]}'::textmultirange; |
||||
select '{[a,d), [d,e)}'::textmultirange; |
||||
-- these are allowed but normalize to empty: |
||||
select '{[a,a)}'::textmultirange; |
||||
select '{(a,a]}'::textmultirange; |
||||
select '{(a,a)}'::textmultirange; |
||||
|
||||
-- |
||||
-- test the constructor |
||||
--- |
||||
select textmultirange(); |
||||
select textmultirange(textrange('a', 'c')); |
||||
select textmultirange(textrange('a', 'c'), textrange('f', 'g')); |
||||
select textmultirange(textrange('a', 'c'), textrange('b', 'd')); |
||||
|
||||
-- |
||||
-- test casts, both a built-in range type and a user-defined one: |
||||
-- |
||||
select 'empty'::int4range::int4multirange; |
||||
select int4range(1, 3)::int4multirange; |
||||
select int4range(1, null)::int4multirange; |
||||
select int4range(null, null)::int4multirange; |
||||
select 'empty'::textrange::textmultirange; |
||||
select textrange('a', 'c')::textmultirange; |
||||
select textrange('a', null)::textmultirange; |
||||
select textrange(null, null)::textmultirange; |
||||
|
||||
-- |
||||
-- create some test data and test the operators |
||||
-- |
||||
|
||||
CREATE TABLE nummultirange_test (nmr NUMMULTIRANGE); |
||||
CREATE INDEX nummultirange_test_btree ON nummultirange_test(nmr); |
||||
|
||||
INSERT INTO nummultirange_test VALUES('{}'); |
||||
INSERT INTO nummultirange_test VALUES('{[,)}'); |
||||
INSERT INTO nummultirange_test VALUES('{[3,]}'); |
||||
INSERT INTO nummultirange_test VALUES('{[,), [3,]}'); |
||||
INSERT INTO nummultirange_test VALUES('{[, 5)}'); |
||||
INSERT INTO nummultirange_test VALUES(nummultirange()); |
||||
INSERT INTO nummultirange_test VALUES(nummultirange(variadic '{}'::numrange[])); |
||||
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.1, 2.2))); |
||||
INSERT INTO nummultirange_test VALUES('{empty}'); |
||||
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.7, 1.9))); |
||||
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.9, 2.1))); |
||||
|
||||
SELECT nmr, isempty(nmr), lower(nmr), upper(nmr) FROM nummultirange_test ORDER BY nmr; |
||||
SELECT nmr, lower_inc(nmr), lower_inf(nmr), upper_inc(nmr), upper_inf(nmr) FROM nummultirange_test ORDER BY nmr; |
||||
|
||||
SELECT * FROM nummultirange_test WHERE nmr = '{}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr = '{(,5)}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr = '{[3,)}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr = '{[1.7,1.7]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr = '{[1.7,1.7],[1.9,2.1)}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr < '{}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr < '{[-1000.0, -1000.0]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr < '{[0.0, 1.0]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr < '{[1000.0, 1001.0]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr <= '{}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr <= '{[3,)}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr >= '{}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr >= '{[3,)}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr > '{}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr > '{[-1000.0, -1000.0]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr > '{[0.0, 1.0]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr > '{[1000.0, 1001.0]}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr <> '{}'; |
||||
SELECT * FROM nummultirange_test WHERE nmr <> '{(,5)}'; |
||||
|
||||
select nummultirange(numrange(2.0, 1.0)); |
||||
select nummultirange(numrange(5.0, 6.0), numrange(1.0, 2.0)); |
||||
|
||||
analyze nummultirange_test; |
||||
|
||||
-- overlaps |
||||
SELECT * FROM nummultirange_test WHERE range_overlaps_multirange(numrange(4.0, 4.2), nmr); |
||||
SELECT * FROM nummultirange_test WHERE numrange(4.0, 4.2) && nmr; |
||||
SELECT * FROM nummultirange_test WHERE multirange_overlaps_range(nmr, numrange(4.0, 4.2)); |
||||
SELECT * FROM nummultirange_test WHERE nmr && numrange(4.0, 4.2); |
||||
SELECT * FROM nummultirange_test WHERE multirange_overlaps_multirange(nmr, nummultirange(numrange(4.0, 4.2), numrange(6.0, 7.0))); |
||||
SELECT * FROM nummultirange_test WHERE nmr && nummultirange(numrange(4.0, 4.2), numrange(6.0, 7.0)); |
||||
SELECT * FROM nummultirange_test WHERE nmr && nummultirange(numrange(6.0, 7.0)); |
||||
SELECT * FROM nummultirange_test WHERE nmr && nummultirange(numrange(6.0, 7.0), numrange(8.0, 9.0)); |
||||
|
||||
-- mr contains x |
||||
SELECT * FROM nummultirange_test WHERE multirange_contains_elem(nmr, 4.0); |
||||
SELECT * FROM nummultirange_test WHERE nmr @> 4.0; |
||||
SELECT * FROM nummultirange_test WHERE multirange_contains_range(nmr, numrange(4.0, 4.2)); |
||||
SELECT * FROM nummultirange_test WHERE nmr @> numrange(4.0, 4.2); |
||||
SELECT * FROM nummultirange_test WHERE multirange_contains_multirange(nmr, '{[4.0,4.2), [6.0, 8.0)}'); |
||||
SELECT * FROM nummultirange_test WHERE nmr @> '{[4.0,4.2), [6.0, 8.0)}'::nummultirange; |
||||
|
||||
-- x is contained by mr |
||||
SELECT * FROM nummultirange_test WHERE elem_contained_by_multirange(4.0, nmr); |
||||
SELECT * FROM nummultirange_test WHERE 4.0 <@ nmr; |
||||
SELECT * FROM nummultirange_test WHERE range_contained_by_multirange(numrange(4.0, 4.2), nmr); |
||||
SELECT * FROM nummultirange_test WHERE numrange(4.0, 4.2) <@ nmr; |
||||
SELECT * FROM nummultirange_test WHERE multirange_contained_by_multirange('{[4.0,4.2), [6.0, 8.0)}', nmr); |
||||
SELECT * FROM nummultirange_test WHERE '{[4.0,4.2), [6.0, 8.0)}'::nummultirange <@ nmr; |
||||
|
||||
-- overlaps |
||||
SELECT 'empty'::numrange && nummultirange(); |
||||
SELECT 'empty'::numrange && nummultirange(numrange(1,2)); |
||||
SELECT nummultirange() && 'empty'::numrange; |
||||
SELECT nummultirange(numrange(1,2)) && 'empty'::numrange; |
||||
SELECT nummultirange() && nummultirange(); |
||||
SELECT nummultirange() && nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) && nummultirange(); |
||||
SELECT nummultirange(numrange(3,4)) && nummultirange(numrange(1,2), numrange(7,8)); |
||||
SELECT nummultirange(numrange(1,2), numrange(7,8)) && nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(3,4)) && nummultirange(numrange(1,2), numrange(3.5,8)); |
||||
SELECT nummultirange(numrange(1,2), numrange(3.5,8)) && numrange(3,4); |
||||
SELECT nummultirange(numrange(1,2), numrange(3.5,8)) && nummultirange(numrange(3,4)); |
||||
|
||||
-- contains |
||||
SELECT nummultirange() @> nummultirange(); |
||||
SELECT nummultirange() @> 'empty'::numrange; |
||||
SELECT nummultirange(numrange(null,null)) @> numrange(1,2); |
||||
SELECT nummultirange(numrange(null,null)) @> numrange(null,2); |
||||
SELECT nummultirange(numrange(null,null)) @> numrange(2,null); |
||||
SELECT nummultirange(numrange(null,5)) @> numrange(null,3); |
||||
SELECT nummultirange(numrange(null,5)) @> numrange(null,8); |
||||
SELECT nummultirange(numrange(5,null)) @> numrange(8,null); |
||||
SELECT nummultirange(numrange(5,null)) @> numrange(3,null); |
||||
SELECT nummultirange(numrange(1,5)) @> numrange(8,9); |
||||
SELECT nummultirange(numrange(1,5)) @> numrange(3,9); |
||||
SELECT nummultirange(numrange(1,5)) @> numrange(1,4); |
||||
SELECT nummultirange(numrange(1,5)) @> numrange(1,5); |
||||
SELECT nummultirange(numrange(-4,-2), numrange(1,5)) @> numrange(1,5); |
||||
SELECT nummultirange(numrange(1,5), numrange(8,9)) @> numrange(1,5); |
||||
SELECT nummultirange(numrange(1,5), numrange(8,9)) @> numrange(6,7); |
||||
SELECT nummultirange(numrange(1,5), numrange(6,9)) @> numrange(6,7); |
||||
SELECT '{[1,5)}'::nummultirange @> '{[1,5)}'; |
||||
SELECT '{[-4,-2), [1,5)}'::nummultirange @> '{[1,5)}'; |
||||
SELECT '{[1,5), [8,9)}'::nummultirange @> '{[1,5)}'; |
||||
SELECT '{[1,5), [8,9)}'::nummultirange @> '{[6,7)}'; |
||||
SELECT '{[1,5), [6,9)}'::nummultirange @> '{[6,7)}'; |
||||
|
||||
-- is contained by |
||||
SELECT nummultirange() <@ nummultirange(); |
||||
SELECT 'empty'::numrange <@ nummultirange(); |
||||
SELECT numrange(1,2) <@ nummultirange(numrange(null,null)); |
||||
SELECT numrange(null,2) <@ nummultirange(numrange(null,null)); |
||||
SELECT numrange(2,null) <@ nummultirange(numrange(null,null)); |
||||
SELECT numrange(null,3) <@ nummultirange(numrange(null,5)); |
||||
SELECT numrange(null,8) <@ nummultirange(numrange(null,5)); |
||||
SELECT numrange(8,null) <@ nummultirange(numrange(5,null)); |
||||
SELECT numrange(3,null) <@ nummultirange(numrange(5,null)); |
||||
SELECT numrange(8,9) <@ nummultirange(numrange(1,5)); |
||||
SELECT numrange(3,9) <@ nummultirange(numrange(1,5)); |
||||
SELECT numrange(1,4) <@ nummultirange(numrange(1,5)); |
||||
SELECT numrange(1,5) <@ nummultirange(numrange(1,5)); |
||||
SELECT numrange(1,5) <@ nummultirange(numrange(-4,-2), numrange(1,5)); |
||||
SELECT numrange(1,5) <@ nummultirange(numrange(1,5), numrange(8,9)); |
||||
SELECT numrange(6,7) <@ nummultirange(numrange(1,5), numrange(8,9)); |
||||
SELECT numrange(6,7) <@ nummultirange(numrange(1,5), numrange(6,9)); |
||||
SELECT '{[1,5)}' <@ '{[1,5)}'::nummultirange; |
||||
SELECT '{[1,5)}' <@ '{[-4,-2), [1,5)}'::nummultirange; |
||||
SELECT '{[1,5)}' <@ '{[1,5), [8,9)}'::nummultirange; |
||||
SELECT '{[6,7)}' <@ '{[1,5), [8,9)}'::nummultirange; |
||||
SELECT '{[6,7)}' <@ '{[1,5), [6,9)}'::nummultirange; |
||||
|
||||
-- overleft |
||||
SELECT 'empty'::numrange &< nummultirange(); |
||||
SELECT 'empty'::numrange &< nummultirange(numrange(1,2)); |
||||
SELECT nummultirange() &< 'empty'::numrange; |
||||
SELECT nummultirange(numrange(1,2)) &< 'empty'::numrange; |
||||
SELECT nummultirange() &< nummultirange(); |
||||
SELECT nummultirange(numrange(1,2)) &< nummultirange(); |
||||
SELECT nummultirange() &< nummultirange(numrange(1,2)); |
||||
SELECT numrange(6,7) &< nummultirange(numrange(3,4)); |
||||
SELECT numrange(1,2) &< nummultirange(numrange(3,4)); |
||||
SELECT numrange(1,4) &< nummultirange(numrange(3,4)); |
||||
SELECT numrange(1,6) &< nummultirange(numrange(3,4)); |
||||
SELECT numrange(3.5,6) &< nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(6,7)) &< numrange(3,4); |
||||
SELECT nummultirange(numrange(1,2)) &< numrange(3,4); |
||||
SELECT nummultirange(numrange(1,4)) &< numrange(3,4); |
||||
SELECT nummultirange(numrange(1,6)) &< numrange(3,4); |
||||
SELECT nummultirange(numrange(3.5,6)) &< numrange(3,4); |
||||
SELECT nummultirange(numrange(6,7)) &< nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,2)) &< nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,4)) &< nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,6)) &< nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(3.5,6)) &< nummultirange(numrange(3,4)); |
||||
|
||||
-- overright |
||||
SELECT nummultirange() &> 'empty'::numrange; |
||||
SELECT nummultirange(numrange(1,2)) &> 'empty'::numrange; |
||||
SELECT 'empty'::numrange &> nummultirange(); |
||||
SELECT 'empty'::numrange &> nummultirange(numrange(1,2)); |
||||
SELECT nummultirange() &> nummultirange(); |
||||
SELECT nummultirange() &> nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) &> nummultirange(); |
||||
SELECT nummultirange(numrange(3,4)) &> numrange(6,7); |
||||
SELECT nummultirange(numrange(3,4)) &> numrange(1,2); |
||||
SELECT nummultirange(numrange(3,4)) &> numrange(1,4); |
||||
SELECT nummultirange(numrange(3,4)) &> numrange(1,6); |
||||
SELECT nummultirange(numrange(3,4)) &> numrange(3.5,6); |
||||
SELECT numrange(3,4) &> nummultirange(numrange(6,7)); |
||||
SELECT numrange(3,4) &> nummultirange(numrange(1,2)); |
||||
SELECT numrange(3,4) &> nummultirange(numrange(1,4)); |
||||
SELECT numrange(3,4) &> nummultirange(numrange(1,6)); |
||||
SELECT numrange(3,4) &> nummultirange(numrange(3.5,6)); |
||||
SELECT nummultirange(numrange(3,4)) &> nummultirange(numrange(6,7)); |
||||
SELECT nummultirange(numrange(3,4)) &> nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(3,4)) &> nummultirange(numrange(1,4)); |
||||
SELECT nummultirange(numrange(3,4)) &> nummultirange(numrange(1,6)); |
||||
SELECT nummultirange(numrange(3,4)) &> nummultirange(numrange(3.5,6)); |
||||
|
||||
-- meets |
||||
SELECT 'empty'::numrange -|- nummultirange(); |
||||
SELECT 'empty'::numrange -|- nummultirange(numrange(1,2)); |
||||
SELECT nummultirange() -|- 'empty'::numrange; |
||||
SELECT nummultirange(numrange(1,2)) -|- 'empty'::numrange; |
||||
SELECT nummultirange() -|- nummultirange(); |
||||
SELECT nummultirange(numrange(1,2)) -|- nummultirange(); |
||||
SELECT nummultirange() -|- nummultirange(numrange(1,2)); |
||||
SELECT numrange(1,2) -|- nummultirange(numrange(2,4)); |
||||
SELECT numrange(1,2) -|- nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,2)) -|- numrange(2,4); |
||||
SELECT nummultirange(numrange(1,2)) -|- numrange(3,4); |
||||
SELECT nummultirange(numrange(1,2)) -|- nummultirange(numrange(2,4)); |
||||
SELECT nummultirange(numrange(1,2)) -|- nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,2), numrange(5,6)) -|- nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,2), numrange(5,6)) -|- nummultirange(numrange(6,7)); |
||||
SELECT nummultirange(numrange(1,2), numrange(5,6)) -|- nummultirange(numrange(8,9)); |
||||
SELECT nummultirange(numrange(1,2)) -|- nummultirange(numrange(2,4), numrange(6,7)); |
||||
|
||||
-- strictly left |
||||
select 'empty'::numrange << nummultirange(); |
||||
select numrange(1,2) << nummultirange(); |
||||
select numrange(1,2) << nummultirange(numrange(3,4)); |
||||
select numrange(1,2) << nummultirange(numrange(0,4)); |
||||
select numrange(1,2) << nummultirange(numrange(0,4), numrange(7,8)); |
||||
select nummultirange() << 'empty'::numrange; |
||||
select nummultirange() << numrange(1,2); |
||||
select nummultirange(numrange(3,4)) << numrange(3,6); |
||||
select nummultirange(numrange(0,2)) << numrange(3,6); |
||||
select nummultirange(numrange(0,2), numrange(7,8)) << numrange(3,6); |
||||
select nummultirange(numrange(-4,-2), numrange(0,2)) << numrange(3,6); |
||||
select nummultirange() << nummultirange(); |
||||
select nummultirange() << nummultirange(numrange(1,2)); |
||||
select nummultirange(numrange(1,2)) << nummultirange(); |
||||
select nummultirange(numrange(1,2)) << nummultirange(numrange(1,2)); |
||||
select nummultirange(numrange(1,2)) << nummultirange(numrange(3,4)); |
||||
select nummultirange(numrange(1,2)) << nummultirange(numrange(3,4), numrange(7,8)); |
||||
select nummultirange(numrange(1,2), numrange(4,5)) << nummultirange(numrange(3,4), numrange(7,8)); |
||||
|
||||
-- strictly right |
||||
select nummultirange() >> 'empty'::numrange; |
||||
select nummultirange() >> numrange(1,2); |
||||
select nummultirange(numrange(3,4)) >> numrange(1,2); |
||||
select nummultirange(numrange(0,4)) >> numrange(1,2); |
||||
select nummultirange(numrange(0,4), numrange(7,8)) >> numrange(1,2); |
||||
select 'empty'::numrange >> nummultirange(); |
||||
select numrange(1,2) >> nummultirange(); |
||||
select numrange(3,6) >> nummultirange(numrange(3,4)); |
||||
select numrange(3,6) >> nummultirange(numrange(0,2)); |
||||
select numrange(3,6) >> nummultirange(numrange(0,2), numrange(7,8)); |
||||
select numrange(3,6) >> nummultirange(numrange(-4,-2), numrange(0,2)); |
||||
select nummultirange() >> nummultirange(); |
||||
select nummultirange(numrange(1,2)) >> nummultirange(); |
||||
select nummultirange() >> nummultirange(numrange(1,2)); |
||||
select nummultirange(numrange(1,2)) >> nummultirange(numrange(1,2)); |
||||
select nummultirange(numrange(3,4)) >> nummultirange(numrange(1,2)); |
||||
select nummultirange(numrange(3,4), numrange(7,8)) >> nummultirange(numrange(1,2)); |
||||
select nummultirange(numrange(3,4), numrange(7,8)) >> nummultirange(numrange(1,2), numrange(4,5)); |
||||
|
||||
-- union |
||||
SELECT nummultirange() + nummultirange(); |
||||
SELECT nummultirange() + nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) + nummultirange(); |
||||
SELECT nummultirange(numrange(1,2)) + nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) + nummultirange(numrange(2,4)); |
||||
SELECT nummultirange(numrange(1,2)) + nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) + nummultirange(numrange(2,4)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) + nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) + nummultirange(numrange(0,9)); |
||||
|
||||
-- merge |
||||
SELECT range_merge(nummultirange()); |
||||
SELECT range_merge(nummultirange(numrange(1,2))); |
||||
SELECT range_merge(nummultirange(numrange(1,2), numrange(7,8))); |
||||
|
||||
-- minus |
||||
SELECT nummultirange() - nummultirange(); |
||||
SELECT nummultirange() - nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) - nummultirange(); |
||||
SELECT nummultirange(numrange(1,2), numrange(3,4)) - nummultirange(); |
||||
SELECT nummultirange(numrange(1,2)) - nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) - nummultirange(numrange(2,4)); |
||||
SELECT nummultirange(numrange(1,2)) - nummultirange(numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,4)) - nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,4)) - nummultirange(numrange(2,3)); |
||||
SELECT nummultirange(numrange(1,4)) - nummultirange(numrange(0,8)); |
||||
SELECT nummultirange(numrange(1,4)) - nummultirange(numrange(0,2)); |
||||
SELECT nummultirange(numrange(1,8)) - nummultirange(numrange(0,2), numrange(3,4)); |
||||
SELECT nummultirange(numrange(1,8)) - nummultirange(numrange(2,3), numrange(5,null)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(-2,0)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(2,4)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(3,5)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(0,9)); |
||||
SELECT nummultirange(numrange(1,3), numrange(4,5)) - nummultirange(numrange(2,9)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(8,9)); |
||||
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(-2,0), numrange(8,9)); |
||||
|
||||
-- intersection |
||||
SELECT nummultirange() * nummultirange(); |
||||
SELECT nummultirange() * nummultirange(numrange(1,2)); |
||||
SELECT nummultirange(numrange(1,2)) * nummultirange(); |
||||
SELECT '{[1,3)}'::nummultirange * '{[1,5)}'::nummultirange; |
||||
SELECT '{[1,3)}'::nummultirange * '{[0,5)}'::nummultirange; |
||||
SELECT '{[1,3)}'::nummultirange * '{[0,2)}'::nummultirange; |
||||
SELECT '{[1,3)}'::nummultirange * '{[2,5)}'::nummultirange; |
||||
SELECT '{[1,4)}'::nummultirange * '{[2,3)}'::nummultirange; |
||||
SELECT '{[1,4)}'::nummultirange * '{[0,2), [3,5)}'::nummultirange; |
||||
SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,8), [9,12)}'::nummultirange; |
||||
SELECT '{[1,4), [7,10)}'::nummultirange * '{[9,12)}'::nummultirange; |
||||
SELECT '{[1,4), [7,10)}'::nummultirange * '{[-5,-4), [5,6), [9,12)}'::nummultirange; |
||||
SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirange; |
||||
SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirange; |
||||
|
||||
-- |
||||
-- range_agg function |
||||
-- |
||||
create table reservations ( room_id integer not null, booked_during daterange ); |
||||
insert into reservations values |
||||
-- 1: has a meets and a gap |
||||
(1, daterange('2018-07-01', '2018-07-07')), |
||||
(1, daterange('2018-07-07', '2018-07-14')), |
||||
(1, daterange('2018-07-20', '2018-07-22')), |
||||
-- 2: just a single row |
||||
(2, daterange('2018-07-01', '2018-07-03')), |
||||
-- 3: one null range |
||||
(3, NULL), |
||||
-- 4: two null ranges |
||||
(4, NULL), |
||||
(4, NULL), |
||||
-- 5: a null range and a non-null range |
||||
(5, NULL), |
||||
(5, daterange('2018-07-01', '2018-07-03')), |
||||
-- 6: has overlap |
||||
(6, daterange('2018-07-01', '2018-07-07')), |
||||
(6, daterange('2018-07-05', '2018-07-10')), |
||||
-- 7: two ranges that meet: no gap or overlap |
||||
(7, daterange('2018-07-01', '2018-07-07')), |
||||
(7, daterange('2018-07-07', '2018-07-14')), |
||||
-- 8: an empty range |
||||
(8, 'empty'::daterange) |
||||
; |
||||
SELECT room_id, range_agg(booked_during) |
||||
FROM reservations |
||||
GROUP BY room_id |
||||
ORDER BY room_id; |
||||
|
||||
-- range_agg on a custom range type too |
||||
SELECT range_agg(r) |
||||
FROM (VALUES |
||||
('[a,c]'::textrange), |
||||
('[b,b]'::textrange), |
||||
('[c,f]'::textrange), |
||||
('[g,h)'::textrange), |
||||
('[h,j)'::textrange) |
||||
) t(r); |
||||
|
||||
select range_intersect_agg(nmr) from nummultirange_test; |
||||
select range_intersect_agg(nmr) from nummultirange_test where false; |
||||
-- test with just one input: |
||||
select range_intersect_agg(nmr) from (values ('{[1,2]}'::nummultirange)) t(nmr); |
||||
select range_intersect_agg(nmr) from nummultirange_test where nmr @> 4.0; |
||||
|
||||
create table nummultirange_test2(nmr nummultirange); |
||||
create index nummultirange_test2_hash_idx on nummultirange_test2 using hash (nmr); |
||||
|
||||
INSERT INTO nummultirange_test2 VALUES('{[, 5)}'); |
||||
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2))); |
||||
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2))); |
||||
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2,'()'))); |
||||
INSERT INTO nummultirange_test2 VALUES('{}'); |
||||
|
||||
select * from nummultirange_test2 where nmr = '{}'; |
||||
select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.2)); |
||||
select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.3)); |
||||
|
||||
set enable_nestloop=t; |
||||
set enable_hashjoin=f; |
||||
set enable_mergejoin=f; |
||||
select * from nummultirange_test natural join nummultirange_test2 order by nmr; |
||||
set enable_nestloop=f; |
||||
set enable_hashjoin=t; |
||||
set enable_mergejoin=f; |
||||
select * from nummultirange_test natural join nummultirange_test2 order by nmr; |
||||
set enable_nestloop=f; |
||||
set enable_hashjoin=f; |
||||
set enable_mergejoin=t; |
||||
select * from nummultirange_test natural join nummultirange_test2 order by nmr; |
||||
|
||||
set enable_nestloop to default; |
||||
set enable_hashjoin to default; |
||||
set enable_mergejoin to default; |
||||
|
||||
DROP TABLE nummultirange_test2; |
||||
|
||||
-- |
||||
-- Test user-defined multirange of floats |
||||
-- |
||||
|
||||
select '{[123.001, 5.e9)}'::float8multirange @> 888.882::float8; |
||||
create table float8multirange_test(f8mr float8multirange, i int); |
||||
insert into float8multirange_test values(float8multirange(float8range(-100.00007, '1.111113e9')), 42); |
||||
select * from float8multirange_test; |
||||
drop table float8multirange_test; |
||||
|
||||
-- |
||||
-- Test multirange types over domains |
||||
-- |
||||
|
||||
create domain mydomain as int4; |
||||
create type mydomainrange as range(subtype=mydomain); |
||||
select '{[4,50)}'::mydomainmultirange @> 7::mydomain; |
||||
drop domain mydomain cascade; |
||||
|
||||
-- |
||||
-- Test domains over multirange types |
||||
-- |
||||
|
||||
create domain restrictedmultirange as int4multirange check (upper(value) < 10); |
||||
select '{[4,5)}'::restrictedmultirange @> 7; |
||||
select '{[4,50)}'::restrictedmultirange @> 7; -- should fail |
||||
drop domain restrictedmultirange; |
||||
|
||||
--- |
||||
-- Check automatic naming of multiranges |
||||
--- |
||||
|
||||
create type intr as range(subtype=int); |
||||
select intr_multirange(intr(1,10)); |
||||
drop type intr; |
||||
create type intmultirange as (x int, y int); |
||||
create type intrange as range(subtype=int); -- should fail |
||||
drop type intmultirange; |
||||
create type intr_multirange as (x int, y int); |
||||
create type intr as range(subtype=int); -- should fail |
||||
drop type intr_multirange; |
||||
|
||||
-- |
||||
-- Test multiple multirange types over the same subtype and manual naming of |
||||
-- the multirange type. |
||||
-- |
||||
|
||||
-- should fail |
||||
create type textrange1 as range(subtype=text, multirange_type_name=int, collation="C"); |
||||
-- should pass |
||||
create type textrange1 as range(subtype=text, multirange_type_name=multirange_of_text, collation="C"); |
||||
-- should pass, because existing _textrange1 is automatically renamed |
||||
create type textrange2 as range(subtype=text, multirange_type_name=_textrange1, collation="C"); |
||||
|
||||
select multirange_of_text(textrange2('a','Z')); -- should fail |
||||
select multirange_of_text(textrange1('a','Z')) @> 'b'::text; |
||||
select _textrange1(textrange2('a','z')) @> 'b'::text; |
||||
|
||||
drop type textrange1; |
||||
drop type textrange2; |
||||
|
||||
-- |
||||
-- Test polymorphic type system |
||||
-- |
||||
|
||||
create function anyarray_anymultirange_func(a anyarray, r anymultirange) |
||||
returns anyelement as 'select $1[1] + lower($2);' language sql; |
||||
|
||||
select anyarray_anymultirange_func(ARRAY[1,2], int4multirange(int4range(10,20))); |
||||
|
||||
-- should fail |
||||
select anyarray_anymultirange_func(ARRAY[1,2], nummultirange(numrange(10,20))); |
||||
|
||||
drop function anyarray_anymultirange_func(anyarray, anymultirange); |
||||
|
||||
-- should fail |
||||
create function bogus_func(anyelement) |
||||
returns anymultirange as 'select int4multirange(int4range(1,10))' language sql; |
||||
|
||||
-- should fail |
||||
create function bogus_func(int) |
||||
returns anymultirange as 'select int4multirange(int4range(1,10))' language sql; |
||||
|
||||
create function range_add_bounds(anymultirange) |
||||
returns anyelement as 'select lower($1) + upper($1)' language sql; |
||||
|
||||
select range_add_bounds(int4multirange(int4range(1, 17))); |
||||
select range_add_bounds(nummultirange(numrange(1.0001, 123.123))); |
||||
|
||||
create function multirangetypes_sql(q anymultirange, b anyarray, out c anyelement) |
||||
as $$ select upper($1) + $2[1] $$ |
||||
language sql; |
||||
|
||||
select multirangetypes_sql(int4multirange(int4range(1,10)), ARRAY[2,20]); |
||||
select multirangetypes_sql(nummultirange(numrange(1,10)), ARRAY[2,20]); -- match failure |
||||
|
||||
create function anycompatiblearray_anycompatiblemultirange_func(a anycompatiblearray, mr anycompatiblemultirange) |
||||
returns anycompatible as 'select $1[1] + lower($2);' language sql; |
||||
|
||||
select anycompatiblearray_anycompatiblemultirange_func(ARRAY[1,2], multirange(int4range(10,20))); |
||||
|
||||
select anycompatiblearray_anycompatiblemultirange_func(ARRAY[1,2], multirange(numrange(10,20))); |
||||
|
||||
-- should fail |
||||
select anycompatiblearray_anycompatiblemultirange_func(ARRAY[1.1,2], multirange(int4range(10,20))); |
||||
|
||||
drop function anycompatiblearray_anycompatiblemultirange_func(anycompatiblearray, anycompatiblemultirange); |
||||
|
||||
create function anycompatiblerange_anycompatiblemultirange_func(r anycompatiblerange, mr anycompatiblemultirange) |
||||
returns anycompatible as 'select lower($1) + lower($2);' language sql; |
||||
|
||||
select anycompatiblerange_anycompatiblemultirange_func(int4range(1,2), multirange(int4range(10,20))); |
||||
|
||||
-- should fail |
||||
select anycompatiblerange_anycompatiblemultirange_func(numrange(1,2), multirange(int4range(10,20))); |
||||
|
||||
drop function anycompatiblerange_anycompatiblemultirange_func(anycompatiblerange, anycompatiblemultirange); |
||||
|
||||
-- should fail |
||||
create function bogus_func(anycompatible) |
||||
returns anycompatiblerange as 'select int4range(1,10)' language sql; |
||||
|
||||
-- |
||||
-- Arrays of multiranges |
||||
-- |
||||
|
||||
select ARRAY[nummultirange(numrange(1.1, 1.2)), nummultirange(numrange(12.3, 155.5))]; |
||||
|
||||
create table i8mr_array (f1 int, f2 int8multirange[]); |
||||
insert into i8mr_array values (42, array[int8multirange(int8range(1,10)), int8multirange(int8range(2,20))]); |
||||
select * from i8mr_array; |
||||
drop table i8mr_array; |
||||
|
||||
-- |
||||
-- Multiranges of arrays |
||||
-- |
||||
|
||||
select arraymultirange(arrayrange(ARRAY[1,2], ARRAY[2,1])); |
||||
select arraymultirange(arrayrange(ARRAY[2,1], ARRAY[1,2])); -- fail |
||||
|
||||
select array[1,1] <@ arraymultirange(arrayrange(array[1,2], array[2,1])); |
||||
select array[1,3] <@ arraymultirange(arrayrange(array[1,2], array[2,1])); |
||||
|
||||
-- |
||||
-- Ranges of composites |
||||
-- |
||||
|
||||
create type two_ints as (a int, b int); |
||||
create type two_ints_range as range (subtype = two_ints); |
||||
|
||||
-- with force_parallel_mode on, this exercises tqueue.c's range remapping |
||||
select *, row_to_json(upper(t)) as u from |
||||
(values (two_ints_multirange(two_ints_range(row(1,2), row(3,4)))), |
||||
(two_ints_multirange(two_ints_range(row(5,6), row(7,8))))) v(t); |
||||
|
||||
drop type two_ints cascade; |
||||
|
||||
-- |
||||
-- Check behavior when subtype lacks a hash function |
||||
-- |
||||
|
||||
set enable_sort = off; -- try to make it pick a hash setop implementation |
||||
|
||||
select '{(2,5)}'::cashmultirange except select '{(5,6)}'::cashmultirange; |
||||
|
||||
reset enable_sort; |
||||
|
||||
-- |
||||
-- OUT/INOUT/TABLE functions |
||||
-- |
||||
|
||||
-- infer anymultirange from anymultirange |
||||
create function mr_outparam_succeed(i anymultirange, out r anymultirange, out t text) |
||||
as $$ select $1, 'foo'::text $$ language sql; |
||||
|
||||
select * from mr_outparam_succeed(int4multirange(int4range(1,2))); |
||||
|
||||
-- infer anyarray from anymultirange |
||||
create function mr_outparam_succeed2(i anymultirange, out r anyarray, out t text) |
||||
as $$ select ARRAY[upper($1)], 'foo'::text $$ language sql; |
||||
|
||||
select * from mr_outparam_succeed2(int4multirange(int4range(1,2))); |
||||
|
||||
-- infer anyrange from anymultirange |
||||
create function mr_outparam_succeed3(i anymultirange, out r anyrange, out t text) |
||||
as $$ select range_merge($1), 'foo'::text $$ language sql; |
||||
select * from mr_outparam_succeed3(int4multirange(int4range(1,2))); |
||||
|
||||
-- infer anymultirange from anyrange |
||||
create function mr_outparam_succeed4(i anyrange, out r anymultirange, out t text) |
||||
as $$ select multirange($1), 'foo'::text $$ language sql; |
||||
|
||||
select * from mr_outparam_succeed4(int4range(1,2)); |
||||
|
||||
-- infer anyelement from anymultirange |
||||
create function mr_inoutparam_succeed(out i anyelement, inout r anymultirange) |
||||
as $$ select upper($1), $1 $$ language sql; |
||||
|
||||
select * from mr_inoutparam_succeed(int4multirange(int4range(1,2))); |
||||
|
||||
-- infer anyelement+anymultirange from anyelement+anymultirange |
||||
create function mr_table_succeed(i anyelement, r anymultirange) returns table(i anyelement, r anymultirange) |
||||
as $$ select $1, $2 $$ language sql; |
||||
|
||||
select * from mr_table_succeed(123, int4multirange(int4range(1,11))); |
||||
|
||||
-- use anymultirange in plpgsql |
||||
create function mr_polymorphic(i anyrange) returns anymultirange |
||||
as $$ begin return multirange($1); end; $$ language plpgsql; |
||||
select mr_polymorphic(int4range(1, 4)); |
||||
|
||||
-- should fail |
||||
create function mr_outparam_fail(i anyelement, out r anymultirange, out t text) |
||||
as $$ select '[1,10]', 'foo' $$ language sql; |
||||
|
||||
--should fail |
||||
create function mr_inoutparam_fail(inout i anyelement, out r anymultirange) |
||||
as $$ select $1, '[1,10]' $$ language sql; |
||||
|
||||
--should fail |
||||
create function mr_table_fail(i anyelement) returns table(i anyelement, r anymultirange) |
||||
as $$ select $1, '[1,10]' $$ language sql; |
Loading…
Reference in new issue