Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* multirangetypes.c
|
|
|
|
* I/O functions, operators, and support functions for multirange types.
|
|
|
|
*
|
|
|
|
* The stored (serialized) format of a multirange value is:
|
|
|
|
*
|
|
|
|
* 12 bytes: MultirangeType struct including varlena header, multirange
|
|
|
|
* type's OID and the number of ranges in the multirange.
|
|
|
|
* 4 * (rangesCount - 1) bytes: 32-bit items pointing to the each range
|
|
|
|
* in the multirange starting from
|
|
|
|
* the second one.
|
|
|
|
* 1 * rangesCount bytes : 8-bit flags for each range in the multirange
|
|
|
|
* The rest of the multirange are range bound values pointed by multirange
|
|
|
|
* items.
|
|
|
|
*
|
|
|
|
* Majority of items contain lengths of corresponding range bound values.
|
|
|
|
* Thanks to that items are typically low numbers. This makes multiranges
|
|
|
|
* compression-friendly. Every MULTIRANGE_ITEM_OFFSET_STRIDE item contains
|
|
|
|
* an offset of the corresponding range bound values. That allows fast lookups
|
|
|
|
* for a particular range index. Offsets are counted starting from the end of
|
|
|
|
* flags aligned to the bound type.
|
|
|
|
*
|
2024-01-04 02:49:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/utils/adt/multirangetypes.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/tupmacs.h"
|
|
|
|
#include "common/hashfn.h"
|
2021-07-18 20:07:24 +02:00
|
|
|
#include "funcapi.h"
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
#include "lib/stringinfo.h"
|
|
|
|
#include "libpq/pqformat.h"
|
2024-03-04 12:00:11 +01:00
|
|
|
#include "nodes/nodes.h"
|
2022-02-20 07:22:08 +01:00
|
|
|
#include "port/pg_bitutils.h"
|
2024-03-13 15:07:00 +01:00
|
|
|
#include "utils/array.h"
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/multirangetypes.h"
|
2024-03-13 15:07:00 +01:00
|
|
|
#include "utils/rangetypes.h"
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
/* fn_extra cache entry for one of the range I/O functions */
|
|
|
|
typedef struct MultirangeIOData
|
|
|
|
{
|
|
|
|
TypeCacheEntry *typcache; /* multirange type's typcache entry */
|
|
|
|
FmgrInfo typioproc; /* range type's I/O proc */
|
|
|
|
Oid typioparam; /* range type's I/O parameter */
|
|
|
|
} MultirangeIOData;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
MULTIRANGE_BEFORE_RANGE,
|
|
|
|
MULTIRANGE_IN_RANGE,
|
|
|
|
MULTIRANGE_IN_RANGE_ESCAPED,
|
|
|
|
MULTIRANGE_IN_RANGE_QUOTED,
|
|
|
|
MULTIRANGE_IN_RANGE_QUOTED_ESCAPED,
|
|
|
|
MULTIRANGE_AFTER_RANGE,
|
|
|
|
MULTIRANGE_FINISHED,
|
|
|
|
} MultirangeParseState;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Macros for accessing past MultirangeType parts of multirange: items, flags
|
|
|
|
* and boundaries.
|
|
|
|
*/
|
|
|
|
#define MultirangeGetItemsPtr(mr) ((uint32 *) ((Pointer) (mr) + \
|
|
|
|
sizeof(MultirangeType)))
|
|
|
|
#define MultirangeGetFlagsPtr(mr) ((uint8 *) ((Pointer) (mr) + \
|
|
|
|
sizeof(MultirangeType) + ((mr)->rangeCount - 1) * sizeof(uint32)))
|
|
|
|
#define MultirangeGetBoundariesPtr(mr, align) ((Pointer) (mr) + \
|
|
|
|
att_align_nominal(sizeof(MultirangeType) + \
|
|
|
|
((mr)->rangeCount - 1) * sizeof(uint32) + \
|
|
|
|
(mr)->rangeCount * sizeof(uint8), (align)))
|
|
|
|
|
|
|
|
#define MULTIRANGE_ITEM_OFF_BIT 0x80000000
|
|
|
|
#define MULTIRANGE_ITEM_GET_OFFLEN(item) ((item) & 0x7FFFFFFF)
|
|
|
|
#define MULTIRANGE_ITEM_HAS_OFF(item) ((item) & MULTIRANGE_ITEM_OFF_BIT)
|
|
|
|
#define MULTIRANGE_ITEM_OFFSET_STRIDE 4
|
|
|
|
|
|
|
|
typedef int (*multirange_bsearch_comparison) (TypeCacheEntry *typcache,
|
|
|
|
RangeBound *lower,
|
|
|
|
RangeBound *upper,
|
|
|
|
void *key,
|
|
|
|
bool *match);
|
|
|
|
|
|
|
|
static MultirangeIOData *get_multirange_io_data(FunctionCallInfo fcinfo,
|
|
|
|
Oid mltrngtypid,
|
|
|
|
IOFuncSelector func);
|
|
|
|
static int32 multirange_canonicalize(TypeCacheEntry *rangetyp,
|
|
|
|
int32 input_range_count,
|
|
|
|
RangeType **ranges);
|
|
|
|
|
|
|
|
/*
|
|
|
|
*----------------------------------------------------------
|
|
|
|
* I/O FUNCTIONS
|
|
|
|
*----------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Converts string to multirange.
|
|
|
|
*
|
|
|
|
* We expect curly brackets to bound the list, with zero or more ranges
|
|
|
|
* separated by commas. We accept whitespace anywhere: before/after our
|
|
|
|
* brackets and around the commas. Ranges can be the empty literal or some
|
|
|
|
* stuff inside parens/brackets. Mostly we delegate parsing the individual
|
|
|
|
* range contents to range_in, but we have to detect quoting and
|
|
|
|
* backslash-escaping which can happen for range bounds. Backslashes can
|
|
|
|
* escape something inside or outside a quoted string, and a quoted string
|
|
|
|
* can escape quote marks with either backslashes or double double-quotes.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
multirange_in(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *input_str = PG_GETARG_CSTRING(0);
|
|
|
|
Oid mltrngtypoid = PG_GETARG_OID(1);
|
|
|
|
Oid typmod = PG_GETARG_INT32(2);
|
2022-12-15 18:18:36 +01:00
|
|
|
Node *escontext = fcinfo->context;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
TypeCacheEntry *rangetyp;
|
|
|
|
int32 ranges_seen = 0;
|
|
|
|
int32 range_count = 0;
|
|
|
|
int32 range_capacity = 8;
|
|
|
|
RangeType *range;
|
|
|
|
RangeType **ranges = palloc(range_capacity * sizeof(RangeType *));
|
|
|
|
MultirangeIOData *cache;
|
|
|
|
MultirangeType *ret;
|
|
|
|
MultirangeParseState parse_state;
|
|
|
|
const char *ptr = input_str;
|
2020-12-30 19:11:31 +01:00
|
|
|
const char *range_str_begin = NULL;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
int32 range_str_len;
|
2020-12-30 19:11:31 +01:00
|
|
|
char *range_str;
|
2022-12-15 18:18:36 +01:00
|
|
|
Datum range_datum;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_input);
|
|
|
|
rangetyp = cache->typcache->rngtype;
|
|
|
|
|
|
|
|
/* consume whitespace */
|
|
|
|
while (*ptr != '\0' && isspace((unsigned char) *ptr))
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr == '{')
|
|
|
|
ptr++;
|
|
|
|
else
|
2022-12-15 18:18:36 +01:00
|
|
|
ereturn(escontext, (Datum) 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("malformed multirange literal: \"%s\"",
|
|
|
|
input_str),
|
2021-05-31 04:35:00 +02:00
|
|
|
errdetail("Missing left brace.")));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
/* consume ranges */
|
|
|
|
parse_state = MULTIRANGE_BEFORE_RANGE;
|
|
|
|
for (; parse_state != MULTIRANGE_FINISHED; ptr++)
|
|
|
|
{
|
|
|
|
char ch = *ptr;
|
|
|
|
|
|
|
|
if (ch == '\0')
|
2022-12-15 18:18:36 +01:00
|
|
|
ereturn(escontext, (Datum) 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("malformed multirange literal: \"%s\"",
|
|
|
|
input_str),
|
|
|
|
errdetail("Unexpected end of input.")));
|
|
|
|
|
|
|
|
/* skip whitespace */
|
|
|
|
if (isspace((unsigned char) ch))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (parse_state)
|
|
|
|
{
|
|
|
|
case MULTIRANGE_BEFORE_RANGE:
|
|
|
|
if (ch == '[' || ch == '(')
|
|
|
|
{
|
2020-12-30 19:11:31 +01:00
|
|
|
range_str_begin = ptr;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
parse_state = MULTIRANGE_IN_RANGE;
|
|
|
|
}
|
|
|
|
else if (ch == '}' && ranges_seen == 0)
|
|
|
|
parse_state = MULTIRANGE_FINISHED;
|
|
|
|
else if (pg_strncasecmp(ptr, RANGE_EMPTY_LITERAL,
|
|
|
|
strlen(RANGE_EMPTY_LITERAL)) == 0)
|
|
|
|
{
|
|
|
|
ranges_seen++;
|
|
|
|
/* nothing to do with an empty range */
|
|
|
|
ptr += strlen(RANGE_EMPTY_LITERAL) - 1;
|
|
|
|
parse_state = MULTIRANGE_AFTER_RANGE;
|
|
|
|
}
|
|
|
|
else
|
2022-12-15 18:18:36 +01:00
|
|
|
ereturn(escontext, (Datum) 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("malformed multirange literal: \"%s\"",
|
|
|
|
input_str),
|
|
|
|
errdetail("Expected range start.")));
|
|
|
|
break;
|
|
|
|
case MULTIRANGE_IN_RANGE:
|
2020-12-30 19:11:31 +01:00
|
|
|
if (ch == ']' || ch == ')')
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
2020-12-30 19:11:31 +01:00
|
|
|
range_str_len = ptr - range_str_begin + 1;
|
|
|
|
range_str = pnstrdup(range_str_begin, range_str_len);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
if (range_capacity == range_count)
|
|
|
|
{
|
|
|
|
range_capacity *= 2;
|
|
|
|
ranges = (RangeType **)
|
|
|
|
repalloc(ranges, range_capacity * sizeof(RangeType *));
|
|
|
|
}
|
|
|
|
ranges_seen++;
|
2022-12-15 18:18:36 +01:00
|
|
|
if (!InputFunctionCallSafe(&cache->typioproc,
|
|
|
|
range_str,
|
|
|
|
cache->typioparam,
|
|
|
|
typmod,
|
|
|
|
escontext,
|
|
|
|
&range_datum))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
range = DatumGetRangeTypeP(range_datum);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
if (!RangeIsEmpty(range))
|
|
|
|
ranges[range_count++] = range;
|
|
|
|
parse_state = MULTIRANGE_AFTER_RANGE;
|
|
|
|
}
|
|
|
|
else
|
2020-12-30 19:11:31 +01:00
|
|
|
{
|
|
|
|
if (ch == '"')
|
|
|
|
parse_state = MULTIRANGE_IN_RANGE_QUOTED;
|
|
|
|
else if (ch == '\\')
|
|
|
|
parse_state = MULTIRANGE_IN_RANGE_ESCAPED;
|
2021-04-23 11:57:33 +02:00
|
|
|
|
2020-12-30 19:11:31 +01:00
|
|
|
/*
|
|
|
|
* We will include this character into range_str once we
|
|
|
|
* find the end of the range value.
|
|
|
|
*/
|
|
|
|
}
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
break;
|
|
|
|
case MULTIRANGE_IN_RANGE_ESCAPED:
|
2021-04-23 11:57:33 +02:00
|
|
|
|
2020-12-30 19:11:31 +01:00
|
|
|
/*
|
|
|
|
* We will include this character into range_str once we find
|
|
|
|
* the end of the range value.
|
|
|
|
*/
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
parse_state = MULTIRANGE_IN_RANGE;
|
|
|
|
break;
|
|
|
|
case MULTIRANGE_IN_RANGE_QUOTED:
|
|
|
|
if (ch == '"')
|
|
|
|
if (*(ptr + 1) == '"')
|
|
|
|
{
|
|
|
|
/* two quote marks means an escaped quote mark */
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
parse_state = MULTIRANGE_IN_RANGE;
|
|
|
|
else if (ch == '\\')
|
|
|
|
parse_state = MULTIRANGE_IN_RANGE_QUOTED_ESCAPED;
|
2020-12-30 19:11:31 +01:00
|
|
|
|
|
|
|
/*
|
2021-04-23 11:57:33 +02:00
|
|
|
* We will include this character into range_str once we find
|
|
|
|
* the end of the range value.
|
2020-12-30 19:11:31 +01:00
|
|
|
*/
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
break;
|
|
|
|
case MULTIRANGE_AFTER_RANGE:
|
|
|
|
if (ch == ',')
|
|
|
|
parse_state = MULTIRANGE_BEFORE_RANGE;
|
|
|
|
else if (ch == '}')
|
|
|
|
parse_state = MULTIRANGE_FINISHED;
|
|
|
|
else
|
2022-12-15 18:18:36 +01:00
|
|
|
ereturn(escontext, (Datum) 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("malformed multirange literal: \"%s\"",
|
|
|
|
input_str),
|
|
|
|
errdetail("Expected comma or end of multirange.")));
|
|
|
|
break;
|
|
|
|
case MULTIRANGE_IN_RANGE_QUOTED_ESCAPED:
|
2021-04-23 11:57:33 +02:00
|
|
|
|
2020-12-30 19:11:31 +01:00
|
|
|
/*
|
|
|
|
* We will include this character into range_str once we find
|
|
|
|
* the end of the range value.
|
|
|
|
*/
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
parse_state = MULTIRANGE_IN_RANGE_QUOTED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unknown parse state: %d", parse_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* consume whitespace */
|
|
|
|
while (*ptr != '\0' && isspace((unsigned char) *ptr))
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (*ptr != '\0')
|
2022-12-15 18:18:36 +01:00
|
|
|
ereturn(escontext, (Datum) 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("malformed multirange literal: \"%s\"",
|
|
|
|
input_str),
|
2021-06-28 08:36:44 +02:00
|
|
|
errdetail("Junk after closing right brace.")));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
ret = make_multirange(mltrngtypoid, rangetyp, range_count, ranges);
|
|
|
|
PG_RETURN_MULTIRANGE_P(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_out(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *multirange = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
Oid mltrngtypoid = MultirangeTypeGetOid(multirange);
|
|
|
|
MultirangeIOData *cache;
|
|
|
|
StringInfoData buf;
|
|
|
|
RangeType *range;
|
|
|
|
char *rangeStr;
|
|
|
|
int32 range_count;
|
|
|
|
int32 i;
|
|
|
|
RangeType **ranges;
|
|
|
|
|
|
|
|
cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_output);
|
|
|
|
|
|
|
|
initStringInfo(&buf);
|
|
|
|
|
|
|
|
appendStringInfoChar(&buf, '{');
|
|
|
|
|
|
|
|
multirange_deserialize(cache->typcache->rngtype, multirange, &range_count, &ranges);
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
if (i > 0)
|
|
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
range = ranges[i];
|
|
|
|
rangeStr = OutputFunctionCall(&cache->typioproc, RangeTypePGetDatum(range));
|
|
|
|
appendStringInfoString(&buf, rangeStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
appendStringInfoChar(&buf, '}');
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(buf.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Binary representation: First a int32-sized count of ranges, followed by
|
|
|
|
* ranges in their native binary representation.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
multirange_recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
Oid mltrngtypoid = PG_GETARG_OID(1);
|
|
|
|
int32 typmod = PG_GETARG_INT32(2);
|
|
|
|
MultirangeIOData *cache;
|
|
|
|
uint32 range_count;
|
|
|
|
RangeType **ranges;
|
|
|
|
MultirangeType *ret;
|
|
|
|
StringInfoData tmpbuf;
|
|
|
|
|
|
|
|
cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_receive);
|
|
|
|
|
|
|
|
range_count = pq_getmsgint(buf, 4);
|
|
|
|
ranges = palloc(range_count * sizeof(RangeType *));
|
|
|
|
|
|
|
|
initStringInfo(&tmpbuf);
|
|
|
|
for (int i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
uint32 range_len = pq_getmsgint(buf, 4);
|
|
|
|
const char *range_data = pq_getmsgbytes(buf, range_len);
|
|
|
|
|
|
|
|
resetStringInfo(&tmpbuf);
|
|
|
|
appendBinaryStringInfo(&tmpbuf, range_data, range_len);
|
|
|
|
|
|
|
|
ranges[i] = DatumGetRangeTypeP(ReceiveFunctionCall(&cache->typioproc,
|
|
|
|
&tmpbuf,
|
|
|
|
cache->typioparam,
|
|
|
|
typmod));
|
|
|
|
}
|
|
|
|
pfree(tmpbuf.data);
|
|
|
|
|
|
|
|
pq_getmsgend(buf);
|
|
|
|
|
|
|
|
ret = make_multirange(mltrngtypoid, cache->typcache->rngtype,
|
|
|
|
range_count, ranges);
|
|
|
|
PG_RETURN_MULTIRANGE_P(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *multirange = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
Oid mltrngtypoid = MultirangeTypeGetOid(multirange);
|
|
|
|
StringInfo buf = makeStringInfo();
|
|
|
|
RangeType **ranges;
|
|
|
|
int32 range_count;
|
|
|
|
MultirangeIOData *cache;
|
|
|
|
|
|
|
|
cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_send);
|
|
|
|
|
|
|
|
/* construct output */
|
|
|
|
pq_begintypsend(buf);
|
|
|
|
|
|
|
|
pq_sendint32(buf, multirange->rangeCount);
|
|
|
|
|
|
|
|
multirange_deserialize(cache->typcache->rngtype, multirange, &range_count, &ranges);
|
|
|
|
for (int i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
Datum range;
|
|
|
|
|
|
|
|
range = RangeTypePGetDatum(ranges[i]);
|
|
|
|
range = PointerGetDatum(SendFunctionCall(&cache->typioproc, range));
|
|
|
|
|
|
|
|
pq_sendint32(buf, VARSIZE(range) - VARHDRSZ);
|
|
|
|
pq_sendbytes(buf, VARDATA(range), VARSIZE(range) - VARHDRSZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_multirange_io_data: get cached information needed for multirange type I/O
|
|
|
|
*
|
|
|
|
* The multirange I/O functions need a bit more cached info than other multirange
|
|
|
|
* functions, so they store a MultirangeIOData struct in fn_extra, not just a
|
|
|
|
* pointer to a type cache entry.
|
|
|
|
*/
|
|
|
|
static MultirangeIOData *
|
|
|
|
get_multirange_io_data(FunctionCallInfo fcinfo, Oid mltrngtypid, IOFuncSelector func)
|
|
|
|
{
|
|
|
|
MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
|
|
|
|
|
|
|
|
if (cache == NULL || cache->typcache->type_id != mltrngtypid)
|
|
|
|
{
|
|
|
|
Oid typiofunc;
|
|
|
|
int16 typlen;
|
|
|
|
bool typbyval;
|
|
|
|
char typalign;
|
|
|
|
char typdelim;
|
|
|
|
|
|
|
|
cache = (MultirangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
|
|
|
|
sizeof(MultirangeIOData));
|
|
|
|
cache->typcache = lookup_type_cache(mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
|
|
|
|
if (cache->typcache->rngtype == NULL)
|
|
|
|
elog(ERROR, "type %u is not a multirange type", mltrngtypid);
|
|
|
|
|
|
|
|
/* get_type_io_data does more than we need, but is convenient */
|
|
|
|
get_type_io_data(cache->typcache->rngtype->type_id,
|
|
|
|
func,
|
|
|
|
&typlen,
|
|
|
|
&typbyval,
|
|
|
|
&typalign,
|
|
|
|
&typdelim,
|
|
|
|
&cache->typioparam,
|
|
|
|
&typiofunc);
|
|
|
|
|
|
|
|
if (!OidIsValid(typiofunc))
|
|
|
|
{
|
|
|
|
/* this could only happen for receive or send */
|
|
|
|
if (func == IOFunc_receive)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("no binary input function available for type %s",
|
|
|
|
format_type_be(cache->typcache->rngtype->type_id))));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("no binary output function available for type %s",
|
|
|
|
format_type_be(cache->typcache->rngtype->type_id))));
|
|
|
|
}
|
|
|
|
fmgr_info_cxt(typiofunc, &cache->typioproc,
|
|
|
|
fcinfo->flinfo->fn_mcxt);
|
|
|
|
|
|
|
|
fcinfo->flinfo->fn_extra = (void *) cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Converts a list of arbitrary ranges into a list that is sorted and merged.
|
|
|
|
* Changes the contents of `ranges`.
|
|
|
|
*
|
|
|
|
* Returns the number of slots actually used, which may be less than
|
|
|
|
* input_range_count but never more.
|
|
|
|
*
|
|
|
|
* We assume that no input ranges are null, but empties are okay.
|
|
|
|
*/
|
|
|
|
static int32
|
|
|
|
multirange_canonicalize(TypeCacheEntry *rangetyp, int32 input_range_count,
|
|
|
|
RangeType **ranges)
|
|
|
|
{
|
|
|
|
RangeType *lastRange = NULL;
|
|
|
|
RangeType *currentRange;
|
|
|
|
int32 i;
|
|
|
|
int32 output_range_count = 0;
|
|
|
|
|
|
|
|
/* Sort the ranges so we can find the ones that overlap/meet. */
|
|
|
|
qsort_arg(ranges, input_range_count, sizeof(RangeType *), range_compare,
|
|
|
|
rangetyp);
|
|
|
|
|
|
|
|
/* Now merge where possible: */
|
|
|
|
for (i = 0; i < input_range_count; i++)
|
|
|
|
{
|
|
|
|
currentRange = ranges[i];
|
|
|
|
if (RangeIsEmpty(currentRange))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (lastRange == NULL)
|
|
|
|
{
|
|
|
|
ranges[output_range_count++] = lastRange = currentRange;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* range_adjacent_internal gives true if *either* A meets B or B meets
|
|
|
|
* A, which is not quite want we want, but we rely on the sorting
|
|
|
|
* above to rule out B meets A ever happening.
|
|
|
|
*/
|
|
|
|
if (range_adjacent_internal(rangetyp, lastRange, currentRange))
|
|
|
|
{
|
|
|
|
/* The two ranges touch (without overlap), so merge them: */
|
|
|
|
ranges[output_range_count - 1] = lastRange =
|
|
|
|
range_union_internal(rangetyp, lastRange, currentRange, false);
|
|
|
|
}
|
|
|
|
else if (range_before_internal(rangetyp, lastRange, currentRange))
|
|
|
|
{
|
|
|
|
/* There's a gap, so make a new entry: */
|
|
|
|
lastRange = ranges[output_range_count] = currentRange;
|
|
|
|
output_range_count++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* They must overlap, so merge them: */
|
|
|
|
ranges[output_range_count - 1] = lastRange =
|
|
|
|
range_union_internal(rangetyp, lastRange, currentRange, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output_range_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*----------------------------------------------------------
|
|
|
|
* SUPPORT FUNCTIONS
|
|
|
|
*
|
|
|
|
* These functions aren't in pg_proc, but are useful for
|
|
|
|
* defining new generic multirange functions in C.
|
|
|
|
*----------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* multirange_get_typcache: get cached information about a multirange type
|
|
|
|
*
|
|
|
|
* This is for use by multirange-related functions that follow the convention
|
|
|
|
* of using the fn_extra field as a pointer to the type cache entry for
|
|
|
|
* the multirange type. Functions that need to cache more information than
|
|
|
|
* that must fend for themselves.
|
|
|
|
*/
|
|
|
|
TypeCacheEntry *
|
|
|
|
multirange_get_typcache(FunctionCallInfo fcinfo, Oid mltrngtypid)
|
|
|
|
{
|
|
|
|
TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
|
|
|
|
|
|
|
if (typcache == NULL ||
|
|
|
|
typcache->type_id != mltrngtypid)
|
|
|
|
{
|
|
|
|
typcache = lookup_type_cache(mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
|
|
|
|
if (typcache->rngtype == NULL)
|
|
|
|
elog(ERROR, "type %u is not a multirange type", mltrngtypid);
|
|
|
|
fcinfo->flinfo->fn_extra = (void *) typcache;
|
|
|
|
}
|
|
|
|
|
|
|
|
return typcache;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2021-04-19 04:32:30 +02:00
|
|
|
* Estimate size occupied by serialized multirange.
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
*/
|
|
|
|
static Size
|
|
|
|
multirange_size_estimate(TypeCacheEntry *rangetyp, int32 range_count,
|
|
|
|
RangeType **ranges)
|
|
|
|
{
|
|
|
|
char elemalign = rangetyp->rngelemtype->typalign;
|
|
|
|
Size size;
|
|
|
|
int32 i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Count space for MultirangeType struct, items and flags.
|
|
|
|
*/
|
|
|
|
size = att_align_nominal(sizeof(MultirangeType) +
|
|
|
|
Max(range_count - 1, 0) * sizeof(uint32) +
|
|
|
|
range_count * sizeof(uint8), elemalign);
|
|
|
|
|
|
|
|
/* Count space for range bounds */
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
size += att_align_nominal(VARSIZE(ranges[i]) -
|
|
|
|
sizeof(RangeType) -
|
|
|
|
sizeof(char), elemalign);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write multirange data into pre-allocated space.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
write_multirange_data(MultirangeType *multirange, TypeCacheEntry *rangetyp,
|
|
|
|
int32 range_count, RangeType **ranges)
|
|
|
|
{
|
|
|
|
uint32 *items;
|
|
|
|
uint32 prev_offset = 0;
|
|
|
|
uint8 *flags;
|
|
|
|
int32 i;
|
|
|
|
Pointer begin,
|
|
|
|
ptr;
|
|
|
|
char elemalign = rangetyp->rngelemtype->typalign;
|
|
|
|
|
|
|
|
items = MultirangeGetItemsPtr(multirange);
|
|
|
|
flags = MultirangeGetFlagsPtr(multirange);
|
|
|
|
ptr = begin = MultirangeGetBoundariesPtr(multirange, elemalign);
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
uint32 len;
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Every range, except the first one, has an item. Every
|
|
|
|
* MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
|
|
|
|
* contain lengths.
|
|
|
|
*/
|
|
|
|
items[i - 1] = ptr - begin;
|
|
|
|
if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
|
|
|
|
items[i - 1] -= prev_offset;
|
|
|
|
else
|
|
|
|
items[i - 1] |= MULTIRANGE_ITEM_OFF_BIT;
|
|
|
|
prev_offset = ptr - begin;
|
|
|
|
}
|
|
|
|
flags[i] = *((Pointer) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
|
|
|
|
len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
|
|
|
|
memcpy(ptr, (Pointer) (ranges[i] + 1), len);
|
|
|
|
ptr += att_align_nominal(len, elemalign);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This serializes the multirange from a list of non-null ranges. It also
|
|
|
|
* sorts the ranges and merges any that touch. The ranges should already be
|
|
|
|
* detoasted, and there should be no NULLs. This should be used by most
|
|
|
|
* callers.
|
|
|
|
*
|
|
|
|
* Note that we may change the `ranges` parameter (the pointers, but not
|
|
|
|
* any already-existing RangeType contents).
|
|
|
|
*/
|
|
|
|
MultirangeType *
|
|
|
|
make_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count,
|
|
|
|
RangeType **ranges)
|
|
|
|
{
|
|
|
|
MultirangeType *multirange;
|
|
|
|
Size size;
|
|
|
|
|
|
|
|
/* Sort and merge input ranges. */
|
|
|
|
range_count = multirange_canonicalize(rangetyp, range_count, ranges);
|
|
|
|
|
|
|
|
/* Note: zero-fill is required here, just as in heap tuples */
|
|
|
|
size = multirange_size_estimate(rangetyp, range_count, ranges);
|
|
|
|
multirange = palloc0(size);
|
|
|
|
SET_VARSIZE(multirange, size);
|
|
|
|
|
|
|
|
/* Now fill in the datum */
|
|
|
|
multirange->multirangetypid = mltrngtypoid;
|
|
|
|
multirange->rangeCount = range_count;
|
|
|
|
|
|
|
|
write_multirange_data(multirange, rangetyp, range_count, ranges);
|
|
|
|
|
|
|
|
return multirange;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get offset of bounds values of the i'th range in the multirange.
|
|
|
|
*/
|
|
|
|
static uint32
|
|
|
|
multirange_get_bounds_offset(const MultirangeType *multirange, int32 i)
|
|
|
|
{
|
|
|
|
uint32 *items = MultirangeGetItemsPtr(multirange);
|
|
|
|
uint32 offset = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Summarize lengths till we meet an offset.
|
|
|
|
*/
|
|
|
|
while (i > 0)
|
|
|
|
{
|
|
|
|
offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
|
|
|
|
if (MULTIRANGE_ITEM_HAS_OFF(items[i - 1]))
|
|
|
|
break;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch the i'th range from the multirange.
|
|
|
|
*/
|
|
|
|
RangeType *
|
|
|
|
multirange_get_range(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *multirange, int i)
|
|
|
|
{
|
|
|
|
uint32 offset;
|
|
|
|
uint8 flags;
|
|
|
|
Pointer begin,
|
|
|
|
ptr;
|
|
|
|
int16 typlen = rangetyp->rngelemtype->typlen;
|
|
|
|
char typalign = rangetyp->rngelemtype->typalign;
|
|
|
|
uint32 len;
|
|
|
|
RangeType *range;
|
|
|
|
|
|
|
|
Assert(i < multirange->rangeCount);
|
|
|
|
|
|
|
|
offset = multirange_get_bounds_offset(multirange, i);
|
|
|
|
flags = MultirangeGetFlagsPtr(multirange)[i];
|
|
|
|
ptr = begin = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the size of bound values. In principle, we could get offset
|
|
|
|
* of the next range bound values and calculate accordingly. But range
|
|
|
|
* bound values are aligned, so we have to walk the values to get the
|
|
|
|
* exact size.
|
|
|
|
*/
|
|
|
|
if (RANGE_HAS_LBOUND(flags))
|
|
|
|
ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
|
|
|
|
if (RANGE_HAS_UBOUND(flags))
|
2021-12-13 15:17:33 +01:00
|
|
|
{
|
|
|
|
ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
|
2021-12-13 15:17:33 +01:00
|
|
|
}
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
|
|
|
|
|
|
|
|
range = palloc0(len);
|
|
|
|
SET_VARSIZE(range, len);
|
|
|
|
range->rangetypid = rangetyp->type_id;
|
|
|
|
|
|
|
|
memcpy(range + 1, begin, ptr - begin);
|
|
|
|
*((uint8 *) (range + 1) + (ptr - begin)) = flags;
|
|
|
|
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch bounds from the i'th range of the multirange. This is the shortcut for
|
|
|
|
* doing the same thing as multirange_get_range() + range_deserialize(), but
|
|
|
|
* performing fewer operations.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
multirange_get_bounds(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *multirange,
|
|
|
|
uint32 i, RangeBound *lower, RangeBound *upper)
|
|
|
|
{
|
|
|
|
uint32 offset;
|
|
|
|
uint8 flags;
|
|
|
|
Pointer ptr;
|
|
|
|
int16 typlen = rangetyp->rngelemtype->typlen;
|
|
|
|
char typalign = rangetyp->rngelemtype->typalign;
|
|
|
|
bool typbyval = rangetyp->rngelemtype->typbyval;
|
|
|
|
Datum lbound;
|
|
|
|
Datum ubound;
|
|
|
|
|
|
|
|
Assert(i < multirange->rangeCount);
|
|
|
|
|
|
|
|
offset = multirange_get_bounds_offset(multirange, i);
|
|
|
|
flags = MultirangeGetFlagsPtr(multirange)[i];
|
|
|
|
ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
|
|
|
|
|
|
|
|
/* multirange can't contain empty ranges */
|
|
|
|
Assert((flags & RANGE_EMPTY) == 0);
|
|
|
|
|
|
|
|
/* fetch lower bound, if any */
|
|
|
|
if (RANGE_HAS_LBOUND(flags))
|
|
|
|
{
|
|
|
|
/* att_align_pointer cannot be necessary here */
|
|
|
|
lbound = fetch_att(ptr, typbyval, typlen);
|
|
|
|
ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lbound = (Datum) 0;
|
|
|
|
|
|
|
|
/* fetch upper bound, if any */
|
|
|
|
if (RANGE_HAS_UBOUND(flags))
|
|
|
|
{
|
|
|
|
ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
|
|
|
|
ubound = fetch_att(ptr, typbyval, typlen);
|
|
|
|
/* no need for att_addlength_pointer */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ubound = (Datum) 0;
|
|
|
|
|
|
|
|
/* emit results */
|
|
|
|
lower->val = lbound;
|
|
|
|
lower->infinite = (flags & RANGE_LB_INF) != 0;
|
|
|
|
lower->inclusive = (flags & RANGE_LB_INC) != 0;
|
|
|
|
lower->lower = true;
|
|
|
|
|
|
|
|
upper->val = ubound;
|
|
|
|
upper->infinite = (flags & RANGE_UB_INF) != 0;
|
|
|
|
upper->inclusive = (flags & RANGE_UB_INC) != 0;
|
|
|
|
upper->lower = false;
|
|
|
|
}
|
|
|
|
|
2020-12-29 21:36:43 +01:00
|
|
|
/*
|
|
|
|
* Construct union range from the multirange.
|
|
|
|
*/
|
|
|
|
RangeType *
|
|
|
|
multirange_get_union_range(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr)
|
|
|
|
{
|
|
|
|
RangeBound lower,
|
|
|
|
upper,
|
|
|
|
tmp;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
return make_empty_range(rangetyp);
|
|
|
|
|
|
|
|
multirange_get_bounds(rangetyp, mr, 0, &lower, &tmp);
|
|
|
|
multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
|
|
|
|
|
2022-12-15 18:18:36 +01:00
|
|
|
return make_range(rangetyp, &lower, &upper, false, NULL);
|
2020-12-29 21:36:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
/*
|
|
|
|
* multirange_deserialize: deconstruct a multirange value
|
|
|
|
*
|
|
|
|
* NB: the given multirange object must be fully detoasted; it cannot have a
|
|
|
|
* short varlena header.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
multirange_deserialize(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *multirange, int32 *range_count,
|
|
|
|
RangeType ***ranges)
|
|
|
|
{
|
|
|
|
*range_count = multirange->rangeCount;
|
|
|
|
|
|
|
|
/* Convert each ShortRangeType into a RangeType */
|
|
|
|
if (*range_count > 0)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*ranges = palloc(*range_count * sizeof(RangeType *));
|
|
|
|
for (i = 0; i < *range_count; i++)
|
|
|
|
(*ranges)[i] = multirange_get_range(rangetyp, multirange, i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ranges = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MultirangeType *
|
|
|
|
make_empty_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp)
|
|
|
|
{
|
|
|
|
return make_multirange(mltrngtypoid, rangetyp, 0, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Similar to range_overlaps_internal(), but takes range bounds instead of
|
|
|
|
* ranges as arguments.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
range_bounds_overlaps(TypeCacheEntry *typcache,
|
|
|
|
RangeBound *lower1, RangeBound *upper1,
|
|
|
|
RangeBound *lower2, RangeBound *upper2)
|
|
|
|
{
|
|
|
|
if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
|
|
|
|
range_cmp_bounds(typcache, lower1, upper2) <= 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
|
|
|
|
range_cmp_bounds(typcache, lower2, upper1) <= 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Similar to range_contains_internal(), but takes range bounds instead of
|
|
|
|
* ranges as arguments.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
range_bounds_contains(TypeCacheEntry *typcache,
|
|
|
|
RangeBound *lower1, RangeBound *upper1,
|
|
|
|
RangeBound *lower2, RangeBound *upper2)
|
|
|
|
{
|
|
|
|
if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
|
|
|
|
range_cmp_bounds(typcache, upper1, upper2) >= 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the given key matches any range in multirange using binary search.
|
|
|
|
* If the required range isn't found, that counts as a mismatch. When the
|
|
|
|
* required range is found, the comparison function can still report this as
|
|
|
|
* either match or mismatch. For instance, if we search for containment, we can
|
|
|
|
* found a range, which is overlapping but not containing the key range, and
|
|
|
|
* that would count as a mismatch.
|
|
|
|
*/
|
|
|
|
static bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_bsearch_match(TypeCacheEntry *typcache, const MultirangeType *mr,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
void *key, multirange_bsearch_comparison cmp_func)
|
|
|
|
{
|
|
|
|
uint32 l,
|
|
|
|
u,
|
|
|
|
idx;
|
|
|
|
int comparison;
|
|
|
|
bool match = false;
|
|
|
|
|
|
|
|
l = 0;
|
|
|
|
u = mr->rangeCount;
|
|
|
|
while (l < u)
|
|
|
|
{
|
|
|
|
RangeBound lower,
|
|
|
|
upper;
|
|
|
|
|
|
|
|
idx = (l + u) / 2;
|
|
|
|
multirange_get_bounds(typcache, mr, idx, &lower, &upper);
|
|
|
|
comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
|
|
|
|
|
|
|
|
if (comparison < 0)
|
|
|
|
u = idx;
|
|
|
|
else if (comparison > 0)
|
|
|
|
l = idx + 1;
|
|
|
|
else
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*----------------------------------------------------------
|
|
|
|
* GENERIC FUNCTIONS
|
|
|
|
*----------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct multirange value from zero or more ranges. Since this is a
|
|
|
|
* variadic function we get passed an array. The array must contain ranges
|
|
|
|
* that match our return value, and there must be no NULLs.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
multirange_constructor2(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
|
|
|
|
Oid rngtypid;
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
TypeCacheEntry *rangetyp;
|
|
|
|
ArrayType *rangeArray;
|
|
|
|
int range_count;
|
|
|
|
Datum *elements;
|
|
|
|
bool *nulls;
|
|
|
|
RangeType **ranges;
|
|
|
|
int dims;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypid);
|
|
|
|
rangetyp = typcache->rngtype;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A no-arg invocation should call multirange_constructor0 instead, but
|
|
|
|
* returning an empty range is what that does.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (PG_NARGS() == 0)
|
|
|
|
PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL));
|
|
|
|
|
|
|
|
/*
|
2021-04-23 11:57:33 +02:00
|
|
|
* This check should be guaranteed by our signature, but let's do it just
|
|
|
|
* in case.
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (PG_ARGISNULL(0))
|
2021-04-23 11:57:33 +02:00
|
|
|
elog(ERROR,
|
2021-09-16 14:48:52 +02:00
|
|
|
"multirange values cannot contain null members");
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
rangeArray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
|
|
|
|
dims = ARR_NDIM(rangeArray);
|
|
|
|
if (dims > 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_CARDINALITY_VIOLATION),
|
2021-06-28 08:36:44 +02:00
|
|
|
errmsg("multiranges cannot be constructed from multidimensional arrays")));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
rngtypid = ARR_ELEMTYPE(rangeArray);
|
|
|
|
if (rngtypid != rangetyp->type_id)
|
2021-09-16 14:48:52 +02:00
|
|
|
elog(ERROR, "type %u does not match constructor type", rngtypid);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Be careful: we can still be called with zero ranges, like this:
|
|
|
|
* `int4multirange(variadic '{}'::int4range[])
|
|
|
|
*/
|
|
|
|
if (dims == 0)
|
|
|
|
{
|
|
|
|
range_count = 0;
|
|
|
|
ranges = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
deconstruct_array(rangeArray, rngtypid, rangetyp->typlen, rangetyp->typbyval,
|
|
|
|
rangetyp->typalign, &elements, &nulls, &range_count);
|
|
|
|
|
|
|
|
ranges = palloc0(range_count * sizeof(RangeType *));
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
if (nulls[i])
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2021-09-16 14:48:52 +02:00
|
|
|
errmsg("multirange values cannot contain null members")));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
/* make_multirange will do its own copy */
|
|
|
|
ranges[i] = DatumGetRangeTypeP(elements[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, range_count, ranges));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct multirange value from a single range. It'd be nice if we could
|
|
|
|
* just use multirange_constructor2 for this case, but we need a non-variadic
|
|
|
|
* single-arg function to let us define a CAST from a range to its multirange.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
multirange_constructor1(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
|
|
|
|
Oid rngtypid;
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
TypeCacheEntry *rangetyp;
|
|
|
|
RangeType *range;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypid);
|
|
|
|
rangetyp = typcache->rngtype;
|
|
|
|
|
|
|
|
/*
|
2021-04-23 11:57:33 +02:00
|
|
|
* This check should be guaranteed by our signature, but let's do it just
|
|
|
|
* in case.
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (PG_ARGISNULL(0))
|
2021-04-23 11:57:33 +02:00
|
|
|
elog(ERROR,
|
2021-09-16 14:48:52 +02:00
|
|
|
"multirange values cannot contain null members");
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
range = PG_GETARG_RANGE_P(0);
|
|
|
|
|
|
|
|
/* Make sure the range type matches. */
|
|
|
|
rngtypid = RangeTypeGetOid(range);
|
|
|
|
if (rngtypid != rangetyp->type_id)
|
2021-09-16 14:48:52 +02:00
|
|
|
elog(ERROR, "type %u does not match constructor type", rngtypid);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 1, &range));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Constructor just like multirange_constructor1, but opr_sanity gets angry
|
|
|
|
* if the same internal function handles multiple functions with different arg
|
|
|
|
* counts.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
multirange_constructor0(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2020-12-21 12:25:32 +01:00
|
|
|
Oid mltrngtypid;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
TypeCacheEntry *rangetyp;
|
|
|
|
|
2020-12-21 12:25:32 +01:00
|
|
|
/* This should always be called without arguments */
|
|
|
|
if (PG_NARGS() != 0)
|
|
|
|
elog(ERROR,
|
|
|
|
"niladic multirange constructor must not receive arguments");
|
|
|
|
|
|
|
|
mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypid);
|
|
|
|
rangetyp = typcache->rngtype;
|
|
|
|
|
2020-12-21 12:25:32 +01:00
|
|
|
PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* multirange, multirange -> multirange type functions */
|
|
|
|
|
|
|
|
/* multirange union */
|
|
|
|
Datum
|
|
|
|
multirange_union(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
int32 range_count1;
|
|
|
|
int32 range_count2;
|
|
|
|
int32 range_count3;
|
|
|
|
RangeType **ranges1;
|
|
|
|
RangeType **ranges2;
|
|
|
|
RangeType **ranges3;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1))
|
|
|
|
PG_RETURN_MULTIRANGE_P(mr2);
|
|
|
|
if (MultirangeIsEmpty(mr2))
|
|
|
|
PG_RETURN_MULTIRANGE_P(mr1);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
|
|
|
multirange_deserialize(typcache->rngtype, mr1, &range_count1, &ranges1);
|
|
|
|
multirange_deserialize(typcache->rngtype, mr2, &range_count2, &ranges2);
|
|
|
|
|
|
|
|
range_count3 = range_count1 + range_count2;
|
|
|
|
ranges3 = palloc0(range_count3 * sizeof(RangeType *));
|
|
|
|
memcpy(ranges3, ranges1, range_count1 * sizeof(RangeType *));
|
|
|
|
memcpy(ranges3 + range_count1, ranges2, range_count2 * sizeof(RangeType *));
|
|
|
|
PG_RETURN_MULTIRANGE_P(make_multirange(typcache->type_id, typcache->rngtype,
|
|
|
|
range_count3, ranges3));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* multirange minus */
|
|
|
|
Datum
|
|
|
|
multirange_minus(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
Oid mltrngtypoid = MultirangeTypeGetOid(mr1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
TypeCacheEntry *rangetyp;
|
|
|
|
int32 range_count1;
|
|
|
|
int32 range_count2;
|
|
|
|
RangeType **ranges1;
|
|
|
|
RangeType **ranges2;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
|
|
|
rangetyp = typcache->rngtype;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
PG_RETURN_MULTIRANGE_P(mr1);
|
|
|
|
|
|
|
|
multirange_deserialize(typcache->rngtype, mr1, &range_count1, &ranges1);
|
|
|
|
multirange_deserialize(typcache->rngtype, mr2, &range_count2, &ranges2);
|
|
|
|
|
|
|
|
PG_RETURN_MULTIRANGE_P(multirange_minus_internal(mltrngtypoid,
|
|
|
|
rangetyp,
|
|
|
|
range_count1,
|
|
|
|
ranges1,
|
|
|
|
range_count2,
|
|
|
|
ranges2));
|
|
|
|
}
|
|
|
|
|
|
|
|
MultirangeType *
|
|
|
|
multirange_minus_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp,
|
|
|
|
int32 range_count1, RangeType **ranges1,
|
|
|
|
int32 range_count2, RangeType **ranges2)
|
|
|
|
{
|
|
|
|
RangeType *r1;
|
|
|
|
RangeType *r2;
|
|
|
|
RangeType **ranges3;
|
|
|
|
int32 range_count3;
|
|
|
|
int32 i1;
|
|
|
|
int32 i2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Worst case: every range in ranges1 makes a different cut to some range
|
|
|
|
* in ranges2.
|
|
|
|
*/
|
|
|
|
ranges3 = palloc0((range_count1 + range_count2) * sizeof(RangeType *));
|
|
|
|
range_count3 = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For each range in mr1, keep subtracting until it's gone or the ranges
|
|
|
|
* in mr2 have passed it. After a subtraction we assign what's left back
|
|
|
|
* to r1. The parallel progress through mr1 and mr2 is similar to
|
|
|
|
* multirange_overlaps_multirange_internal.
|
|
|
|
*/
|
|
|
|
r2 = ranges2[0];
|
|
|
|
for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
|
|
|
|
{
|
|
|
|
r1 = ranges1[i1];
|
|
|
|
|
|
|
|
/* Discard r2s while r2 << r1 */
|
|
|
|
while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
|
|
|
|
{
|
|
|
|
r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
|
|
|
|
}
|
|
|
|
|
|
|
|
while (r2 != NULL)
|
|
|
|
{
|
|
|
|
if (range_split_internal(rangetyp, r1, r2, &ranges3[range_count3], &r1))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If r2 takes a bite out of the middle of r1, we need two
|
|
|
|
* outputs
|
|
|
|
*/
|
|
|
|
range_count3++;
|
|
|
|
r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
|
|
|
|
}
|
|
|
|
else if (range_overlaps_internal(rangetyp, r1, r2))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If r2 overlaps r1, replace r1 with r1 - r2.
|
|
|
|
*/
|
|
|
|
r1 = range_minus_internal(rangetyp, r1, r2);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If r2 goes past r1, then we need to stay with it, in case
|
|
|
|
* it hits future r1s. Otherwise we need to keep r1, in case
|
|
|
|
* future r2s hit it. Since we already subtracted, there's no
|
|
|
|
* point in using the overright/overleft calls.
|
|
|
|
*/
|
|
|
|
if (RangeIsEmpty(r1) || range_before_internal(rangetyp, r1, r2))
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This and all future r2s are past r1, so keep them. Also
|
|
|
|
* assign whatever is left of r1 to the result.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Nothing else can remove anything from r1, so keep it. Even if r1 is
|
|
|
|
* empty here, make_multirange will remove it.
|
|
|
|
*/
|
|
|
|
ranges3[range_count3++] = r1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return make_multirange(mltrngtypoid, rangetyp, range_count3, ranges3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* multirange intersection */
|
|
|
|
Datum
|
|
|
|
multirange_intersect(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
Oid mltrngtypoid = MultirangeTypeGetOid(mr1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
TypeCacheEntry *rangetyp;
|
|
|
|
int32 range_count1;
|
|
|
|
int32 range_count2;
|
|
|
|
RangeType **ranges1;
|
|
|
|
RangeType **ranges2;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
|
|
|
rangetyp = typcache->rngtype;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
PG_RETURN_MULTIRANGE_P(make_empty_multirange(mltrngtypoid, rangetyp));
|
|
|
|
|
|
|
|
multirange_deserialize(rangetyp, mr1, &range_count1, &ranges1);
|
|
|
|
multirange_deserialize(rangetyp, mr2, &range_count2, &ranges2);
|
|
|
|
|
|
|
|
PG_RETURN_MULTIRANGE_P(multirange_intersect_internal(mltrngtypoid,
|
|
|
|
rangetyp,
|
|
|
|
range_count1,
|
|
|
|
ranges1,
|
|
|
|
range_count2,
|
|
|
|
ranges2));
|
|
|
|
}
|
|
|
|
|
|
|
|
MultirangeType *
|
|
|
|
multirange_intersect_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp,
|
|
|
|
int32 range_count1, RangeType **ranges1,
|
|
|
|
int32 range_count2, RangeType **ranges2)
|
|
|
|
{
|
|
|
|
RangeType *r1;
|
|
|
|
RangeType *r2;
|
|
|
|
RangeType **ranges3;
|
|
|
|
int32 range_count3;
|
|
|
|
int32 i1;
|
|
|
|
int32 i2;
|
|
|
|
|
|
|
|
if (range_count1 == 0 || range_count2 == 0)
|
|
|
|
return make_multirange(mltrngtypoid, rangetyp, 0, NULL);
|
|
|
|
|
|
|
|
/*-----------------------------------------------
|
|
|
|
* Worst case is a stitching pattern like this:
|
|
|
|
*
|
|
|
|
* mr1: --- --- --- ---
|
|
|
|
* mr2: --- --- ---
|
|
|
|
* mr3: - - - - - -
|
|
|
|
*
|
|
|
|
* That seems to be range_count1 + range_count2 - 1,
|
|
|
|
* but one extra won't hurt.
|
|
|
|
*-----------------------------------------------
|
|
|
|
*/
|
|
|
|
ranges3 = palloc0((range_count1 + range_count2) * sizeof(RangeType *));
|
|
|
|
range_count3 = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For each range in mr1, keep intersecting until the ranges in mr2 have
|
|
|
|
* passed it. The parallel progress through mr1 and mr2 is similar to
|
|
|
|
* multirange_minus_multirange_internal, but we don't have to assign back
|
|
|
|
* to r1.
|
|
|
|
*/
|
|
|
|
r2 = ranges2[0];
|
|
|
|
for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
|
|
|
|
{
|
|
|
|
r1 = ranges1[i1];
|
|
|
|
|
|
|
|
/* Discard r2s while r2 << r1 */
|
|
|
|
while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
|
|
|
|
{
|
|
|
|
r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
|
|
|
|
}
|
|
|
|
|
|
|
|
while (r2 != NULL)
|
|
|
|
{
|
|
|
|
if (range_overlaps_internal(rangetyp, r1, r2))
|
|
|
|
{
|
|
|
|
/* Keep the overlapping part */
|
|
|
|
ranges3[range_count3++] = range_intersect_internal(rangetyp, r1, r2);
|
|
|
|
|
|
|
|
/* If we "used up" all of r2, go to the next one... */
|
|
|
|
if (range_overleft_internal(rangetyp, r2, r1))
|
|
|
|
r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
|
|
|
|
|
|
|
|
/* ...otherwise go to the next r1 */
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* We're past r1, so move to the next one */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we're out of r2s, there can be no more intersections */
|
|
|
|
if (r2 == NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return make_multirange(mltrngtypoid, rangetyp, range_count3, ranges3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* range_agg_transfn: combine adjacent/overlapping ranges.
|
|
|
|
*
|
|
|
|
* All we do here is gather the input ranges into an array
|
|
|
|
* so that the finalfn can sort and combine them.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
range_agg_transfn(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MemoryContext aggContext;
|
|
|
|
Oid rngtypoid;
|
|
|
|
ArrayBuildState *state;
|
|
|
|
|
|
|
|
if (!AggCheckCallContext(fcinfo, &aggContext))
|
|
|
|
elog(ERROR, "range_agg_transfn called in non-aggregate context");
|
|
|
|
|
|
|
|
rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
|
|
|
|
if (!type_is_range(rngtypoid))
|
2022-03-30 17:48:56 +02:00
|
|
|
elog(ERROR, "range_agg must be called with a range");
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
if (PG_ARGISNULL(0))
|
|
|
|
state = initArrayResult(rngtypoid, aggContext, false);
|
|
|
|
else
|
|
|
|
state = (ArrayBuildState *) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
/* skip NULLs */
|
|
|
|
if (!PG_ARGISNULL(1))
|
|
|
|
accumArrayResult(state, PG_GETARG_DATUM(1), false, rngtypoid, aggContext);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* range_agg_finalfn: use our internal array to merge touching ranges.
|
2022-03-30 20:12:53 +02:00
|
|
|
*
|
|
|
|
* Shared by range_agg_finalfn(anyrange) and
|
|
|
|
* multirange_agg_finalfn(anymultirange).
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
range_agg_finalfn(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MemoryContext aggContext;
|
|
|
|
Oid mltrngtypoid;
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
ArrayBuildState *state;
|
|
|
|
int32 range_count;
|
|
|
|
RangeType **ranges;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!AggCheckCallContext(fcinfo, &aggContext))
|
|
|
|
elog(ERROR, "range_agg_finalfn called in non-aggregate context");
|
|
|
|
|
|
|
|
state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
|
|
|
|
if (state == NULL)
|
|
|
|
/* This shouldn't be possible, but just in case.... */
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
/* Also return NULL if we had zero inputs, like other aggregates */
|
|
|
|
range_count = state->nelems;
|
|
|
|
if (range_count == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
|
|
|
|
|
|
|
ranges = palloc0(range_count * sizeof(RangeType *));
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
|
|
|
|
|
|
|
|
PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypoid, typcache->rngtype, range_count, ranges));
|
|
|
|
}
|
|
|
|
|
2022-03-30 20:12:53 +02:00
|
|
|
/*
|
|
|
|
* multirange_agg_transfn: combine adjacent/overlapping multiranges.
|
|
|
|
*
|
|
|
|
* All we do here is gather the input multiranges' ranges into an array so
|
|
|
|
* that the finalfn can sort and combine them.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
multirange_agg_transfn(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MemoryContext aggContext;
|
|
|
|
Oid mltrngtypoid;
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
TypeCacheEntry *rngtypcache;
|
|
|
|
ArrayBuildState *state;
|
|
|
|
|
|
|
|
if (!AggCheckCallContext(fcinfo, &aggContext))
|
|
|
|
elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
|
|
|
|
|
|
|
|
mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
|
|
|
|
if (!type_is_multirange(mltrngtypoid))
|
|
|
|
elog(ERROR, "range_agg must be called with a multirange");
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
|
|
|
rngtypcache = typcache->rngtype;
|
|
|
|
|
|
|
|
if (PG_ARGISNULL(0))
|
|
|
|
state = initArrayResult(rngtypcache->type_id, aggContext, false);
|
|
|
|
else
|
|
|
|
state = (ArrayBuildState *) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
/* skip NULLs */
|
|
|
|
if (!PG_ARGISNULL(1))
|
|
|
|
{
|
|
|
|
MultirangeType *current;
|
|
|
|
int32 range_count;
|
|
|
|
RangeType **ranges;
|
|
|
|
|
|
|
|
current = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
multirange_deserialize(rngtypcache, current, &range_count, &ranges);
|
|
|
|
if (range_count == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Add an empty range so we get an empty result (not a null
|
|
|
|
* result).
|
|
|
|
*/
|
|
|
|
accumArrayResult(state,
|
|
|
|
RangeTypePGetDatum(make_empty_range(rngtypcache)),
|
|
|
|
false, rngtypcache->type_id, aggContext);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int32 i = 0; i < range_count; i++)
|
|
|
|
accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(state);
|
|
|
|
}
|
|
|
|
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
Datum
|
|
|
|
multirange_intersect_agg_transfn(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MemoryContext aggContext;
|
|
|
|
Oid mltrngtypoid;
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
MultirangeType *result;
|
|
|
|
MultirangeType *current;
|
|
|
|
int32 range_count1;
|
|
|
|
int32 range_count2;
|
|
|
|
RangeType **ranges1;
|
|
|
|
RangeType **ranges2;
|
|
|
|
|
|
|
|
if (!AggCheckCallContext(fcinfo, &aggContext))
|
|
|
|
elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
|
|
|
|
|
|
|
|
mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
|
|
|
|
if (!type_is_multirange(mltrngtypoid))
|
2022-03-30 17:48:56 +02:00
|
|
|
elog(ERROR, "range_intersect_agg must be called with a multirange");
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
|
|
|
|
|
|
|
/* strictness ensures these are non-null */
|
|
|
|
result = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
current = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
|
|
|
|
multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
|
|
|
|
multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
|
|
|
|
|
|
|
|
result = multirange_intersect_internal(mltrngtypoid,
|
|
|
|
typcache->rngtype,
|
|
|
|
range_count1,
|
|
|
|
ranges1,
|
|
|
|
range_count2,
|
|
|
|
ranges2);
|
2022-08-28 10:47:10 +02:00
|
|
|
PG_RETURN_MULTIRANGE_P(result);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* multirange -> element type functions */
|
|
|
|
|
|
|
|
/* extract lower bound value */
|
|
|
|
Datum
|
|
|
|
multirange_lower(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower;
|
|
|
|
RangeBound upper;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, 0,
|
|
|
|
&lower, &upper);
|
|
|
|
|
|
|
|
if (!lower.infinite)
|
|
|
|
PG_RETURN_DATUM(lower.val);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* extract upper bound value */
|
|
|
|
Datum
|
|
|
|
multirange_upper(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower;
|
|
|
|
RangeBound upper;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
|
|
|
|
&lower, &upper);
|
|
|
|
|
|
|
|
if (!upper.infinite)
|
|
|
|
PG_RETURN_DATUM(upper.val);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* multirange -> bool functions */
|
|
|
|
|
|
|
|
/* is multirange empty? */
|
|
|
|
Datum
|
|
|
|
multirange_empty(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(MultirangeIsEmpty(mr));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is lower bound inclusive? */
|
|
|
|
Datum
|
|
|
|
multirange_lower_inc(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower;
|
|
|
|
RangeBound upper;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, 0,
|
|
|
|
&lower, &upper);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(lower.inclusive);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is upper bound inclusive? */
|
|
|
|
Datum
|
|
|
|
multirange_upper_inc(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower;
|
|
|
|
RangeBound upper;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
|
|
|
|
&lower, &upper);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(upper.inclusive);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is lower bound infinite? */
|
|
|
|
Datum
|
|
|
|
multirange_lower_inf(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower;
|
|
|
|
RangeBound upper;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, 0,
|
|
|
|
&lower, &upper);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(lower.infinite);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is upper bound infinite? */
|
|
|
|
Datum
|
|
|
|
multirange_upper_inf(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower;
|
|
|
|
RangeBound upper;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
|
|
|
|
&lower, &upper);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(upper.infinite);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* multirange, element -> bool functions */
|
|
|
|
|
|
|
|
/* contains? */
|
|
|
|
Datum
|
|
|
|
multirange_contains_elem(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
Datum val = PG_GETARG_DATUM(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_contains_elem_internal(typcache->rngtype, mr, val));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* contained by? */
|
|
|
|
Datum
|
|
|
|
elem_contained_by_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Datum val = PG_GETARG_DATUM(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_contains_elem_internal(typcache->rngtype, mr, val));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison function for checking if any range of multirange contains given
|
|
|
|
* key element using binary search.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
multirange_elem_bsearch_comparison(TypeCacheEntry *typcache,
|
|
|
|
RangeBound *lower, RangeBound *upper,
|
|
|
|
void *key, bool *match)
|
|
|
|
{
|
|
|
|
Datum val = *((Datum *) key);
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
if (!lower->infinite)
|
|
|
|
{
|
|
|
|
cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
|
|
|
|
typcache->rng_collation,
|
|
|
|
lower->val, val));
|
|
|
|
if (cmp > 0 || (cmp == 0 && !lower->inclusive))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!upper->infinite)
|
|
|
|
{
|
|
|
|
cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
|
|
|
|
typcache->rng_collation,
|
|
|
|
upper->val, val));
|
|
|
|
if (cmp < 0 || (cmp == 0 && !upper->inclusive))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*match = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Test whether multirange mr contains a specific element value.
|
|
|
|
*/
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_contains_elem_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr, Datum val)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
return multirange_bsearch_match(rangetyp, mr, &val,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
multirange_elem_bsearch_comparison);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* multirange, range -> bool functions */
|
|
|
|
|
|
|
|
/* contains? */
|
|
|
|
Datum
|
|
|
|
multirange_contains_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_contains_range_internal(typcache->rngtype, mr, r));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
2020-12-29 21:35:33 +01:00
|
|
|
Datum
|
|
|
|
range_contains_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_contains_multirange_internal(typcache->rngtype, r, mr));
|
2020-12-29 21:35:33 +01:00
|
|
|
}
|
|
|
|
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
/* contained by? */
|
|
|
|
Datum
|
|
|
|
range_contained_by_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_contains_range_internal(typcache->rngtype, mr, r));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
2020-12-29 21:35:33 +01:00
|
|
|
Datum
|
|
|
|
multirange_contained_by_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_contains_multirange_internal(typcache->rngtype, r, mr));
|
2020-12-29 21:35:33 +01:00
|
|
|
}
|
|
|
|
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
/*
|
|
|
|
* Comparison function for checking if any range of multirange contains given
|
|
|
|
* key range using binary search.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
multirange_range_contains_bsearch_comparison(TypeCacheEntry *typcache,
|
|
|
|
RangeBound *lower, RangeBound *upper,
|
|
|
|
void *key, bool *match)
|
|
|
|
{
|
|
|
|
RangeBound *keyLower = (RangeBound *) key;
|
|
|
|
RangeBound *keyUpper = (RangeBound *) key + 1;
|
|
|
|
|
|
|
|
/* Check if key range is strictly in the left or in the right */
|
|
|
|
if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
|
|
|
|
return -1;
|
|
|
|
if (range_cmp_bounds(typcache, keyLower, upper) > 0)
|
2020-12-29 21:35:26 +01:00
|
|
|
return 1;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point we found overlapping range. But we have to check if it
|
|
|
|
* really contains the key range. Anyway, we have to stop our search
|
|
|
|
* here, because multirange contains only non-overlapping ranges.
|
|
|
|
*/
|
|
|
|
*match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Test whether multirange mr contains a specific range r.
|
|
|
|
*/
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_contains_range_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr,
|
|
|
|
const RangeType *r)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound bounds[2];
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Every multirange contains an infinite number of empty ranges, even an
|
|
|
|
* empty one.
|
|
|
|
*/
|
|
|
|
if (RangeIsEmpty(r))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
|
|
|
|
Assert(!empty);
|
|
|
|
|
|
|
|
return multirange_bsearch_match(rangetyp, mr, bounds,
|
|
|
|
multirange_range_contains_bsearch_comparison);
|
|
|
|
}
|
|
|
|
|
2020-12-29 21:35:33 +01:00
|
|
|
/*
|
|
|
|
* Test whether range r contains a multirange mr.
|
|
|
|
*/
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
range_contains_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
2020-12-29 21:35:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2,
|
|
|
|
tmp;
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Every range contains an infinite number of empty multiranges, even an
|
|
|
|
* empty one.
|
|
|
|
*/
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Range contains multirange iff it contains its union range. */
|
|
|
|
range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
|
|
|
|
Assert(!empty);
|
|
|
|
multirange_get_bounds(rangetyp, mr, 0, &lower2, &tmp);
|
|
|
|
multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
|
|
|
|
|
|
|
|
return range_bounds_contains(rangetyp, &lower1, &upper1, &lower2, &upper2);
|
|
|
|
}
|
|
|
|
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
/* multirange, multirange -> bool functions */
|
|
|
|
|
|
|
|
/* equality (internal version) */
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_eq_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr1,
|
|
|
|
const MultirangeType *mr2)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
int32 range_count_1;
|
|
|
|
int32 range_count_2;
|
|
|
|
int32 i;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
/* Different types should be prevented by ANYMULTIRANGE matching rules */
|
|
|
|
if (MultirangeTypeGetOid(mr1) != MultirangeTypeGetOid(mr2))
|
|
|
|
elog(ERROR, "multirange types do not match");
|
|
|
|
|
|
|
|
range_count_1 = mr1->rangeCount;
|
|
|
|
range_count_2 = mr2->rangeCount;
|
|
|
|
|
|
|
|
if (range_count_1 != range_count_2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (i = 0; i < range_count_1; i++)
|
|
|
|
{
|
|
|
|
multirange_get_bounds(rangetyp, mr1, i, &lower1, &upper1);
|
|
|
|
multirange_get_bounds(rangetyp, mr2, i, &lower2, &upper2);
|
|
|
|
|
|
|
|
if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
|
|
|
|
range_cmp_bounds(rangetyp, &upper1, &upper2) != 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* equality */
|
|
|
|
Datum
|
|
|
|
multirange_eq(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_eq_internal(typcache->rngtype, mr1, mr2));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* inequality (internal version) */
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_ne_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr1,
|
|
|
|
const MultirangeType *mr2)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
2020-12-29 21:35:38 +01:00
|
|
|
return (!multirange_eq_internal(rangetyp, mr1, mr2));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* inequality */
|
|
|
|
Datum
|
|
|
|
multirange_ne(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_ne_internal(typcache->rngtype, mr1, mr2));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* overlaps? */
|
|
|
|
Datum
|
|
|
|
range_overlaps_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_overlaps_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_overlaps_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_overlaps_multirange_internal(typcache->rngtype, mr1, mr2));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison function for checking if any range of multirange overlaps given
|
|
|
|
* key range using binary search.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
multirange_range_overlaps_bsearch_comparison(TypeCacheEntry *typcache,
|
|
|
|
RangeBound *lower, RangeBound *upper,
|
|
|
|
void *key, bool *match)
|
|
|
|
{
|
|
|
|
RangeBound *keyLower = (RangeBound *) key;
|
|
|
|
RangeBound *keyUpper = (RangeBound *) key + 1;
|
|
|
|
|
|
|
|
if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
|
|
|
|
return -1;
|
|
|
|
if (range_cmp_bounds(typcache, keyLower, upper) > 0)
|
2020-12-29 21:35:26 +01:00
|
|
|
return 1;
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
|
|
|
*match = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
range_overlaps_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound bounds[2];
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Empties never overlap, even with empties. (This seems strange since
|
|
|
|
* they *do* contain each other, but we want to follow how ranges work.)
|
|
|
|
*/
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
|
|
|
|
Assert(!empty);
|
|
|
|
|
|
|
|
return multirange_bsearch_match(rangetyp, mr, bounds,
|
|
|
|
multirange_range_overlaps_bsearch_comparison);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_overlaps_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr1,
|
|
|
|
const MultirangeType *mr2)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
int32 range_count1;
|
|
|
|
int32 range_count2;
|
|
|
|
int32 i1;
|
|
|
|
int32 i2;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Empties never overlap, even with empties. (This seems strange since
|
|
|
|
* they *do* contain each other, but we want to follow how ranges work.)
|
|
|
|
*/
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
range_count1 = mr1->rangeCount;
|
|
|
|
range_count2 = mr2->rangeCount;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Every range in mr1 gets a chance to overlap with the ranges in mr2, but
|
|
|
|
* we can use their ordering to avoid O(n^2). This is similar to
|
|
|
|
* range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
|
|
|
|
* don't find an overlap with r we're done, and here if we don't find an
|
|
|
|
* overlap with r2 we try the next r2.
|
|
|
|
*/
|
|
|
|
i1 = 0;
|
|
|
|
multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
|
|
|
|
for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
|
|
|
|
{
|
|
|
|
multirange_get_bounds(rangetyp, mr2, i2, &lower2, &upper2);
|
|
|
|
|
|
|
|
/* Discard r1s while r1 << r2 */
|
|
|
|
while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
|
|
|
|
{
|
|
|
|
if (++i1 >= range_count1)
|
|
|
|
return false;
|
|
|
|
multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If r1 && r2, we're done, otherwise we failed to find an overlap for
|
|
|
|
* r2, so go to the next one.
|
|
|
|
*/
|
|
|
|
if (range_bounds_overlaps(rangetyp, &lower1, &upper1, &lower2, &upper2))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We looked through all of mr2 without finding an overlap */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* does not extend to right of? */
|
2020-12-29 21:35:38 +01:00
|
|
|
bool
|
|
|
|
range_overleft_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
Assert(!empty);
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
&lower2, &upper2);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
range_overleft_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(range_overleft_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_overleft_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr) || RangeIsEmpty(r))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
|
|
|
|
&lower1, &upper1);
|
|
|
|
range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
|
|
|
|
Assert(!empty);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_overleft_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
|
|
|
|
&lower1, &upper1);
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
|
|
|
|
&lower2, &upper2);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* does not extend to left of? */
|
2020-12-29 21:35:38 +01:00
|
|
|
bool
|
|
|
|
range_overright_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
Assert(!empty);
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
range_overright_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(range_overright_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_overright_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr) || RangeIsEmpty(r))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
|
|
|
|
range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
|
|
|
|
Assert(!empty);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_overright_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr1, 0, &lower1, &upper1);
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr2, 0, &lower2, &upper2);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* contains? */
|
|
|
|
Datum
|
|
|
|
multirange_contains_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache->rngtype, mr1, mr2));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* contained by? */
|
|
|
|
Datum
|
|
|
|
multirange_contained_by_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache->rngtype, mr2, mr1));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Test whether multirange mr1 contains every range from another multirange mr2.
|
|
|
|
*/
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_contains_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr1,
|
|
|
|
const MultirangeType *mr2)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
int32 range_count1 = mr1->rangeCount;
|
|
|
|
int32 range_count2 = mr2->rangeCount;
|
|
|
|
int i1,
|
|
|
|
i2;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We follow the same logic for empties as ranges: - an empty multirange
|
|
|
|
* contains an empty range/multirange. - an empty multirange can't contain
|
|
|
|
* any other range/multirange. - an empty multirange is contained by any
|
|
|
|
* other range/multirange.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (range_count2 == 0)
|
|
|
|
return true;
|
|
|
|
if (range_count1 == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Every range in mr2 must be contained by some range in mr1. To avoid
|
|
|
|
* O(n^2) we walk through both ranges in tandem.
|
|
|
|
*/
|
|
|
|
i1 = 0;
|
|
|
|
multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
|
|
|
|
for (i2 = 0; i2 < range_count2; i2++)
|
|
|
|
{
|
|
|
|
multirange_get_bounds(rangetyp, mr2, i2, &lower2, &upper2);
|
|
|
|
|
|
|
|
/* Discard r1s while r1 << r2 */
|
|
|
|
while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
|
|
|
|
{
|
|
|
|
if (++i1 >= range_count1)
|
|
|
|
return false;
|
|
|
|
multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If r1 @> r2, go to the next r2, otherwise return false (since every
|
|
|
|
* r1[n] and r1[n+1] must have a gap). Note this will give weird
|
|
|
|
* answers if you don't canonicalize, e.g. with a custom
|
|
|
|
* int2multirange {[1,1], [2,2]} there is a "gap". But that is
|
|
|
|
* consistent with other range operators, e.g. '[1,1]'::int2range -|-
|
|
|
|
* '[2,2]'::int2range is false.
|
|
|
|
*/
|
|
|
|
if (!range_bounds_contains(rangetyp, &lower1, &upper1,
|
|
|
|
&lower2, &upper2))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All ranges in mr2 are satisfied */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strictly left of? */
|
|
|
|
Datum
|
|
|
|
range_before_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_before_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_before_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_after_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_before_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_before_multirange_internal(typcache->rngtype, mr1, mr2));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* strictly right of? */
|
|
|
|
Datum
|
|
|
|
range_after_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_after_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_after_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_before_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_after_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(multirange_before_multirange_internal(typcache->rngtype, mr2, mr1));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* strictly left of? (internal version) */
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
range_before_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
Assert(!empty);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_before_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const MultirangeType *mr1,
|
|
|
|
const MultirangeType *mr2)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
return false;
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
&lower1, &upper1);
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr2, 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
&lower2, &upper2);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* strictly right of? (internal version) */
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
range_after_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
int32 range_count;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
Assert(!empty);
|
|
|
|
|
|
|
|
range_count = mr->rangeCount;
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr, range_count - 1,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
&lower2, &upper2);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2020-12-29 21:35:38 +01:00
|
|
|
range_adjacent_multirange_internal(TypeCacheEntry *rangetyp,
|
|
|
|
const RangeType *r,
|
|
|
|
const MultirangeType *mr)
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
bool empty;
|
|
|
|
int32 range_count;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
Assert(!empty);
|
|
|
|
|
|
|
|
range_count = mr->rangeCount;
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr, 0,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
&lower2, &upper2);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
if (bounds_adjacent(rangetyp, upper1, lower2))
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (range_count > 1)
|
2020-12-29 21:35:38 +01:00
|
|
|
multirange_get_bounds(rangetyp, mr, range_count - 1,
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
&lower2, &upper2);
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
if (bounds_adjacent(rangetyp, upper2, lower1))
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adjacent to? */
|
|
|
|
Datum
|
|
|
|
range_adjacent_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(0);
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_adjacent_range(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
RangeType *r = PG_GETARG_RANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
|
|
|
|
if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
|
2020-12-29 21:35:38 +01:00
|
|
|
PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache->rngtype, r, mr));
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_adjacent_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
int32 range_count1;
|
|
|
|
int32 range_count2;
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
|
|
|
range_count1 = mr1->rangeCount;
|
|
|
|
range_count2 = mr2->rangeCount;
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr1, range_count1 - 1,
|
|
|
|
&lower1, &upper1);
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr2, 0,
|
|
|
|
&lower2, &upper2);
|
|
|
|
if (bounds_adjacent(typcache->rngtype, upper1, lower2))
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
|
|
|
if (range_count1 > 1)
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr1, 0,
|
|
|
|
&lower1, &upper1);
|
|
|
|
if (range_count2 > 1)
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr2, range_count2 - 1,
|
|
|
|
&lower2, &upper2);
|
|
|
|
if (bounds_adjacent(typcache->rngtype, upper2, lower1))
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Btree support */
|
|
|
|
|
|
|
|
/* btree comparator */
|
|
|
|
Datum
|
|
|
|
multirange_cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
|
|
|
|
int32 range_count_1;
|
|
|
|
int32 range_count_2;
|
|
|
|
int32 range_count_max;
|
|
|
|
int32 i;
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
int cmp = 0; /* If both are empty we'll use this. */
|
|
|
|
|
|
|
|
/* Different types should be prevented by ANYMULTIRANGE matching rules */
|
|
|
|
if (MultirangeTypeGetOid(mr1) != MultirangeTypeGetOid(mr2))
|
|
|
|
elog(ERROR, "multirange types do not match");
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
|
|
|
|
|
|
|
|
range_count_1 = mr1->rangeCount;
|
|
|
|
range_count_2 = mr2->rangeCount;
|
|
|
|
|
|
|
|
/* Loop over source data */
|
|
|
|
range_count_max = Max(range_count_1, range_count_2);
|
|
|
|
for (i = 0; i < range_count_max; i++)
|
|
|
|
{
|
|
|
|
RangeBound lower1,
|
|
|
|
upper1,
|
|
|
|
lower2,
|
|
|
|
upper2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If one multirange is shorter, it's as if it had empty ranges at the
|
|
|
|
* end to extend its length. An empty range compares earlier than any
|
|
|
|
* other range, so the shorter multirange comes before the longer.
|
|
|
|
* This is the same behavior as in other types, e.g. in strings 'aaa'
|
|
|
|
* < 'aaaaaa'.
|
|
|
|
*/
|
|
|
|
if (i >= range_count_1)
|
|
|
|
{
|
|
|
|
cmp = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i >= range_count_2)
|
|
|
|
{
|
|
|
|
cmp = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr1, i, &lower1, &upper1);
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr2, i, &lower2, &upper2);
|
|
|
|
|
|
|
|
cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
|
|
|
|
if (cmp == 0)
|
|
|
|
cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
|
|
|
|
if (cmp != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(mr1, 0);
|
|
|
|
PG_FREE_IF_COPY(mr2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(cmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* inequality operators using the multirange_cmp function */
|
|
|
|
Datum
|
|
|
|
multirange_lt(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int cmp = multirange_cmp(fcinfo);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_le(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int cmp = multirange_cmp(fcinfo);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_ge(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int cmp = multirange_cmp(fcinfo);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
multirange_gt(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int cmp = multirange_cmp(fcinfo);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* multirange -> range functions */
|
|
|
|
|
|
|
|
/* Find the smallest range that includes everything in the multirange */
|
|
|
|
Datum
|
|
|
|
range_merge_from_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
Oid mltrngtypoid = MultirangeTypeGetOid(mr);
|
|
|
|
TypeCacheEntry *typcache;
|
|
|
|
RangeType *result;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
|
|
|
|
|
|
|
if (MultirangeIsEmpty(mr))
|
|
|
|
{
|
|
|
|
result = make_empty_range(typcache->rngtype);
|
|
|
|
}
|
|
|
|
else if (mr->rangeCount == 1)
|
|
|
|
{
|
|
|
|
result = multirange_get_range(typcache->rngtype, mr, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RangeBound firstLower,
|
|
|
|
firstUpper,
|
|
|
|
lastLower,
|
|
|
|
lastUpper;
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, 0,
|
|
|
|
&firstLower, &firstUpper);
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
|
|
|
|
&lastLower, &lastUpper);
|
|
|
|
|
2022-12-15 18:18:36 +01:00
|
|
|
result = make_range(typcache->rngtype, &firstLower, &lastUpper,
|
|
|
|
false, NULL);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_RANGE_P(result);
|
|
|
|
}
|
|
|
|
|
2021-07-18 20:07:24 +02:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
/* Hash support */
|
|
|
|
|
|
|
|
/* hash a multirange value */
|
|
|
|
Datum
|
|
|
|
hash_multirange(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
uint32 result = 1;
|
|
|
|
TypeCacheEntry *typcache,
|
|
|
|
*scache;
|
|
|
|
int32 range_count,
|
|
|
|
i;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
scache = typcache->rngtype->rngelemtype;
|
|
|
|
if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
|
|
|
|
{
|
|
|
|
scache = lookup_type_cache(scache->type_id,
|
|
|
|
TYPECACHE_HASH_PROC_FINFO);
|
|
|
|
if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("could not identify a hash function for type %s",
|
|
|
|
format_type_be(scache->type_id))));
|
|
|
|
}
|
|
|
|
|
|
|
|
range_count = mr->rangeCount;
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
RangeBound lower,
|
|
|
|
upper;
|
|
|
|
uint8 flags = MultirangeGetFlagsPtr(mr)[i];
|
|
|
|
uint32 lower_hash;
|
|
|
|
uint32 upper_hash;
|
|
|
|
uint32 range_hash;
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
|
|
|
|
|
|
|
|
if (RANGE_HAS_LBOUND(flags))
|
|
|
|
lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
|
|
|
|
typcache->rngtype->rng_collation,
|
|
|
|
lower.val));
|
|
|
|
else
|
|
|
|
lower_hash = 0;
|
|
|
|
|
|
|
|
if (RANGE_HAS_UBOUND(flags))
|
|
|
|
upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
|
|
|
|
typcache->rngtype->rng_collation,
|
|
|
|
upper.val));
|
|
|
|
else
|
|
|
|
upper_hash = 0;
|
|
|
|
|
|
|
|
/* Merge hashes of flags and bounds */
|
|
|
|
range_hash = hash_uint32((uint32) flags);
|
|
|
|
range_hash ^= lower_hash;
|
2022-02-20 07:22:08 +01:00
|
|
|
range_hash = pg_rotate_left32(range_hash, 1);
|
Multirange datatypes
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 Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
range_hash ^= upper_hash;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the same approach as hash_array to combine the individual
|
|
|
|
* elements' hash values:
|
|
|
|
*/
|
|
|
|
result = (result << 5) - result + range_hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(mr, 0);
|
|
|
|
|
|
|
|
PG_RETURN_UINT32(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
|
|
|
|
* Otherwise, similar to hash_multirange.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
hash_multirange_extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
|
|
|
|
Datum seed = PG_GETARG_DATUM(1);
|
|
|
|
uint64 result = 1;
|
|
|
|
TypeCacheEntry *typcache,
|
|
|
|
*scache;
|
|
|
|
int32 range_count,
|
|
|
|
i;
|
|
|
|
|
|
|
|
typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
|
|
|
|
scache = typcache->rngtype->rngelemtype;
|
|
|
|
if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
|
|
|
|
{
|
|
|
|
scache = lookup_type_cache(scache->type_id,
|
|
|
|
TYPECACHE_HASH_EXTENDED_PROC_FINFO);
|
|
|
|
if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("could not identify a hash function for type %s",
|
|
|
|
format_type_be(scache->type_id))));
|
|
|
|
}
|
|
|
|
|
|
|
|
range_count = mr->rangeCount;
|
|
|
|
for (i = 0; i < range_count; i++)
|
|
|
|
{
|
|
|
|
RangeBound lower,
|
|
|
|
upper;
|
|
|
|
uint8 flags = MultirangeGetFlagsPtr(mr)[i];
|
|
|
|
uint64 lower_hash;
|
|
|
|
uint64 upper_hash;
|
|
|
|
uint64 range_hash;
|
|
|
|
|
|
|
|
multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
|
|
|
|
|
|
|
|
if (RANGE_HAS_LBOUND(flags))
|
|
|
|
lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
|
|
|
|
typcache->rngtype->rng_collation,
|
|
|
|
lower.val,
|
|
|
|
seed));
|
|
|
|
else
|
|
|
|
lower_hash = 0;
|
|
|
|
|
|
|
|
if (RANGE_HAS_UBOUND(flags))
|
|
|
|
upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
|
|
|
|
typcache->rngtype->rng_collation,
|
|
|
|
upper.val,
|
|
|
|
seed));
|
|
|
|
else
|
|
|
|
upper_hash = 0;
|
|
|
|
|
|
|
|
/* Merge hashes of flags and bounds */
|
|
|
|
range_hash = DatumGetUInt64(hash_uint32_extended((uint32) flags,
|
|
|
|
DatumGetInt64(seed)));
|
|
|
|
range_hash ^= lower_hash;
|
|
|
|
range_hash = ROTATE_HIGH_AND_LOW_32BITS(range_hash);
|
|
|
|
range_hash ^= upper_hash;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the same approach as hash_array to combine the individual
|
|
|
|
* elements' hash values:
|
|
|
|
*/
|
|
|
|
result = (result << 5) - result + range_hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(mr, 0);
|
|
|
|
|
|
|
|
PG_RETURN_UINT64(result);
|
|
|
|
}
|