Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * rangetypes.c
4 : * I/O functions, operators, and support functions for range types.
5 : *
6 : * The stored (serialized) format of a range value is:
7 : *
8 : * 4 bytes: varlena header
9 : * 4 bytes: range type's OID
10 : * Lower boundary value, if any, aligned according to subtype's typalign
11 : * Upper boundary value, if any, aligned according to subtype's typalign
12 : * 1 byte for flags
13 : *
14 : * This representation is chosen to avoid needing any padding before the
15 : * lower boundary value, even when it requires double alignment. We can
16 : * expect that the varlena header is presented to us on a suitably aligned
17 : * boundary (possibly after detoasting), and then the lower boundary is too.
18 : * Note that this means we can't work with a packed (short varlena header)
19 : * value; we must detoast it first.
20 : *
21 : *
22 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
23 : * Portions Copyright (c) 1994, Regents of the University of California
24 : *
25 : *
26 : * IDENTIFICATION
27 : * src/backend/utils/adt/rangetypes.c
28 : *
29 : *-------------------------------------------------------------------------
30 : */
31 : #include "postgres.h"
32 :
33 : #include "access/tupmacs.h"
34 : #include "common/hashfn.h"
35 : #include "lib/stringinfo.h"
36 : #include "libpq/pqformat.h"
37 : #include "miscadmin.h"
38 : #include "nodes/miscnodes.h"
39 : #include "port/pg_bitutils.h"
40 : #include "utils/builtins.h"
41 : #include "utils/date.h"
42 : #include "utils/lsyscache.h"
43 : #include "utils/rangetypes.h"
44 : #include "utils/timestamp.h"
45 : #include "varatt.h"
46 :
47 :
48 : /* fn_extra cache entry for one of the range I/O functions */
49 : typedef struct RangeIOData
50 : {
51 : TypeCacheEntry *typcache; /* range type's typcache entry */
52 : FmgrInfo typioproc; /* element type's I/O function */
53 : Oid typioparam; /* element type's I/O parameter */
54 : } RangeIOData;
55 :
56 :
57 : static RangeIOData *get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid,
58 : IOFuncSelector func);
59 : static char range_parse_flags(const char *flags_str);
60 : static bool range_parse(const char *string, char *flags, char **lbound_str,
61 : char **ubound_str, Node *escontext);
62 : static const char *range_parse_bound(const char *string, const char *ptr,
63 : char **bound_str, bool *infinite,
64 : Node *escontext);
65 : static char *range_deparse(char flags, const char *lbound_str,
66 : const char *ubound_str);
67 : static char *range_bound_escape(const char *value);
68 : static Size datum_compute_size(Size data_length, Datum val, bool typbyval,
69 : char typalign, int16 typlen, char typstorage);
70 : static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval,
71 : char typalign, int16 typlen, char typstorage);
72 :
73 :
74 : /*
75 : *----------------------------------------------------------
76 : * I/O FUNCTIONS
77 : *----------------------------------------------------------
78 : */
79 :
80 : Datum
4175 heikki.linnakangas 81 GIC 1471 : range_in(PG_FUNCTION_ARGS)
82 : {
4164 bruce 83 1471 : char *input_str = PG_GETARG_CSTRING(0);
4164 bruce 84 CBC 1471 : Oid rngtypoid = PG_GETARG_OID(1);
4164 bruce 85 GIC 1471 : Oid typmod = PG_GETARG_INT32(2);
115 tgl 86 GNC 1471 : Node *escontext = fcinfo->context;
4163 tgl 87 ECB : RangeType *range;
88 : RangeIOData *cache;
4164 89 : char flags;
bruce 90 : char *lbound_str;
91 : char *ubound_str;
92 : RangeBound lower;
93 : RangeBound upper;
94 :
2743 noah 95 GIC 1471 : check_stack_depth(); /* recurses when subtype is a range type */
96 :
4163 tgl 97 1471 : cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_input);
98 :
4175 heikki.linnakangas 99 ECB : /* parse */
115 tgl 100 GNC 1471 : if (!range_parse(input_str, &flags, &lbound_str, &ubound_str, escontext))
101 6 : PG_RETURN_NULL();
4175 heikki.linnakangas 102 ECB :
103 : /* call element type's input function */
4175 heikki.linnakangas 104 GIC 1429 : if (RANGE_HAS_LBOUND(flags))
115 tgl 105 GNC 1096 : if (!InputFunctionCallSafe(&cache->typioproc, lbound_str,
106 : cache->typioparam, typmod,
107 : escontext, &lower.val))
115 tgl 108 UNC 0 : PG_RETURN_NULL();
4175 heikki.linnakangas 109 GIC 1429 : if (RANGE_HAS_UBOUND(flags))
115 tgl 110 GNC 1048 : if (!InputFunctionCallSafe(&cache->typioproc, ubound_str,
111 : cache->typioparam, typmod,
112 : escontext, &upper.val))
113 12 : PG_RETURN_NULL();
4175 heikki.linnakangas 114 ECB :
4163 tgl 115 GIC 1417 : lower.infinite = (flags & RANGE_LB_INF) != 0;
116 1417 : lower.inclusive = (flags & RANGE_LB_INC) != 0;
4163 tgl 117 GBC 1417 : lower.lower = true;
4163 tgl 118 CBC 1417 : upper.infinite = (flags & RANGE_UB_INF) != 0;
119 1417 : upper.inclusive = (flags & RANGE_UB_INC) != 0;
4163 tgl 120 GIC 1417 : upper.lower = false;
121 :
4175 heikki.linnakangas 122 ECB : /* serialize and canonicalize */
115 tgl 123 GNC 1417 : range = make_range(cache->typcache, &lower, &upper,
124 1417 : flags & RANGE_EMPTY, escontext);
4175 heikki.linnakangas 125 ECB :
2029 tgl 126 CBC 1408 : PG_RETURN_RANGE_P(range);
4175 heikki.linnakangas 127 ECB : }
128 :
129 : Datum
4175 heikki.linnakangas 130 CBC 52061 : range_out(PG_FUNCTION_ARGS)
131 : {
2029 tgl 132 GIC 52061 : RangeType *range = PG_GETARG_RANGE_P(0);
4164 tgl 133 ECB : char *output_str;
4163 134 : RangeIOData *cache;
135 : char flags;
4175 heikki.linnakangas 136 CBC 52061 : char *lbound_str = NULL;
4175 heikki.linnakangas 137 GIC 52061 : char *ubound_str = NULL;
138 : RangeBound lower;
139 : RangeBound upper;
4163 tgl 140 ECB : bool empty;
141 :
2743 noah 142 CBC 52061 : check_stack_depth(); /* recurses when subtype is a range type */
143 :
4163 tgl 144 GIC 52061 : cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_output);
145 :
4163 tgl 146 ECB : /* deserialize */
4163 tgl 147 CBC 52061 : range_deserialize(cache->typcache, range, &lower, &upper, &empty);
4163 tgl 148 GIC 52061 : flags = range_get_flags(range);
149 :
150 : /* call element type's output function */
4175 heikki.linnakangas 151 52061 : if (RANGE_HAS_LBOUND(flags))
1130 alvherre 152 CBC 42382 : lbound_str = OutputFunctionCall(&cache->typioproc, lower.val);
4175 heikki.linnakangas 153 GIC 52061 : if (RANGE_HAS_UBOUND(flags))
1130 alvherre 154 CBC 42349 : ubound_str = OutputFunctionCall(&cache->typioproc, upper.val);
155 :
156 : /* construct result string */
4175 heikki.linnakangas 157 52061 : output_str = range_deparse(flags, lbound_str, ubound_str);
4175 heikki.linnakangas 158 ECB :
4175 heikki.linnakangas 159 GIC 52061 : PG_RETURN_CSTRING(output_str);
160 : }
4175 heikki.linnakangas 161 ECB :
162 : /*
4163 tgl 163 : * Binary representation: The first byte is the flags, then the lower bound
164 : * (if present), then the upper bound (if present). Each bound is represented
165 : * by a 4-byte length header and the binary representation of that bound (as
166 : * returned by a call to the send function for the subtype).
4175 heikki.linnakangas 167 : */
168 :
169 : Datum
4175 heikki.linnakangas 170 UIC 0 : range_recv(PG_FUNCTION_ARGS)
171 : {
4164 bruce 172 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
4163 tgl 173 0 : Oid rngtypoid = PG_GETARG_OID(1);
4164 bruce 174 0 : int32 typmod = PG_GETARG_INT32(2);
175 : RangeType *range;
176 : RangeIOData *cache;
177 : char flags;
178 : RangeBound lower;
179 : RangeBound upper;
4175 heikki.linnakangas 180 EUB :
2743 noah 181 UIC 0 : check_stack_depth(); /* recurses when subtype is a range type */
2743 noah 182 EUB :
4163 tgl 183 UBC 0 : cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_receive);
4175 heikki.linnakangas 184 EUB :
185 : /* receive the flags... */
4163 tgl 186 UIC 0 : flags = (unsigned char) pq_getmsgbyte(buf);
187 :
188 : /*
189 : * Mask out any unsupported flags, particularly RANGE_xB_NULL which would
190 : * confuse following tests. Note that range_serialize will take care of
4156 tgl 191 EUB : * cleaning up any inconsistencies in the remaining flags.
192 : */
4163 tgl 193 UBC 0 : flags &= (RANGE_EMPTY |
194 : RANGE_LB_INC |
195 : RANGE_LB_INF |
4163 tgl 196 EUB : RANGE_UB_INC |
197 : RANGE_UB_INF);
198 :
199 : /* receive the bounds ... */
4175 heikki.linnakangas 200 UIC 0 : if (RANGE_HAS_LBOUND(flags))
201 : {
4164 bruce 202 0 : uint32 bound_len = pq_getmsgint(buf, 4);
4164 bruce 203 UBC 0 : const char *bound_data = pq_getmsgbytes(buf, bound_len);
204 : StringInfoData bound_buf;
205 :
4175 heikki.linnakangas 206 UIC 0 : initStringInfo(&bound_buf);
207 0 : appendBinaryStringInfo(&bound_buf, bound_data, bound_len);
208 :
1130 alvherre 209 0 : lower.val = ReceiveFunctionCall(&cache->typioproc,
4163 tgl 210 EUB : &bound_buf,
211 : cache->typioparam,
212 : typmod);
4175 heikki.linnakangas 213 UBC 0 : pfree(bound_buf.data);
214 : }
215 : else
216 0 : lower.val = (Datum) 0;
4175 heikki.linnakangas 217 EUB :
4175 heikki.linnakangas 218 UIC 0 : if (RANGE_HAS_UBOUND(flags))
4175 heikki.linnakangas 219 EUB : {
4164 bruce 220 UIC 0 : uint32 bound_len = pq_getmsgint(buf, 4);
221 0 : const char *bound_data = pq_getmsgbytes(buf, bound_len);
222 : StringInfoData bound_buf;
4175 heikki.linnakangas 223 EUB :
4175 heikki.linnakangas 224 UIC 0 : initStringInfo(&bound_buf);
225 0 : appendBinaryStringInfo(&bound_buf, bound_data, bound_len);
4175 heikki.linnakangas 226 EUB :
1130 alvherre 227 UIC 0 : upper.val = ReceiveFunctionCall(&cache->typioproc,
4163 tgl 228 EUB : &bound_buf,
229 : cache->typioparam,
230 : typmod);
4175 heikki.linnakangas 231 UBC 0 : pfree(bound_buf.data);
232 : }
233 : else
234 0 : upper.val = (Datum) 0;
4175 heikki.linnakangas 235 EUB :
4175 heikki.linnakangas 236 UIC 0 : pq_getmsgend(buf);
4175 heikki.linnakangas 237 EUB :
238 : /* finish constructing RangeBound representation */
4164 bruce 239 UIC 0 : lower.infinite = (flags & RANGE_LB_INF) != 0;
4175 heikki.linnakangas 240 0 : lower.inclusive = (flags & RANGE_LB_INC) != 0;
4164 bruce 241 UBC 0 : lower.lower = true;
4164 bruce 242 UIC 0 : upper.infinite = (flags & RANGE_UB_INF) != 0;
4175 heikki.linnakangas 243 0 : upper.inclusive = (flags & RANGE_UB_INC) != 0;
4164 bruce 244 UBC 0 : upper.lower = false;
245 :
4175 heikki.linnakangas 246 EUB : /* serialize and canonicalize */
115 tgl 247 UNC 0 : range = make_range(cache->typcache, &lower, &upper,
248 0 : flags & RANGE_EMPTY, NULL);
249 :
2029 tgl 250 UBC 0 : PG_RETURN_RANGE_P(range);
4175 heikki.linnakangas 251 EUB : }
252 :
253 : Datum
4175 heikki.linnakangas 254 UBC 0 : range_send(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 255 EUB : {
2029 tgl 256 UIC 0 : RangeType *range = PG_GETARG_RANGE_P(0);
4164 bruce 257 0 : StringInfo buf = makeStringInfo();
4163 tgl 258 EUB : RangeIOData *cache;
259 : char flags;
260 : RangeBound lower;
4164 bruce 261 : RangeBound upper;
262 : bool empty;
263 :
2743 noah 264 UIC 0 : check_stack_depth(); /* recurses when subtype is a range type */
2743 noah 265 EUB :
4163 tgl 266 UIC 0 : cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_send);
4163 tgl 267 EUB :
268 : /* deserialize */
4163 tgl 269 UIC 0 : range_deserialize(cache->typcache, range, &lower, &upper, &empty);
270 0 : flags = range_get_flags(range);
271 :
272 : /* construct output */
4175 heikki.linnakangas 273 0 : pq_begintypsend(buf);
274 :
4175 heikki.linnakangas 275 UBC 0 : pq_sendbyte(buf, flags);
276 :
277 0 : if (RANGE_HAS_LBOUND(flags))
278 : {
1130 alvherre 279 UIC 0 : Datum bound = PointerGetDatum(SendFunctionCall(&cache->typioproc,
4163 tgl 280 EUB : lower.val));
4164 bruce 281 UBC 0 : uint32 bound_len = VARSIZE(bound) - VARHDRSZ;
4164 bruce 282 UIC 0 : char *bound_data = VARDATA(bound);
283 :
2006 andres 284 UBC 0 : pq_sendint32(buf, bound_len);
4175 heikki.linnakangas 285 UIC 0 : pq_sendbytes(buf, bound_data, bound_len);
4175 heikki.linnakangas 286 EUB : }
287 :
4175 heikki.linnakangas 288 UBC 0 : if (RANGE_HAS_UBOUND(flags))
289 : {
1130 alvherre 290 0 : Datum bound = PointerGetDatum(SendFunctionCall(&cache->typioproc,
291 : upper.val));
4164 bruce 292 0 : uint32 bound_len = VARSIZE(bound) - VARHDRSZ;
293 0 : char *bound_data = VARDATA(bound);
294 :
2006 andres 295 0 : pq_sendint32(buf, bound_len);
4175 heikki.linnakangas 296 0 : pq_sendbytes(buf, bound_data, bound_len);
297 : }
298 :
299 0 : PG_RETURN_BYTEA_P(pq_endtypsend(buf));
300 : }
4175 heikki.linnakangas 301 EUB :
302 : /*
4163 tgl 303 : * get_range_io_data: get cached information needed for range type I/O
304 : *
305 : * The range I/O functions need a bit more cached info than other range
306 : * functions, so they store a RangeIOData struct in fn_extra, not just a
307 : * pointer to a type cache entry.
308 : */
309 : static RangeIOData *
4163 tgl 310 GBC 53532 : get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func)
311 : {
4163 tgl 312 GIC 53532 : RangeIOData *cache = (RangeIOData *) fcinfo->flinfo->fn_extra;
313 :
314 53532 : if (cache == NULL || cache->typcache->type_id != rngtypid)
315 : {
316 : int16 typlen;
317 : bool typbyval;
318 : char typalign;
319 : char typdelim;
320 : Oid typiofunc;
4163 tgl 321 ECB :
4163 tgl 322 GIC 2298 : cache = (RangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
4163 tgl 323 ECB : sizeof(RangeIOData));
4163 tgl 324 GIC 2298 : cache->typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
4163 tgl 325 CBC 2298 : if (cache->typcache->rngelemtype == NULL)
4163 tgl 326 UIC 0 : elog(ERROR, "type %u is not a range type", rngtypid);
327 :
328 : /* get_type_io_data does more than we need, but is convenient */
4163 tgl 329 GIC 2298 : get_type_io_data(cache->typcache->rngelemtype->type_id,
330 : func,
331 : &typlen,
332 : &typbyval,
4163 tgl 333 ECB : &typalign,
334 : &typdelim,
335 : &cache->typioparam,
1130 alvherre 336 : &typiofunc);
4163 tgl 337 EUB :
1130 alvherre 338 GIC 2298 : if (!OidIsValid(typiofunc))
339 : {
4163 tgl 340 ECB : /* this could only happen for receive or send */
4163 tgl 341 UIC 0 : if (func == IOFunc_receive)
342 0 : ereport(ERROR,
343 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
344 : errmsg("no binary input function available for type %s",
345 : format_type_be(cache->typcache->rngelemtype->type_id))));
346 : else
347 0 : ereport(ERROR,
348 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2118 tgl 349 ECB : errmsg("no binary output function available for type %s",
350 : format_type_be(cache->typcache->rngelemtype->type_id))));
351 : }
1130 alvherre 352 GBC 2298 : fmgr_info_cxt(typiofunc, &cache->typioproc,
4163 tgl 353 2298 : fcinfo->flinfo->fn_mcxt);
354 :
4163 tgl 355 GIC 2298 : fcinfo->flinfo->fn_extra = (void *) cache;
356 : }
357 :
4163 tgl 358 GBC 53532 : return cache;
359 : }
360 :
361 :
362 : /*
4175 heikki.linnakangas 363 ECB : *----------------------------------------------------------
364 : * GENERIC FUNCTIONS
365 : *----------------------------------------------------------
366 : */
367 :
368 : /* Construct standard-form range value from two arguments */
369 : Datum
4175 heikki.linnakangas 370 GIC 53973 : range_constructor2(PG_FUNCTION_ARGS)
371 : {
4164 bruce 372 53973 : Datum arg1 = PG_GETARG_DATUM(0);
373 53973 : Datum arg2 = PG_GETARG_DATUM(1);
374 53973 : Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
375 : RangeType *range;
376 : TypeCacheEntry *typcache;
377 : RangeBound lower;
378 : RangeBound upper;
379 :
4163 tgl 380 53973 : typcache = range_get_typcache(fcinfo, rngtypid);
4163 tgl 381 ECB :
4164 bruce 382 GIC 53973 : lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
4164 bruce 383 CBC 53973 : lower.infinite = PG_ARGISNULL(0);
4163 tgl 384 53973 : lower.inclusive = true;
4164 bruce 385 53973 : lower.lower = true;
386 :
4164 bruce 387 GIC 53973 : upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
388 53973 : upper.infinite = PG_ARGISNULL(1);
4163 tgl 389 53973 : upper.inclusive = false;
4164 bruce 390 53973 : upper.lower = false;
4175 heikki.linnakangas 391 ECB :
115 tgl 392 GNC 53973 : range = make_range(typcache, &lower, &upper, false, NULL);
4175 heikki.linnakangas 393 ECB :
2029 tgl 394 CBC 53955 : PG_RETURN_RANGE_P(range);
4175 heikki.linnakangas 395 ECB : }
396 :
397 : /* Construct general range value from three arguments */
398 : Datum
4175 heikki.linnakangas 399 CBC 2559 : range_constructor3(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 400 ECB : {
4164 bruce 401 CBC 2559 : Datum arg1 = PG_GETARG_DATUM(0);
4164 bruce 402 GIC 2559 : Datum arg2 = PG_GETARG_DATUM(1);
4164 bruce 403 CBC 2559 : Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
404 : RangeType *range;
4163 tgl 405 ECB : TypeCacheEntry *typcache;
406 : RangeBound lower;
407 : RangeBound upper;
408 : char flags;
409 :
4163 tgl 410 CBC 2559 : typcache = range_get_typcache(fcinfo, rngtypid);
411 :
4175 heikki.linnakangas 412 2559 : if (PG_ARGISNULL(2))
4175 heikki.linnakangas 413 LBC 0 : ereport(ERROR,
4175 heikki.linnakangas 414 ECB : (errcode(ERRCODE_DATA_EXCEPTION),
415 : errmsg("range constructor flags argument must not be null")));
416 :
2219 noah 417 GIC 2559 : flags = range_parse_flags(text_to_cstring(PG_GETARG_TEXT_PP(2)));
418 :
4164 bruce 419 2559 : lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
420 2559 : lower.infinite = PG_ARGISNULL(0);
4163 tgl 421 CBC 2559 : lower.inclusive = (flags & RANGE_LB_INC) != 0;
4164 bruce 422 GIC 2559 : lower.lower = true;
4175 heikki.linnakangas 423 ECB :
4164 bruce 424 GBC 2559 : upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
4164 bruce 425 GIC 2559 : upper.infinite = PG_ARGISNULL(1);
4163 tgl 426 2559 : upper.inclusive = (flags & RANGE_UB_INC) != 0;
4164 bruce 427 2559 : upper.lower = false;
4175 heikki.linnakangas 428 ECB :
115 tgl 429 GNC 2559 : range = make_range(typcache, &lower, &upper, false, NULL);
4175 heikki.linnakangas 430 ECB :
2029 tgl 431 CBC 2559 : PG_RETURN_RANGE_P(range);
4175 heikki.linnakangas 432 ECB : }
433 :
434 :
4156 tgl 435 : /* range -> subtype functions */
436 :
437 : /* extract lower bound value */
4175 heikki.linnakangas 438 : Datum
4175 heikki.linnakangas 439 GIC 120 : range_lower(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 440 ECB : {
2029 tgl 441 GIC 120 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 442 ECB : TypeCacheEntry *typcache;
443 : RangeBound lower;
444 : RangeBound upper;
445 : bool empty;
446 :
4163 tgl 447 GIC 120 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
448 :
449 120 : range_deserialize(typcache, r1, &lower, &upper, &empty);
4175 heikki.linnakangas 450 ECB :
451 : /* Return NULL if there's no finite lower bound */
4164 tgl 452 CBC 120 : if (empty || lower.infinite)
4164 tgl 453 GIC 18 : PG_RETURN_NULL();
454 :
4175 heikki.linnakangas 455 102 : PG_RETURN_DATUM(lower.val);
456 : }
457 :
4156 tgl 458 ECB : /* extract upper bound value */
459 : Datum
4175 heikki.linnakangas 460 CBC 114 : range_upper(PG_FUNCTION_ARGS)
461 : {
2029 tgl 462 GIC 114 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 463 ECB : TypeCacheEntry *typcache;
4164 bruce 464 : RangeBound lower;
465 : RangeBound upper;
466 : bool empty;
467 :
4163 tgl 468 GIC 114 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
469 :
470 114 : range_deserialize(typcache, r1, &lower, &upper, &empty);
4175 heikki.linnakangas 471 ECB :
472 : /* Return NULL if there's no finite upper bound */
4164 tgl 473 CBC 114 : if (empty || upper.infinite)
4164 tgl 474 GIC 18 : PG_RETURN_NULL();
475 :
4175 heikki.linnakangas 476 96 : PG_RETURN_DATUM(upper.val);
477 : }
478 :
4175 heikki.linnakangas 479 ECB :
480 : /* range -> bool functions */
4156 tgl 481 :
482 : /* is range empty? */
483 : Datum
4175 heikki.linnakangas 484 CBC 1098 : range_empty(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 485 ECB : {
2029 tgl 486 GIC 1098 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 487 CBC 1098 : char flags = range_get_flags(r1);
488 :
4163 tgl 489 GIC 1098 : PG_RETURN_BOOL(flags & RANGE_EMPTY);
490 : }
491 :
492 : /* is lower bound inclusive? */
493 : Datum
4175 heikki.linnakangas 494 36 : range_lower_inc(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 495 ECB : {
2029 tgl 496 GIC 36 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 497 CBC 36 : char flags = range_get_flags(r1);
4175 heikki.linnakangas 498 ECB :
4163 tgl 499 GIC 36 : PG_RETURN_BOOL(flags & RANGE_LB_INC);
4175 heikki.linnakangas 500 ECB : }
501 :
502 : /* is upper bound inclusive? */
503 : Datum
4175 heikki.linnakangas 504 GIC 36 : range_upper_inc(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 505 ECB : {
2029 tgl 506 GIC 36 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 507 CBC 36 : char flags = range_get_flags(r1);
4175 heikki.linnakangas 508 ECB :
4163 tgl 509 GIC 36 : PG_RETURN_BOOL(flags & RANGE_UB_INC);
4175 heikki.linnakangas 510 ECB : }
511 :
512 : /* is lower bound infinite? */
513 : Datum
4175 heikki.linnakangas 514 GIC 36 : range_lower_inf(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 515 ECB : {
2029 tgl 516 GIC 36 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 517 CBC 36 : char flags = range_get_flags(r1);
4175 heikki.linnakangas 518 ECB :
4163 tgl 519 GIC 36 : PG_RETURN_BOOL(flags & RANGE_LB_INF);
4175 heikki.linnakangas 520 ECB : }
521 :
522 : /* is upper bound infinite? */
523 : Datum
4175 heikki.linnakangas 524 GIC 36 : range_upper_inf(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 525 ECB : {
2029 tgl 526 GIC 36 : RangeType *r1 = PG_GETARG_RANGE_P(0);
4163 tgl 527 CBC 36 : char flags = range_get_flags(r1);
4175 heikki.linnakangas 528 ECB :
4163 tgl 529 GIC 36 : PG_RETURN_BOOL(flags & RANGE_UB_INF);
4175 heikki.linnakangas 530 ECB : }
531 :
532 :
533 : /* range, element -> bool functions */
534 :
4156 tgl 535 : /* contains? */
536 : Datum
4156 tgl 537 CBC 38019 : range_contains_elem(PG_FUNCTION_ARGS)
4156 tgl 538 ECB : {
2029 tgl 539 GIC 38019 : RangeType *r = PG_GETARG_RANGE_P(0);
4156 tgl 540 CBC 38019 : Datum val = PG_GETARG_DATUM(1);
541 : TypeCacheEntry *typcache;
542 :
4156 tgl 543 GIC 38019 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
544 :
545 38019 : PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
546 : }
547 :
4156 tgl 548 ECB : /* contained by? */
549 : Datum
4156 tgl 550 CBC 342 : elem_contained_by_range(PG_FUNCTION_ARGS)
4156 tgl 551 ECB : {
4156 tgl 552 GIC 342 : Datum val = PG_GETARG_DATUM(0);
2029 553 342 : RangeType *r = PG_GETARG_RANGE_P(1);
4156 tgl 554 ECB : TypeCacheEntry *typcache;
555 :
4156 tgl 556 CBC 342 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
557 :
4156 tgl 558 GIC 342 : PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
559 : }
560 :
4156 tgl 561 ECB :
562 : /* range, range -> bool functions */
563 :
3917 heikki.linnakangas 564 : /* equality (internal version) */
565 : bool
1256 peter 566 GIC 89394 : range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
4175 heikki.linnakangas 567 ECB : {
568 : RangeBound lower1,
4164 bruce 569 : lower2;
570 : RangeBound upper1,
571 : upper2;
572 : bool empty1,
573 : empty2;
574 :
575 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 576 GIC 89394 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 577 LBC 0 : elog(ERROR, "range types do not match");
578 :
4163 tgl 579 GIC 89394 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
580 89394 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
581 :
4175 heikki.linnakangas 582 89394 : if (empty1 && empty2)
3917 583 6231 : return true;
4175 584 83163 : if (empty1 != empty2)
3917 585 6756 : return false;
586 :
4163 tgl 587 CBC 76407 : if (range_cmp_bounds(typcache, &lower1, &lower2) != 0)
3917 heikki.linnakangas 588 GBC 36252 : return false;
589 :
4163 tgl 590 CBC 40155 : if (range_cmp_bounds(typcache, &upper1, &upper2) != 0)
3917 heikki.linnakangas 591 25171 : return false;
592 :
593 14984 : return true;
3917 heikki.linnakangas 594 ECB : }
4175 595 :
3917 596 : /* equality */
597 : Datum
3917 heikki.linnakangas 598 CBC 38622 : range_eq(PG_FUNCTION_ARGS)
3917 heikki.linnakangas 599 ECB : {
2029 tgl 600 GIC 38622 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 601 CBC 38622 : RangeType *r2 = PG_GETARG_RANGE_P(1);
3917 heikki.linnakangas 602 ECB : TypeCacheEntry *typcache;
603 :
3917 heikki.linnakangas 604 CBC 38622 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
605 :
3917 heikki.linnakangas 606 GIC 38622 : PG_RETURN_BOOL(range_eq_internal(typcache, r1, r2));
607 : }
608 :
3917 heikki.linnakangas 609 ECB : /* inequality (internal version) */
610 : bool
1256 peter 611 LBC 0 : range_ne_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 612 ECB : {
3917 heikki.linnakangas 613 UIC 0 : return (!range_eq_internal(typcache, r1, r2));
614 : }
4175 heikki.linnakangas 615 ECB :
616 : /* inequality */
617 : Datum
4175 heikki.linnakangas 618 UIC 0 : range_ne(PG_FUNCTION_ARGS)
619 : {
2029 tgl 620 0 : RangeType *r1 = PG_GETARG_RANGE_P(0);
621 0 : RangeType *r2 = PG_GETARG_RANGE_P(1);
3917 heikki.linnakangas 622 EUB : TypeCacheEntry *typcache;
623 :
3917 heikki.linnakangas 624 UBC 0 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
625 :
3917 heikki.linnakangas 626 UIC 0 : PG_RETURN_BOOL(range_ne_internal(typcache, r1, r2));
627 : }
628 :
4156 tgl 629 EUB : /* contains? */
630 : Datum
4175 heikki.linnakangas 631 GBC 77235 : range_contains(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 632 EUB : {
2029 tgl 633 GIC 77235 : RangeType *r1 = PG_GETARG_RANGE_P(0);
634 77235 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 635 EUB : TypeCacheEntry *typcache;
636 :
4163 tgl 637 GBC 77235 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
638 :
4163 tgl 639 GIC 77235 : PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
640 : }
641 :
4156 tgl 642 ECB : /* contained by? */
643 : Datum
4175 heikki.linnakangas 644 CBC 38454 : range_contained_by(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 645 ECB : {
2029 tgl 646 GIC 38454 : RangeType *r1 = PG_GETARG_RANGE_P(0);
647 38454 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 648 ECB : TypeCacheEntry *typcache;
649 :
4163 tgl 650 CBC 38454 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
651 :
3917 heikki.linnakangas 652 GIC 38454 : PG_RETURN_BOOL(range_contained_by_internal(typcache, r1, r2));
653 : }
654 :
3917 heikki.linnakangas 655 ECB : /* strictly left of? (internal version) */
656 : bool
1256 peter 657 CBC 62944 : range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
4175 heikki.linnakangas 658 ECB : {
659 : RangeBound lower1,
660 : lower2;
4164 bruce 661 : RangeBound upper1,
662 : upper2;
663 : bool empty1,
664 : empty2;
665 :
666 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 667 GIC 62944 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 668 LBC 0 : elog(ERROR, "range types do not match");
669 :
4163 tgl 670 GIC 62944 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
671 62944 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
672 :
673 : /* An empty range is neither before nor after any other range */
4175 heikki.linnakangas 674 62944 : if (empty1 || empty2)
3917 675 7455 : return false;
676 :
677 55489 : return (range_cmp_bounds(typcache, &upper1, &lower2) < 0);
4175 heikki.linnakangas 678 ECB : }
4175 heikki.linnakangas 679 EUB :
680 : /* strictly left of? */
4175 heikki.linnakangas 681 ECB : Datum
3917 heikki.linnakangas 682 CBC 39459 : range_before(PG_FUNCTION_ARGS)
683 : {
2029 tgl 684 GIC 39459 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 685 CBC 39459 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 686 ECB : TypeCacheEntry *typcache;
687 :
3917 heikki.linnakangas 688 CBC 39459 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
689 :
3917 heikki.linnakangas 690 GIC 39459 : PG_RETURN_BOOL(range_before_internal(typcache, r1, r2));
691 : }
692 :
3917 heikki.linnakangas 693 ECB : /* strictly right of? (internal version) */
694 : bool
1256 peter 695 CBC 98402 : range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 696 ECB : {
697 : RangeBound lower1,
698 : lower2;
4164 bruce 699 : RangeBound upper1,
700 : upper2;
701 : bool empty1,
702 : empty2;
703 :
704 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 705 GIC 98402 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 706 LBC 0 : elog(ERROR, "range types do not match");
707 :
4163 tgl 708 GIC 98402 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
709 98402 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
710 :
711 : /* An empty range is neither before nor after any other range */
4175 heikki.linnakangas 712 98402 : if (empty1 || empty2)
3917 713 7155 : return false;
714 :
715 91247 : return (range_cmp_bounds(typcache, &lower1, &upper2) > 0);
4175 heikki.linnakangas 716 ECB : }
4175 heikki.linnakangas 717 EUB :
718 : /* strictly right of? */
4164 bruce 719 ECB : Datum
3917 heikki.linnakangas 720 CBC 39153 : range_after(PG_FUNCTION_ARGS)
721 : {
2029 tgl 722 GIC 39153 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 723 CBC 39153 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 724 ECB : TypeCacheEntry *typcache;
725 :
3917 heikki.linnakangas 726 CBC 39153 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
727 :
3917 heikki.linnakangas 728 GIC 39153 : PG_RETURN_BOOL(range_after_internal(typcache, r1, r2));
729 : }
730 :
3684 heikki.linnakangas 731 ECB : /*
732 : * Check if two bounds A and B are "adjacent", where A is an upper bound and B
733 : * is a lower bound. For the bounds to be adjacent, each subtype value must
734 : * satisfy strictly one of the bounds: there are no values which satisfy both
735 : * bounds (i.e. less than A and greater than B); and there are no values which
736 : * satisfy neither bound (i.e. greater than A and less than B).
737 : *
738 : * For discrete ranges, we rely on the canonicalization function to see if A..B
739 : * normalizes to empty. (If there is no canonicalization function, it's
740 : * impossible for such a range to normalize to empty, so we needn't bother to
741 : * try.)
742 : *
743 : * If A == B, the ranges are adjacent only if the bounds have different
744 : * inclusive flags (i.e., exactly one of the ranges includes the common
745 : * boundary point).
746 : *
747 : * And if A > B then the ranges are not adjacent in this order.
748 : */
749 : bool
3684 heikki.linnakangas 750 GIC 236310 : bounds_adjacent(TypeCacheEntry *typcache, RangeBound boundA, RangeBound boundB)
751 : {
752 : int cmp;
753 :
754 236310 : Assert(!boundA.lower && boundB.lower);
755 :
756 236310 : cmp = range_cmp_bound_values(typcache, &boundA, &boundB);
757 236310 : if (cmp < 0)
758 : {
759 : RangeType *r;
760 :
3684 heikki.linnakangas 761 ECB : /*
762 : * Bounds do not overlap; see if there are points in between.
763 : */
764 :
765 : /* in a continuous subtype, there are assumed to be points between */
3684 heikki.linnakangas 766 GIC 72527 : if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
3684 heikki.linnakangas 767 CBC 408 : return false;
3684 heikki.linnakangas 768 ECB :
769 : /*
770 : * The bounds are of a discrete range type; so make a range A..B and
771 : * see if it's empty.
772 : */
773 :
774 : /* flip the inclusion flags */
3684 heikki.linnakangas 775 GIC 72119 : boundA.inclusive = !boundA.inclusive;
776 72119 : boundB.inclusive = !boundB.inclusive;
3684 heikki.linnakangas 777 ECB : /* change upper/lower labels to avoid Assert failures */
3684 heikki.linnakangas 778 CBC 72119 : boundA.lower = true;
3684 heikki.linnakangas 779 GIC 72119 : boundB.lower = false;
115 tgl 780 GNC 72119 : r = make_range(typcache, &boundA, &boundB, false, NULL);
3684 heikki.linnakangas 781 GIC 72119 : return RangeIsEmpty(r);
782 : }
783 163783 : else if (cmp == 0)
784 873 : return boundA.inclusive != boundB.inclusive;
785 : else
3602 bruce 786 CBC 162910 : return false; /* bounds overlap */
3684 heikki.linnakangas 787 ECB : }
788 :
3917 789 : /* adjacent to (but not overlapping)? (internal version) */
790 : bool
1256 peter 791 CBC 71402 : range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 792 ECB : {
793 : RangeBound lower1,
4164 bruce 794 : lower2;
795 : RangeBound upper1,
796 : upper2;
797 : bool empty1,
798 : empty2;
799 :
800 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 801 GIC 71402 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 802 LBC 0 : elog(ERROR, "range types do not match");
803 :
4163 tgl 804 GIC 71402 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
805 71402 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
806 :
807 : /* An empty range is not adjacent to any other range */
4175 heikki.linnakangas 808 71402 : if (empty1 || empty2)
3917 809 6000 : return false;
810 :
811 : /*
3684 heikki.linnakangas 812 ECB : * Given two ranges A..B and C..D, the ranges are adjacent if and only if
3684 heikki.linnakangas 813 EUB : * B is adjacent to C, or D is adjacent to A.
814 : */
3684 heikki.linnakangas 815 CBC 130123 : return (bounds_adjacent(typcache, upper1, lower2) ||
816 64721 : bounds_adjacent(typcache, upper2, lower1));
817 : }
818 :
3917 heikki.linnakangas 819 ECB : /* adjacent to (but not overlapping)? */
4175 820 : Datum
3917 heikki.linnakangas 821 GIC 37218 : range_adjacent(PG_FUNCTION_ARGS)
822 : {
2029 tgl 823 37218 : RangeType *r1 = PG_GETARG_RANGE_P(0);
824 37218 : RangeType *r2 = PG_GETARG_RANGE_P(1);
825 : TypeCacheEntry *typcache;
3917 heikki.linnakangas 826 ECB :
3917 heikki.linnakangas 827 CBC 37218 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
828 :
3917 heikki.linnakangas 829 GIC 37218 : PG_RETURN_BOOL(range_adjacent_internal(typcache, r1, r2));
830 : }
831 :
3917 heikki.linnakangas 832 ECB : /* overlaps? (internal version) */
833 : bool
1256 peter 834 CBC 48353 : range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 835 ECB : {
836 : RangeBound lower1,
837 : lower2;
4164 bruce 838 : RangeBound upper1,
839 : upper2;
840 : bool empty1,
841 : empty2;
842 :
843 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 844 GIC 48353 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 845 LBC 0 : elog(ERROR, "range types do not match");
846 :
4163 tgl 847 GIC 48353 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
848 48353 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
849 :
850 : /* An empty range does not overlap any other range */
4175 heikki.linnakangas 851 48353 : if (empty1 || empty2)
3917 852 7044 : return false;
853 :
4163 tgl 854 79669 : if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 &&
4163 tgl 855 CBC 38360 : range_cmp_bounds(typcache, &lower1, &upper2) <= 0)
3917 heikki.linnakangas 856 GBC 1341 : return true;
857 :
4163 tgl 858 CBC 42917 : if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 &&
859 2949 : range_cmp_bounds(typcache, &lower2, &upper1) <= 0)
3917 heikki.linnakangas 860 GIC 2901 : return true;
861 :
3917 heikki.linnakangas 862 CBC 37067 : return false;
4175 heikki.linnakangas 863 ECB : }
864 :
3917 865 : /* overlaps? */
4175 866 : Datum
3917 heikki.linnakangas 867 CBC 38705 : range_overlaps(PG_FUNCTION_ARGS)
868 : {
2029 tgl 869 38705 : RangeType *r1 = PG_GETARG_RANGE_P(0);
870 38705 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 871 ECB : TypeCacheEntry *typcache;
872 :
3917 heikki.linnakangas 873 CBC 38705 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
874 :
3917 heikki.linnakangas 875 GIC 38705 : PG_RETURN_BOOL(range_overlaps_internal(typcache, r1, r2));
876 : }
877 :
3917 heikki.linnakangas 878 ECB : /* does not extend to right of? (internal version) */
879 : bool
1256 peter 880 CBC 65695 : range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 881 ECB : {
882 : RangeBound lower1,
883 : lower2;
4164 bruce 884 : RangeBound upper1,
885 : upper2;
886 : bool empty1,
887 : empty2;
888 :
889 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 890 GIC 65695 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 891 LBC 0 : elog(ERROR, "range types do not match");
892 :
4163 tgl 893 GIC 65695 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
894 65695 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
895 :
896 : /* An empty range is neither before nor after any other range */
4175 heikki.linnakangas 897 65695 : if (empty1 || empty2)
3917 898 6573 : return false;
899 :
4163 tgl 900 59122 : if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
3917 heikki.linnakangas 901 CBC 20309 : return true;
4175 heikki.linnakangas 902 EUB :
3917 heikki.linnakangas 903 GIC 38813 : return false;
4175 heikki.linnakangas 904 ECB : }
905 :
906 : /* does not extend to right of? */
907 : Datum
3917 heikki.linnakangas 908 CBC 38253 : range_overleft(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 909 ECB : {
2029 tgl 910 GIC 38253 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 911 CBC 38253 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 912 ECB : TypeCacheEntry *typcache;
913 :
3917 heikki.linnakangas 914 CBC 38253 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
915 :
3917 heikki.linnakangas 916 GIC 38253 : PG_RETURN_BOOL(range_overleft_internal(typcache, r1, r2));
917 : }
918 :
3917 heikki.linnakangas 919 ECB : /* does not extend to left of? (internal version) */
920 : bool
1256 peter 921 CBC 109035 : range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 922 ECB : {
923 : RangeBound lower1,
924 : lower2;
4164 bruce 925 : RangeBound upper1,
926 : upper2;
927 : bool empty1,
928 : empty2;
929 :
930 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 931 GIC 109035 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 932 LBC 0 : elog(ERROR, "range types do not match");
933 :
4163 tgl 934 GIC 109035 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
935 109035 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
936 :
937 : /* An empty range is neither before nor after any other range */
4175 heikki.linnakangas 938 109035 : if (empty1 || empty2)
3158 tgl 939 6573 : return false;
940 :
4163 941 102462 : if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
3158 tgl 942 CBC 95487 : return true;
4175 heikki.linnakangas 943 EUB :
3158 tgl 944 GIC 6975 : return false;
4175 heikki.linnakangas 945 ECB : }
946 :
947 : /* does not extend to left of? */
948 : Datum
3917 heikki.linnakangas 949 CBC 38250 : range_overright(PG_FUNCTION_ARGS)
3917 heikki.linnakangas 950 ECB : {
2029 tgl 951 GIC 38250 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 952 CBC 38250 : RangeType *r2 = PG_GETARG_RANGE_P(1);
3917 heikki.linnakangas 953 ECB : TypeCacheEntry *typcache;
954 :
3917 heikki.linnakangas 955 CBC 38250 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
956 :
3917 heikki.linnakangas 957 GIC 38250 : PG_RETURN_BOOL(range_overright_internal(typcache, r1, r2));
958 : }
959 :
4175 heikki.linnakangas 960 ECB :
961 : /* range, range -> range functions */
4156 tgl 962 :
963 : /* set difference */
964 : Datum
4175 heikki.linnakangas 965 GIC 15 : range_minus(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 966 ECB : {
2029 tgl 967 GIC 15 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 968 CBC 15 : RangeType *r2 = PG_GETARG_RANGE_P(1);
969 : RangeType *ret;
970 : TypeCacheEntry *typcache;
971 :
972 : /* Different types should be prevented by ANYRANGE matching rules */
840 akorotkov 973 GIC 15 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
840 akorotkov 974 UIC 0 : elog(ERROR, "range types do not match");
975 :
840 akorotkov 976 CBC 15 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
977 :
978 15 : ret = range_minus_internal(typcache, r1, r2);
979 15 : if (ret)
840 akorotkov 980 GIC 15 : PG_RETURN_RANGE_P(ret);
981 : else
840 akorotkov 982 UIC 0 : PG_RETURN_NULL();
983 : }
840 akorotkov 984 ECB :
840 akorotkov 985 EUB : RangeType *
840 akorotkov 986 GIC 48 : range_minus_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
840 akorotkov 987 ECB : {
988 : RangeBound lower1,
4164 bruce 989 : lower2;
990 : RangeBound upper1,
991 : upper2;
992 : bool empty1,
4164 bruce 993 EUB : empty2;
994 : int cmp_l1l2,
995 : cmp_l1u2,
996 : cmp_u1l2,
4164 bruce 997 ECB : cmp_u1u2;
998 :
4163 tgl 999 GIC 48 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
1000 48 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
1001 :
1002 : /* if either is empty, r1 is the correct answer */
4175 heikki.linnakangas 1003 48 : if (empty1 || empty2)
840 akorotkov 1004 UIC 0 : return r1;
1005 :
4163 tgl 1006 GIC 48 : cmp_l1l2 = range_cmp_bounds(typcache, &lower1, &lower2);
1007 48 : cmp_l1u2 = range_cmp_bounds(typcache, &lower1, &upper2);
1008 48 : cmp_u1l2 = range_cmp_bounds(typcache, &upper1, &lower2);
1009 48 : cmp_u1u2 = range_cmp_bounds(typcache, &upper1, &upper2);
4175 heikki.linnakangas 1010 ECB :
4175 heikki.linnakangas 1011 CBC 48 : if (cmp_l1l2 < 0 && cmp_u1u2 > 0)
4175 heikki.linnakangas 1012 UIC 0 : ereport(ERROR,
1013 : (errcode(ERRCODE_DATA_EXCEPTION),
2118 tgl 1014 ECB : errmsg("result of range difference would not be contiguous")));
4175 heikki.linnakangas 1015 EUB :
4175 heikki.linnakangas 1016 GIC 48 : if (cmp_l1u2 > 0 || cmp_u1l2 < 0)
840 akorotkov 1017 CBC 6 : return r1;
4175 heikki.linnakangas 1018 ECB :
4175 heikki.linnakangas 1019 CBC 42 : if (cmp_l1l2 >= 0 && cmp_u1u2 <= 0)
840 akorotkov 1020 21 : return make_empty_range(typcache);
1021 :
4175 heikki.linnakangas 1022 21 : if (cmp_l1l2 <= 0 && cmp_u1l2 >= 0 && cmp_u1u2 <= 0)
4175 heikki.linnakangas 1023 EUB : {
4175 heikki.linnakangas 1024 GIC 12 : lower2.inclusive = !lower2.inclusive;
4164 bruce 1025 12 : lower2.lower = false; /* it will become the upper bound */
115 tgl 1026 GNC 12 : return make_range(typcache, &lower1, &lower2, false, NULL);
4175 heikki.linnakangas 1027 ECB : }
1028 :
4175 heikki.linnakangas 1029 GIC 9 : if (cmp_l1l2 >= 0 && cmp_u1u2 >= 0 && cmp_l1u2 <= 0)
4175 heikki.linnakangas 1030 ECB : {
4175 heikki.linnakangas 1031 CBC 9 : upper2.inclusive = !upper2.inclusive;
4164 bruce 1032 GIC 9 : upper2.lower = true; /* it will become the lower bound */
115 tgl 1033 GNC 9 : return make_range(typcache, &upper2, &upper1, false, NULL);
1034 : }
4175 heikki.linnakangas 1035 ECB :
4164 tgl 1036 LBC 0 : elog(ERROR, "unexpected case in range_minus");
840 akorotkov 1037 ECB : return NULL;
1038 : }
1039 :
2896 alvherre 1040 : /*
1041 : * Set union. If strict is true, it is an error that the two input ranges
1042 : * are not adjacent or overlapping.
1043 : */
840 akorotkov 1044 : RangeType *
2896 alvherre 1045 GIC 714 : range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
1046 : bool strict)
4175 heikki.linnakangas 1047 EUB : {
1048 : RangeBound lower1,
1049 : lower2;
1050 : RangeBound upper1,
1051 : upper2;
1052 : bool empty1,
1053 : empty2;
1054 : RangeBound *result_lower;
1055 : RangeBound *result_upper;
4175 heikki.linnakangas 1056 ECB :
1057 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 1058 GIC 714 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4164 tgl 1059 UIC 0 : elog(ERROR, "range types do not match");
1060 :
4163 tgl 1061 GIC 714 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
1062 714 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
1063 :
1064 : /* if either is empty, the other is the correct answer */
4175 heikki.linnakangas 1065 714 : if (empty1)
2896 alvherre 1066 3 : return r2;
4175 heikki.linnakangas 1067 711 : if (empty2)
2896 alvherre 1068 UIC 0 : return r1;
4175 heikki.linnakangas 1069 ECB :
2896 alvherre 1070 GBC 711 : if (strict &&
2896 alvherre 1071 GIC 69 : !DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
2896 alvherre 1072 CBC 6 : !DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
4175 heikki.linnakangas 1073 3 : ereport(ERROR,
1074 : (errcode(ERRCODE_DATA_EXCEPTION),
1075 : errmsg("result of range union would not be contiguous")));
4175 heikki.linnakangas 1076 ECB :
4163 tgl 1077 CBC 708 : if (range_cmp_bounds(typcache, &lower1, &lower2) < 0)
4175 heikki.linnakangas 1078 690 : result_lower = &lower1;
4175 heikki.linnakangas 1079 EUB : else
4175 heikki.linnakangas 1080 GIC 18 : result_lower = &lower2;
4175 heikki.linnakangas 1081 ECB :
4163 tgl 1082 CBC 708 : if (range_cmp_bounds(typcache, &upper1, &upper2) > 0)
4175 heikki.linnakangas 1083 24 : result_upper = &upper1;
4175 heikki.linnakangas 1084 ECB : else
4175 heikki.linnakangas 1085 GIC 684 : result_upper = &upper2;
1086 :
115 tgl 1087 GNC 708 : return make_range(typcache, result_lower, result_upper, false, NULL);
2896 alvherre 1088 ECB : }
1089 :
1090 : Datum
2896 alvherre 1091 CBC 9 : range_union(PG_FUNCTION_ARGS)
1092 : {
2029 tgl 1093 9 : RangeType *r1 = PG_GETARG_RANGE_P(0);
1094 9 : RangeType *r2 = PG_GETARG_RANGE_P(1);
1095 : TypeCacheEntry *typcache;
2896 alvherre 1096 ECB :
2896 alvherre 1097 GIC 9 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
2896 alvherre 1098 ECB :
2029 tgl 1099 GIC 9 : PG_RETURN_RANGE_P(range_union_internal(typcache, r1, r2, true));
1100 : }
1101 :
2896 alvherre 1102 ECB : /*
1103 : * range merge: like set union, except also allow and account for non-adjacent
1104 : * input ranges.
1105 : */
1106 : Datum
2896 alvherre 1107 GIC 15 : range_merge(PG_FUNCTION_ARGS)
2896 alvherre 1108 ECB : {
2029 tgl 1109 GIC 15 : RangeType *r1 = PG_GETARG_RANGE_P(0);
2029 tgl 1110 CBC 15 : RangeType *r2 = PG_GETARG_RANGE_P(1);
1111 : TypeCacheEntry *typcache;
1112 :
2896 alvherre 1113 GIC 15 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
1114 :
2029 tgl 1115 15 : PG_RETURN_RANGE_P(range_union_internal(typcache, r1, r2, false));
1116 : }
1117 :
4156 tgl 1118 ECB : /* set intersection */
1119 : Datum
4175 heikki.linnakangas 1120 CBC 9 : range_intersect(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 1121 ECB : {
2029 tgl 1122 GIC 9 : RangeType *r1 = PG_GETARG_RANGE_P(0);
1123 9 : RangeType *r2 = PG_GETARG_RANGE_P(1);
4163 tgl 1124 ECB : TypeCacheEntry *typcache;
1125 :
840 akorotkov 1126 : /* Different types should be prevented by ANYRANGE matching rules */
840 akorotkov 1127 GIC 9 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
840 akorotkov 1128 UIC 0 : elog(ERROR, "range types do not match");
1129 :
840 akorotkov 1130 GIC 9 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
840 akorotkov 1131 ECB :
840 akorotkov 1132 GIC 9 : PG_RETURN_RANGE_P(range_intersect_internal(typcache, r1, r2));
840 akorotkov 1133 ECB : }
1134 :
1135 : RangeType *
840 akorotkov 1136 GIC 108 : range_intersect_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
1137 : {
4164 bruce 1138 ECB : RangeBound lower1,
4164 bruce 1139 EUB : lower2;
1140 : RangeBound upper1,
4164 bruce 1141 ECB : upper2;
1142 : bool empty1,
1143 : empty2;
1144 : RangeBound *result_lower;
1145 : RangeBound *result_upper;
1146 :
4163 tgl 1147 CBC 108 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
4163 tgl 1148 GIC 108 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
1149 :
840 akorotkov 1150 108 : if (empty1 || empty2 || !range_overlaps_internal(typcache, r1, r2))
1151 15 : return make_empty_range(typcache);
1152 :
4163 tgl 1153 93 : if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
4175 heikki.linnakangas 1154 45 : result_lower = &lower1;
1155 : else
1156 48 : result_lower = &lower2;
1157 :
4163 tgl 1158 CBC 93 : if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
4175 heikki.linnakangas 1159 63 : result_upper = &upper1;
1160 : else
1161 30 : result_upper = &upper2;
4175 heikki.linnakangas 1162 ECB :
115 tgl 1163 GNC 93 : return make_range(typcache, result_lower, result_upper, false, NULL);
840 akorotkov 1164 ECB : }
1165 :
1166 : /* range, range -> range, range functions */
1167 :
1168 : /*
1169 : * range_split_internal - if r2 intersects the middle of r1, leaving non-empty
1170 : * ranges on both sides, then return true and set output1 and output2 to the
1171 : * results of r1 - r2 (in order). Otherwise return false and don't set output1
1172 : * or output2. Neither input range should be empty.
1173 : */
1174 : bool
840 akorotkov 1175 GIC 66 : range_split_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2,
1176 : RangeType **output1, RangeType **output2)
1177 : {
1178 : RangeBound lower1,
1179 : lower2;
1180 : RangeBound upper1,
1181 : upper2;
1182 : bool empty1,
1183 : empty2;
1184 :
1185 66 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
840 akorotkov 1186 CBC 66 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
1187 :
840 akorotkov 1188 GIC 105 : if (range_cmp_bounds(typcache, &lower1, &lower2) < 0 &&
1189 39 : range_cmp_bounds(typcache, &upper1, &upper2) > 0)
1190 : {
1191 : /*
1192 : * Need to invert inclusive/exclusive for the lower2 and upper2
1193 : * points. They can't be infinite though. We're allowed to overwrite
1194 : * these RangeBounds since they only exist locally.
1195 : */
840 akorotkov 1196 CBC 9 : lower2.inclusive = !lower2.inclusive;
1197 9 : lower2.lower = false;
840 akorotkov 1198 GIC 9 : upper2.inclusive = !upper2.inclusive;
840 akorotkov 1199 CBC 9 : upper2.lower = true;
840 akorotkov 1200 ECB :
115 tgl 1201 GNC 9 : *output1 = make_range(typcache, &lower1, &lower2, false, NULL);
1202 9 : *output2 = make_range(typcache, &upper2, &upper1, false, NULL);
840 akorotkov 1203 GIC 9 : return true;
1204 : }
1205 :
1206 57 : return false;
840 akorotkov 1207 ECB : }
1208 :
1209 : /* range -> range aggregate functions */
1210 :
1211 : Datum
840 akorotkov 1212 CBC 21 : range_intersect_agg_transfn(PG_FUNCTION_ARGS)
840 akorotkov 1213 ECB : {
1214 : MemoryContext aggContext;
1215 : Oid rngtypoid;
1216 : TypeCacheEntry *typcache;
1217 : RangeType *result;
1218 : RangeType *current;
1219 :
840 akorotkov 1220 GIC 21 : if (!AggCheckCallContext(fcinfo, &aggContext))
840 akorotkov 1221 UIC 0 : elog(ERROR, "range_intersect_agg_transfn called in non-aggregate context");
1222 :
840 akorotkov 1223 CBC 21 : rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
840 akorotkov 1224 GIC 21 : if (!type_is_range(rngtypoid))
375 peter 1225 UIC 0 : elog(ERROR, "range_intersect_agg must be called with a range");
1226 :
840 akorotkov 1227 GIC 21 : typcache = range_get_typcache(fcinfo, rngtypoid);
1228 :
1229 : /* strictness ensures these are non-null */
1230 21 : result = PG_GETARG_RANGE_P(0);
840 akorotkov 1231 CBC 21 : current = PG_GETARG_RANGE_P(1);
840 akorotkov 1232 EUB :
840 akorotkov 1233 GIC 21 : result = range_intersect_internal(typcache, result, current);
840 akorotkov 1234 CBC 21 : PG_RETURN_RANGE_P(result);
4175 heikki.linnakangas 1235 ECB : }
4175 heikki.linnakangas 1236 EUB :
1237 :
4175 heikki.linnakangas 1238 ECB : /* Btree support */
1239 :
1240 : /* btree comparator */
1241 : Datum
4175 heikki.linnakangas 1242 CBC 5511 : range_cmp(PG_FUNCTION_ARGS)
1243 : {
2029 tgl 1244 5511 : RangeType *r1 = PG_GETARG_RANGE_P(0);
1245 5511 : RangeType *r2 = PG_GETARG_RANGE_P(1);
1246 : TypeCacheEntry *typcache;
1247 : RangeBound lower1,
1248 : lower2;
1249 : RangeBound upper1,
1250 : upper2;
1251 : bool empty1,
1252 : empty2;
4164 bruce 1253 ECB : int cmp;
1254 :
2743 noah 1255 CBC 5511 : check_stack_depth(); /* recurses when subtype is a range type */
2743 noah 1256 ECB :
1257 : /* Different types should be prevented by ANYRANGE matching rules */
4163 tgl 1258 GIC 5511 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
4175 heikki.linnakangas 1259 UIC 0 : elog(ERROR, "range types do not match");
1260 :
4163 tgl 1261 GIC 5511 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
1262 :
1263 5511 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
1264 5511 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
1265 :
4164 tgl 1266 ECB : /* For b-tree use, empty ranges sort before all else */
4175 heikki.linnakangas 1267 GIC 5511 : if (empty1 && empty2)
3483 1268 1320 : cmp = 0;
4175 heikki.linnakangas 1269 CBC 4191 : else if (empty1)
3483 heikki.linnakangas 1270 GBC 1740 : cmp = -1;
4175 heikki.linnakangas 1271 GIC 2451 : else if (empty2)
3483 heikki.linnakangas 1272 CBC 1065 : cmp = 1;
1273 : else
3483 heikki.linnakangas 1274 ECB : {
3483 heikki.linnakangas 1275 CBC 1386 : cmp = range_cmp_bounds(typcache, &lower1, &lower2);
3483 heikki.linnakangas 1276 GIC 1386 : if (cmp == 0)
1277 54 : cmp = range_cmp_bounds(typcache, &upper1, &upper2);
3483 heikki.linnakangas 1278 ECB : }
4175 1279 :
3483 heikki.linnakangas 1280 CBC 5511 : PG_FREE_IF_COPY(r1, 0);
1281 5511 : PG_FREE_IF_COPY(r2, 1);
4175 heikki.linnakangas 1282 ECB :
3483 heikki.linnakangas 1283 CBC 5511 : PG_RETURN_INT32(cmp);
1284 : }
1285 :
4156 tgl 1286 ECB : /* inequality operators using the range_cmp function */
4175 heikki.linnakangas 1287 : Datum
4175 heikki.linnakangas 1288 CBC 669 : range_lt(PG_FUNCTION_ARGS)
1289 : {
4164 bruce 1290 GIC 669 : int cmp = range_cmp(fcinfo);
4164 bruce 1291 ECB :
4175 heikki.linnakangas 1292 CBC 669 : PG_RETURN_BOOL(cmp < 0);
1293 : }
4175 heikki.linnakangas 1294 ECB :
1295 : Datum
4175 heikki.linnakangas 1296 GIC 1506 : range_le(PG_FUNCTION_ARGS)
1297 : {
4164 bruce 1298 1506 : int cmp = range_cmp(fcinfo);
4164 bruce 1299 ECB :
4175 heikki.linnakangas 1300 GIC 1506 : PG_RETURN_BOOL(cmp <= 0);
4175 heikki.linnakangas 1301 ECB : }
1302 :
1303 : Datum
4175 heikki.linnakangas 1304 GIC 1518 : range_ge(PG_FUNCTION_ARGS)
1305 : {
4164 bruce 1306 1518 : int cmp = range_cmp(fcinfo);
4164 bruce 1307 ECB :
4175 heikki.linnakangas 1308 GIC 1518 : PG_RETURN_BOOL(cmp >= 0);
4175 heikki.linnakangas 1309 ECB : }
1310 :
1311 : Datum
4175 heikki.linnakangas 1312 GIC 1536 : range_gt(PG_FUNCTION_ARGS)
1313 : {
4164 bruce 1314 1536 : int cmp = range_cmp(fcinfo);
4164 bruce 1315 ECB :
4175 heikki.linnakangas 1316 GIC 1536 : PG_RETURN_BOOL(cmp > 0);
4175 heikki.linnakangas 1317 ECB : }
1318 :
1319 : /* Hash support */
1320 :
1321 : /* hash a range value */
1322 : Datum
4175 heikki.linnakangas 1323 CBC 105 : hash_range(PG_FUNCTION_ARGS)
1324 : {
2029 tgl 1325 105 : RangeType *r = PG_GETARG_RANGE_P(0);
1326 : uint32 result;
4163 tgl 1327 ECB : TypeCacheEntry *typcache;
1328 : TypeCacheEntry *scache;
1329 : RangeBound lower;
1330 : RangeBound upper;
1331 : bool empty;
1332 : char flags;
1333 : uint32 lower_hash;
1334 : uint32 upper_hash;
1335 :
2743 noah 1336 CBC 105 : check_stack_depth(); /* recurses when subtype is a range type */
1337 :
4163 tgl 1338 GIC 105 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
1339 :
1340 : /* deserialize */
1341 105 : range_deserialize(typcache, r, &lower, &upper, &empty);
1342 105 : flags = range_get_flags(r);
1343 :
1344 : /*
1345 : * Look up the element type's hash function, if not done already.
1346 : */
4163 tgl 1347 CBC 105 : scache = typcache->rngelemtype;
4163 tgl 1348 GIC 105 : if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
4175 heikki.linnakangas 1349 ECB : {
4163 tgl 1350 GIC 3 : scache = lookup_type_cache(scache->type_id, TYPECACHE_HASH_PROC_FINFO);
1351 3 : if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
4175 heikki.linnakangas 1352 LBC 0 : ereport(ERROR,
4175 heikki.linnakangas 1353 ECB : (errcode(ERRCODE_UNDEFINED_FUNCTION),
1354 : errmsg("could not identify a hash function for type %s",
1355 : format_type_be(scache->type_id))));
1356 : }
1357 :
1358 : /*
4163 tgl 1359 : * Apply the hash function to each bound.
1360 : */
4175 heikki.linnakangas 1361 CBC 105 : if (RANGE_HAS_LBOUND(flags))
4163 tgl 1362 72 : lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
4163 tgl 1363 EUB : typcache->rng_collation,
1364 : lower.val));
1365 : else
4163 tgl 1366 GIC 33 : lower_hash = 0;
1367 :
4175 heikki.linnakangas 1368 105 : if (RANGE_HAS_UBOUND(flags))
4163 tgl 1369 78 : upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
1370 : typcache->rng_collation,
1371 : upper.val));
4163 tgl 1372 ECB : else
4163 tgl 1373 CBC 27 : upper_hash = 0;
1374 :
1375 : /* Merge hashes of flags and bounds */
4164 bruce 1376 GIC 105 : result = hash_uint32((uint32) flags);
4175 heikki.linnakangas 1377 CBC 105 : result ^= lower_hash;
413 john.naylor 1378 GIC 105 : result = pg_rotate_left32(result, 1);
4175 heikki.linnakangas 1379 CBC 105 : result ^= upper_hash;
4175 heikki.linnakangas 1380 ECB :
4175 heikki.linnakangas 1381 GIC 105 : PG_RETURN_INT32(result);
1382 : }
1383 :
2047 rhaas 1384 ECB : /*
1385 : * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
1386 : * Otherwise, similar to hash_range.
1387 : */
1388 : Datum
2047 rhaas 1389 CBC 30 : hash_range_extended(PG_FUNCTION_ARGS)
2047 rhaas 1390 ECB : {
2029 tgl 1391 GIC 30 : RangeType *r = PG_GETARG_RANGE_P(0);
2046 rhaas 1392 CBC 30 : Datum seed = PG_GETARG_DATUM(1);
1393 : uint64 result;
1394 : TypeCacheEntry *typcache;
1395 : TypeCacheEntry *scache;
1396 : RangeBound lower;
1397 : RangeBound upper;
1398 : bool empty;
1399 : char flags;
2047 rhaas 1400 ECB : uint64 lower_hash;
1401 : uint64 upper_hash;
1402 :
2047 rhaas 1403 CBC 30 : check_stack_depth();
1404 :
2047 rhaas 1405 GIC 30 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
1406 :
1407 30 : range_deserialize(typcache, r, &lower, &upper, &empty);
1408 30 : flags = range_get_flags(r);
1409 :
1410 30 : scache = typcache->rngelemtype;
1411 30 : if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
1412 : {
2047 rhaas 1413 UIC 0 : scache = lookup_type_cache(scache->type_id,
2047 rhaas 1414 ECB : TYPECACHE_HASH_EXTENDED_PROC_FINFO);
2047 rhaas 1415 UIC 0 : if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2047 rhaas 1416 LBC 0 : ereport(ERROR,
1417 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2047 rhaas 1418 ECB : errmsg("could not identify a hash function for type %s",
1419 : format_type_be(scache->type_id))));
1420 : }
1421 :
2047 rhaas 1422 CBC 30 : if (RANGE_HAS_LBOUND(flags))
2047 rhaas 1423 GIC 30 : lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2047 rhaas 1424 EUB : typcache->rng_collation,
1425 : lower.val,
1426 : seed));
1427 : else
2047 rhaas 1428 UIC 0 : lower_hash = 0;
1429 :
2047 rhaas 1430 GIC 30 : if (RANGE_HAS_UBOUND(flags))
1431 30 : upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
1432 : typcache->rng_collation,
2047 rhaas 1433 ECB : upper.val,
1434 : seed));
1435 : else
2047 rhaas 1436 UIC 0 : upper_hash = 0;
1437 :
1438 : /* Merge hashes of flags and bounds */
2046 rhaas 1439 GBC 30 : result = DatumGetUInt64(hash_uint32_extended((uint32) flags,
2046 rhaas 1440 GIC 30 : DatumGetInt64(seed)));
2047 rhaas 1441 CBC 30 : result ^= lower_hash;
1442 30 : result = ROTATE_HIGH_AND_LOW_32BITS(result);
2047 rhaas 1443 GIC 30 : result ^= upper_hash;
1444 :
1445 30 : PG_RETURN_UINT64(result);
1446 : }
2047 rhaas 1447 EUB :
1448 : /*
1449 : *----------------------------------------------------------
4175 heikki.linnakangas 1450 ECB : * CANONICAL FUNCTIONS
1451 : *
4164 bruce 1452 : * Functions for specific built-in range types.
4175 heikki.linnakangas 1453 : *----------------------------------------------------------
1454 : */
1455 :
1456 : Datum
4175 heikki.linnakangas 1457 GIC 231834 : int4range_canonical(PG_FUNCTION_ARGS)
1458 : {
2029 tgl 1459 231834 : RangeType *r = PG_GETARG_RANGE_P(0);
115 tgl 1460 GNC 231834 : Node *escontext = fcinfo->context;
1461 : TypeCacheEntry *typcache;
1462 : RangeBound lower;
1463 : RangeBound upper;
1464 : bool empty;
1465 :
4163 tgl 1466 GIC 231834 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
1467 :
1468 231834 : range_deserialize(typcache, r, &lower, &upper, &empty);
4175 heikki.linnakangas 1469 ECB :
4175 heikki.linnakangas 1470 GIC 231834 : if (empty)
2029 tgl 1471 LBC 0 : PG_RETURN_RANGE_P(r);
4175 heikki.linnakangas 1472 ECB :
4175 heikki.linnakangas 1473 GIC 231834 : if (!lower.infinite && !lower.inclusive)
1474 : {
115 tgl 1475 GNC 1624 : int32 bnd = DatumGetInt32(lower.val);
1476 :
1477 : /* Handle possible overflow manually */
1478 1624 : if (unlikely(bnd == PG_INT32_MAX))
115 tgl 1479 UNC 0 : ereturn(escontext, (Datum) 0,
1480 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1481 : errmsg("integer out of range")));
115 tgl 1482 GNC 1624 : lower.val = Int32GetDatum(bnd + 1);
4175 heikki.linnakangas 1483 GIC 1624 : lower.inclusive = true;
1484 : }
4175 heikki.linnakangas 1485 ECB :
4175 heikki.linnakangas 1486 GIC 231834 : if (!upper.infinite && upper.inclusive)
4175 heikki.linnakangas 1487 ECB : {
115 tgl 1488 GNC 1609 : int32 bnd = DatumGetInt32(upper.val);
1489 :
1490 : /* Handle possible overflow manually */
1491 1609 : if (unlikely(bnd == PG_INT32_MAX))
1492 6 : ereturn(escontext, (Datum) 0,
1493 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1494 : errmsg("integer out of range")));
1495 1603 : upper.val = Int32GetDatum(bnd + 1);
4175 heikki.linnakangas 1496 CBC 1603 : upper.inclusive = false;
4175 heikki.linnakangas 1497 EUB : }
1498 :
115 tgl 1499 GNC 231828 : PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
1500 : false, escontext));
1501 : }
4175 heikki.linnakangas 1502 ECB :
1503 : Datum
4175 heikki.linnakangas 1504 GIC 43 : int8range_canonical(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 1505 ECB : {
2029 tgl 1506 GBC 43 : RangeType *r = PG_GETARG_RANGE_P(0);
115 tgl 1507 GNC 43 : Node *escontext = fcinfo->context;
1508 : TypeCacheEntry *typcache;
1509 : RangeBound lower;
4175 heikki.linnakangas 1510 ECB : RangeBound upper;
1511 : bool empty;
1512 :
4163 tgl 1513 GIC 43 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
4163 tgl 1514 ECB :
4163 tgl 1515 GIC 43 : range_deserialize(typcache, r, &lower, &upper, &empty);
4175 heikki.linnakangas 1516 ECB :
4175 heikki.linnakangas 1517 GIC 43 : if (empty)
2029 tgl 1518 UIC 0 : PG_RETURN_RANGE_P(r);
4175 heikki.linnakangas 1519 ECB :
4175 heikki.linnakangas 1520 CBC 43 : if (!lower.infinite && !lower.inclusive)
1521 : {
115 tgl 1522 GNC 9 : int64 bnd = DatumGetInt64(lower.val);
1523 :
1524 : /* Handle possible overflow manually */
1525 9 : if (unlikely(bnd == PG_INT64_MAX))
115 tgl 1526 UNC 0 : ereturn(escontext, (Datum) 0,
1527 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1528 : errmsg("bigint out of range")));
115 tgl 1529 GNC 9 : lower.val = Int64GetDatum(bnd + 1);
4175 heikki.linnakangas 1530 CBC 9 : lower.inclusive = true;
4175 heikki.linnakangas 1531 ECB : }
1532 :
4175 heikki.linnakangas 1533 GIC 43 : if (!upper.infinite && upper.inclusive)
4175 heikki.linnakangas 1534 ECB : {
115 tgl 1535 GNC 12 : int64 bnd = DatumGetInt64(upper.val);
1536 :
1537 : /* Handle possible overflow manually */
1538 12 : if (unlikely(bnd == PG_INT64_MAX))
115 tgl 1539 UNC 0 : ereturn(escontext, (Datum) 0,
1540 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1541 : errmsg("bigint out of range")));
115 tgl 1542 GNC 12 : upper.val = Int64GetDatum(bnd + 1);
4175 heikki.linnakangas 1543 GIC 12 : upper.inclusive = false;
1544 : }
1545 :
115 tgl 1546 GNC 43 : PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
1547 : false, escontext));
1548 : }
4175 heikki.linnakangas 1549 ECB :
1550 : Datum
4175 heikki.linnakangas 1551 GIC 81 : daterange_canonical(PG_FUNCTION_ARGS)
1552 : {
2029 tgl 1553 81 : RangeType *r = PG_GETARG_RANGE_P(0);
115 tgl 1554 GNC 81 : Node *escontext = fcinfo->context;
1555 : TypeCacheEntry *typcache;
1556 : RangeBound lower;
4175 heikki.linnakangas 1557 ECB : RangeBound upper;
1558 : bool empty;
1559 :
4163 tgl 1560 GIC 81 : typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
4163 tgl 1561 ECB :
4163 tgl 1562 GBC 81 : range_deserialize(typcache, r, &lower, &upper, &empty);
1563 :
4175 heikki.linnakangas 1564 CBC 81 : if (empty)
2029 tgl 1565 UIC 0 : PG_RETURN_RANGE_P(r);
4175 heikki.linnakangas 1566 ECB :
1361 jdavis 1567 GIC 81 : if (!lower.infinite && !DATE_NOT_FINITE(DatumGetDateADT(lower.val)) &&
1568 75 : !lower.inclusive)
4175 heikki.linnakangas 1569 ECB : {
115 tgl 1570 GNC 18 : DateADT bnd = DatumGetDateADT(lower.val);
1571 :
1572 : /* Check for overflow -- note we already eliminated PG_INT32_MAX */
1573 18 : bnd++;
1574 18 : if (unlikely(!IS_VALID_DATE(bnd)))
115 tgl 1575 UNC 0 : ereturn(escontext, (Datum) 0,
1576 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1577 : errmsg("date out of range")));
115 tgl 1578 GNC 18 : lower.val = DateADTGetDatum(bnd);
4175 heikki.linnakangas 1579 GIC 18 : lower.inclusive = true;
1580 : }
4175 heikki.linnakangas 1581 ECB :
1361 jdavis 1582 CBC 81 : if (!upper.infinite && !DATE_NOT_FINITE(DatumGetDateADT(upper.val)) &&
1361 jdavis 1583 GIC 75 : upper.inclusive)
1584 : {
115 tgl 1585 GNC 15 : DateADT bnd = DatumGetDateADT(upper.val);
1586 :
1587 : /* Check for overflow -- note we already eliminated PG_INT32_MAX */
1588 15 : bnd++;
1589 15 : if (unlikely(!IS_VALID_DATE(bnd)))
1590 6 : ereturn(escontext, (Datum) 0,
1591 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1592 : errmsg("date out of range")));
1593 9 : upper.val = DateADTGetDatum(bnd);
4175 heikki.linnakangas 1594 GIC 9 : upper.inclusive = false;
4175 heikki.linnakangas 1595 ECB : }
1596 :
115 tgl 1597 GNC 75 : PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
1598 : false, escontext));
4175 heikki.linnakangas 1599 ECB : }
4175 heikki.linnakangas 1600 EUB :
1601 : /*
1602 : *----------------------------------------------------------
4175 heikki.linnakangas 1603 ECB : * SUBTYPE_DIFF FUNCTIONS
1604 : *
1605 : * Functions for specific built-in range types.
1606 : *
4156 tgl 1607 : * Note that subtype_diff does return the difference, not the absolute value
1608 : * of the difference, and it must take care to avoid overflow.
1609 : * (numrange_subdiff is at some risk there ...)
1610 : *----------------------------------------------------------
1611 : */
4175 heikki.linnakangas 1612 :
1613 : Datum
4175 heikki.linnakangas 1614 CBC 610854 : int4range_subdiff(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 1615 ECB : {
4164 bruce 1616 GIC 610854 : int32 v1 = PG_GETARG_INT32(0);
1617 610854 : int32 v2 = PG_GETARG_INT32(1);
1618 :
tgl 1619 610854 : PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
1620 : }
4175 heikki.linnakangas 1621 ECB :
1622 : Datum
4175 heikki.linnakangas 1623 LBC 0 : int8range_subdiff(PG_FUNCTION_ARGS)
1624 : {
4164 bruce 1625 0 : int64 v1 = PG_GETARG_INT64(0);
4164 bruce 1626 UBC 0 : int64 v2 = PG_GETARG_INT64(1);
1627 :
4164 tgl 1628 LBC 0 : PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
4175 heikki.linnakangas 1629 ECB : }
1630 :
1631 : Datum
4175 heikki.linnakangas 1632 GIC 123 : numrange_subdiff(PG_FUNCTION_ARGS)
1633 : {
4175 heikki.linnakangas 1634 CBC 123 : Datum v1 = PG_GETARG_DATUM(0);
1635 123 : Datum v2 = PG_GETARG_DATUM(1);
4175 heikki.linnakangas 1636 EUB : Datum numresult;
1637 : float8 floatresult;
1638 :
4175 heikki.linnakangas 1639 CBC 123 : numresult = DirectFunctionCall2(numeric_sub, v1, v2);
4175 heikki.linnakangas 1640 ECB :
4164 tgl 1641 GIC 123 : floatresult = DatumGetFloat8(DirectFunctionCall1(numeric_float8,
1642 : numresult));
4175 heikki.linnakangas 1643 ECB :
4175 heikki.linnakangas 1644 CBC 123 : PG_RETURN_FLOAT8(floatresult);
1645 : }
4175 heikki.linnakangas 1646 ECB :
1647 : Datum
4164 tgl 1648 UIC 0 : daterange_subdiff(PG_FUNCTION_ARGS)
4164 tgl 1649 ECB : {
4164 tgl 1650 LBC 0 : int32 v1 = PG_GETARG_INT32(0);
1651 0 : int32 v2 = PG_GETARG_INT32(1);
1652 :
4164 tgl 1653 UIC 0 : PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
4164 tgl 1654 ECB : }
1655 :
1656 : Datum
4175 heikki.linnakangas 1657 UIC 0 : tsrange_subdiff(PG_FUNCTION_ARGS)
4175 heikki.linnakangas 1658 ECB : {
4175 heikki.linnakangas 1659 UIC 0 : Timestamp v1 = PG_GETARG_TIMESTAMP(0);
1660 0 : Timestamp v2 = PG_GETARG_TIMESTAMP(1);
1661 : float8 result;
1662 :
4164 tgl 1663 0 : result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
4175 heikki.linnakangas 1664 0 : PG_RETURN_FLOAT8(result);
1665 : }
1666 :
1667 : Datum
1668 0 : tstzrange_subdiff(PG_FUNCTION_ARGS)
1669 : {
1670 0 : Timestamp v1 = PG_GETARG_TIMESTAMP(0);
1671 0 : Timestamp v2 = PG_GETARG_TIMESTAMP(1);
1672 : float8 result;
1673 :
4164 tgl 1674 0 : result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
4175 heikki.linnakangas 1675 LBC 0 : PG_RETURN_FLOAT8(result);
1676 : }
4175 heikki.linnakangas 1677 ECB :
1678 : /*
1679 : *----------------------------------------------------------
1680 : * SUPPORT FUNCTIONS
1681 : *
1682 : * These functions aren't in pg_proc, but are useful for
1683 : * defining new generic range functions in C.
4175 heikki.linnakangas 1684 EUB : *----------------------------------------------------------
1685 : */
1686 :
4163 tgl 1687 : /*
1688 : * range_get_typcache: get cached information about a range type
1689 : *
1690 : * This is for use by range-related functions that follow the convention
1691 : * of using the fn_extra field as a pointer to the type cache entry for
1692 : * the range type. Functions that need to cache more information than
4163 tgl 1693 ECB : * that must fend for themselves.
1694 : */
1695 : TypeCacheEntry *
4163 tgl 1696 CBC 2357008 : range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
1697 : {
4163 tgl 1698 GIC 2357008 : TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1699 :
4163 tgl 1700 CBC 2357008 : if (typcache == NULL ||
4163 tgl 1701 GIC 2352722 : typcache->type_id != rngtypid)
4163 tgl 1702 ECB : {
4163 tgl 1703 GIC 4286 : typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
1704 4286 : if (typcache->rngelemtype == NULL)
4163 tgl 1705 LBC 0 : elog(ERROR, "type %u is not a range type", rngtypid);
4163 tgl 1706 GIC 4286 : fcinfo->flinfo->fn_extra = (void *) typcache;
1707 : }
1708 :
4163 tgl 1709 GBC 2357008 : return typcache;
1710 : }
4163 tgl 1711 EUB :
4175 heikki.linnakangas 1712 : /*
1713 : * range_serialize: construct a range value from bounds and empty-flag
4164 tgl 1714 : *
1715 : * This does not force canonicalization of the range value. In most cases,
1716 : * external callers should only be canonicalization functions. Note that
1717 : * we perform some datatype-independent canonicalization checks anyway.
4175 heikki.linnakangas 1718 : */
1719 : RangeType *
4163 tgl 1720 GBC 469852 : range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
1721 : bool empty, struct Node *escontext)
1722 : {
1723 : RangeType *range;
4156 tgl 1724 EUB : int cmp;
4163 1725 : Size msize;
1726 : Pointer ptr;
1727 : int16 typlen;
1728 : bool typbyval;
1729 : char typalign;
1730 : char typstorage;
4164 bruce 1731 GBC 469852 : char flags = 0;
4175 heikki.linnakangas 1732 EUB :
1733 : /*
1734 : * Verify range is not invalid on its face, and construct flags value,
4156 tgl 1735 : * preventing any non-canonical combinations such as infinite+inclusive.
1736 : */
4156 tgl 1737 GIC 469852 : Assert(lower->lower);
1738 469852 : Assert(!upper->lower);
1739 :
4175 heikki.linnakangas 1740 469852 : if (empty)
1741 1830 : flags |= RANGE_EMPTY;
1742 : else
1743 : {
4156 tgl 1744 468022 : cmp = range_cmp_bound_values(typcache, lower, upper);
1745 :
1746 : /* error check: if lower bound value is above upper, it's wrong */
1747 468022 : if (cmp > 0)
115 tgl 1748 GNC 33 : ereturn(escontext, NULL,
1749 : (errcode(ERRCODE_DATA_EXCEPTION),
1750 : errmsg("range lower bound must be less than or equal to range upper bound")));
1751 :
1752 : /* if bounds are equal, and not both inclusive, range is empty */
4156 tgl 1753 GIC 467989 : if (cmp == 0 && !(lower->inclusive && upper->inclusive))
1754 192 : flags |= RANGE_EMPTY;
1755 : else
1756 : {
4156 tgl 1757 ECB : /* infinite boundaries are never inclusive */
4156 tgl 1758 GIC 467797 : if (lower->infinite)
4156 tgl 1759 CBC 4911 : flags |= RANGE_LB_INF;
4156 tgl 1760 GIC 462886 : else if (lower->inclusive)
4156 tgl 1761 CBC 461082 : flags |= RANGE_LB_INC;
1762 467797 : if (upper->infinite)
4156 tgl 1763 GIC 3363 : flags |= RANGE_UB_INF;
4156 tgl 1764 CBC 464434 : else if (upper->inclusive)
1765 1969 : flags |= RANGE_UB_INC;
4156 tgl 1766 EUB : }
4163 tgl 1767 ECB : }
1768 :
1769 : /* Fetch information about range's element type */
4156 tgl 1770 CBC 469819 : typlen = typcache->rngelemtype->typlen;
4156 tgl 1771 GIC 469819 : typbyval = typcache->rngelemtype->typbyval;
1772 469819 : typalign = typcache->rngelemtype->typalign;
1773 469819 : typstorage = typcache->rngelemtype->typstorage;
1774 :
1775 : /* Count space for varlena header and range type's OID */
4163 1776 469819 : msize = sizeof(RangeType);
1777 469819 : Assert(msize == MAXALIGN(msize));
1778 :
1779 : /* Count space for bounds */
4175 heikki.linnakangas 1780 469819 : if (RANGE_HAS_LBOUND(flags))
4175 heikki.linnakangas 1781 ECB : {
1782 : /*
1783 : * Make sure item to be inserted is not toasted. It is essential that
1784 : * we not insert an out-of-line toast value pointer into a range
1785 : * object, for the same reasons that arrays and records can't contain
1786 : * them. It would work to store a compressed-in-line value, but we
1787 : * prefer to decompress and then let compression be applied to the
1788 : * whole range object if necessary. But, unlike arrays, we do allow
1789 : * short-header varlena objects to stay as-is.
1790 : */
4164 tgl 1791 GIC 462886 : if (typlen == -1)
4164 tgl 1792 CBC 2361 : lower->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(lower->val));
1793 :
4175 heikki.linnakangas 1794 GIC 462886 : msize = datum_compute_size(msize, lower->val, typbyval, typalign,
1795 : typlen, typstorage);
1796 : }
1797 :
4175 heikki.linnakangas 1798 CBC 469819 : if (RANGE_HAS_UBOUND(flags))
4175 heikki.linnakangas 1799 ECB : {
1800 : /* Make sure item to be inserted is not toasted */
4164 tgl 1801 CBC 464434 : if (typlen == -1)
1802 2343 : upper->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(upper->val));
1803 :
4175 heikki.linnakangas 1804 GIC 464434 : msize = datum_compute_size(msize, upper->val, typbyval, typalign,
4175 heikki.linnakangas 1805 ECB : typlen, typstorage);
1806 : }
1807 :
4163 tgl 1808 : /* Add space for flag byte */
4175 heikki.linnakangas 1809 CBC 469819 : msize += sizeof(char);
1810 :
1811 : /* Note: zero-fill is required here, just as in heap tuples */
4163 tgl 1812 GIC 469819 : range = (RangeType *) palloc0(msize);
1813 469819 : SET_VARSIZE(range, msize);
4175 heikki.linnakangas 1814 ECB :
4163 tgl 1815 : /* Now fill in the datum */
4163 tgl 1816 GIC 469819 : range->rangetypid = typcache->type_id;
1817 :
1818 469819 : ptr = (char *) (range + 1);
4175 heikki.linnakangas 1819 ECB :
4175 heikki.linnakangas 1820 CBC 469819 : if (RANGE_HAS_LBOUND(flags))
4175 heikki.linnakangas 1821 ECB : {
4175 heikki.linnakangas 1822 CBC 462886 : Assert(lower->lower);
1823 462886 : ptr = datum_write(ptr, lower->val, typbyval, typalign, typlen,
4175 heikki.linnakangas 1824 ECB : typstorage);
1825 : }
1826 :
4175 heikki.linnakangas 1827 GIC 469819 : if (RANGE_HAS_UBOUND(flags))
1828 : {
1829 464434 : Assert(!upper->lower);
1830 464434 : ptr = datum_write(ptr, upper->val, typbyval, typalign, typlen,
4175 heikki.linnakangas 1831 ECB : typstorage);
1832 : }
1833 :
4163 tgl 1834 CBC 469819 : *((char *) ptr) = flags;
1835 :
4163 tgl 1836 GIC 469819 : return range;
4175 heikki.linnakangas 1837 ECB : }
1838 :
1839 : /*
1840 : * range_deserialize: deconstruct a range value
4164 tgl 1841 : *
1842 : * NB: the given range object must be fully detoasted; it cannot have a
1843 : * short varlena header.
1844 : *
1845 : * Note that if the element type is pass-by-reference, the datums in the
1846 : * RangeBound structs will be pointers into the given range object.
1847 : */
1848 : void
1256 peter 1849 GIC 4814011 : range_deserialize(TypeCacheEntry *typcache, const RangeType *range,
1850 : RangeBound *lower, RangeBound *upper, bool *empty)
1851 : {
4175 heikki.linnakangas 1852 ECB : char flags;
4163 tgl 1853 : int16 typlen;
1854 : bool typbyval;
1855 : char typalign;
1856 : Pointer ptr;
1857 : Datum lbound;
1858 : Datum ubound;
1859 :
1860 : /* assert caller passed the right typcache entry */
4163 tgl 1861 GIC 4814011 : Assert(RangeTypeGetOid(range) == typcache->type_id);
4175 heikki.linnakangas 1862 ECB :
4164 tgl 1863 : /* fetch the flag byte from datum's last byte */
1256 peter 1864 GIC 4814011 : flags = *((const char *) range + VARSIZE(range) - 1);
4175 heikki.linnakangas 1865 ECB :
1866 : /* fetch information about range's element type */
4163 tgl 1867 GIC 4814011 : typlen = typcache->rngelemtype->typlen;
1868 4814011 : typbyval = typcache->rngelemtype->typbyval;
1869 4814011 : typalign = typcache->rngelemtype->typalign;
4175 heikki.linnakangas 1870 ECB :
1871 : /* initialize data pointer just after the range OID */
4163 tgl 1872 GIC 4814011 : ptr = (Pointer) (range + 1);
4175 heikki.linnakangas 1873 ECB :
4164 tgl 1874 : /* fetch lower bound, if any */
4175 heikki.linnakangas 1875 GIC 4814011 : if (RANGE_HAS_LBOUND(flags))
1876 : {
4164 tgl 1877 ECB : /* att_align_pointer cannot be necessary here */
4175 heikki.linnakangas 1878 GIC 4258782 : lbound = fetch_att(ptr, typbyval, typlen);
4164 tgl 1879 CBC 4258782 : ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
1880 : }
4175 heikki.linnakangas 1881 ECB : else
4175 heikki.linnakangas 1882 GIC 555229 : lbound = (Datum) 0;
4175 heikki.linnakangas 1883 ECB :
4164 tgl 1884 : /* fetch upper bound, if any */
4175 heikki.linnakangas 1885 GIC 4814011 : if (RANGE_HAS_UBOUND(flags))
1886 : {
1887 4266555 : ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
4175 heikki.linnakangas 1888 CBC 4266555 : ubound = fetch_att(ptr, typbyval, typlen);
1889 : /* no need for att_addlength_pointer */
4175 heikki.linnakangas 1890 ECB : }
1891 : else
4175 heikki.linnakangas 1892 GIC 547456 : ubound = (Datum) 0;
1893 :
1894 : /* emit results */
4164 tgl 1895 ECB :
4163 tgl 1896 GIC 4814011 : *empty = (flags & RANGE_EMPTY) != 0;
4175 heikki.linnakangas 1897 ECB :
4164 bruce 1898 GIC 4814011 : lower->val = lbound;
tgl 1899 4814011 : lower->infinite = (flags & RANGE_LB_INF) != 0;
4163 1900 4814011 : lower->inclusive = (flags & RANGE_LB_INC) != 0;
4164 bruce 1901 4814011 : lower->lower = true;
1902 :
1903 4814011 : upper->val = ubound;
tgl 1904 4814011 : upper->infinite = (flags & RANGE_UB_INF) != 0;
4163 1905 4814011 : upper->inclusive = (flags & RANGE_UB_INC) != 0;
4164 bruce 1906 4814011 : upper->lower = false;
4175 heikki.linnakangas 1907 4814011 : }
1908 :
1909 : /*
4163 tgl 1910 ECB : * range_get_flags: just get the flags from a RangeType value.
1911 : *
1912 : * This is frequently useful in places that only need the flags and not
1913 : * the full results of range_deserialize.
1914 : */
1915 : char
1256 peter 1916 GIC 1477088 : range_get_flags(const RangeType *range)
1917 : {
1918 : /* fetch the flag byte from datum's last byte */
4163 tgl 1919 1477088 : return *((char *) range + VARSIZE(range) - 1);
1920 : }
1921 :
4151 tgl 1922 ECB : /*
1923 : * range_set_contain_empty: set the RANGE_CONTAIN_EMPTY bit in the value.
1924 : *
1925 : * This is only needed in GiST operations, so we don't include a provision
1926 : * for setting it in range_serialize; rather, this function must be applied
1927 : * afterwards.
1928 : */
1929 : void
4151 tgl 1930 CBC 9 : range_set_contain_empty(RangeType *range)
1931 : {
1932 : char *flagsp;
4151 tgl 1933 ECB :
1934 : /* flag byte is datum's last byte */
4151 tgl 1935 GIC 9 : flagsp = (char *) range + VARSIZE(range) - 1;
4151 tgl 1936 ECB :
4151 tgl 1937 GIC 9 : *flagsp |= RANGE_CONTAIN_EMPTY;
1938 9 : }
4151 tgl 1939 ECB :
4175 heikki.linnakangas 1940 : /*
1941 : * This both serializes and canonicalizes (if applicable) the range.
1942 : * This should be used by most callers.
1943 : */
1944 : RangeType *
4163 tgl 1945 GIC 236600 : make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
1946 : bool empty, struct Node *escontext)
1947 : {
4163 tgl 1948 ECB : RangeType *range;
4175 heikki.linnakangas 1949 :
115 tgl 1950 GNC 236600 : range = range_serialize(typcache, lower, upper, empty, escontext);
1951 :
1952 236573 : if (SOFT_ERROR_OCCURRED(escontext))
1953 6 : return NULL;
1954 :
1955 : /* no need to call canonical on empty ranges ... */
4156 tgl 1956 CBC 236567 : if (OidIsValid(typcache->rng_canonical_finfo.fn_oid) &&
4156 tgl 1957 GIC 233773 : !RangeIsEmpty(range))
1958 : {
1959 : /* Do this the hard way so that we can pass escontext */
115 tgl 1960 GNC 231958 : LOCAL_FCINFO(fcinfo, 1);
1961 : Datum result;
1962 :
1963 231958 : InitFunctionCallInfoData(*fcinfo, &typcache->rng_canonical_finfo, 1,
1964 : InvalidOid, escontext, NULL);
1965 :
1966 231958 : fcinfo->args[0].value = RangeTypePGetDatum(range);
1967 231958 : fcinfo->args[0].isnull = false;
1968 :
1969 231958 : result = FunctionCallInvoke(fcinfo);
1970 :
1971 231958 : if (SOFT_ERROR_OCCURRED(escontext))
1972 12 : return NULL;
1973 :
1974 : /* Should not get a null result if there was no error */
1975 231946 : if (fcinfo->isnull)
115 tgl 1976 UNC 0 : elog(ERROR, "function %u returned NULL",
1977 : typcache->rng_canonical_finfo.fn_oid);
1978 :
115 tgl 1979 GNC 231946 : range = DatumGetRangeTypeP(result);
1980 : }
4175 heikki.linnakangas 1981 ECB :
4163 tgl 1982 GIC 236555 : return range;
4175 heikki.linnakangas 1983 ECB : }
1984 :
4161 tgl 1985 : /*
1986 : * Compare two range boundary points, returning <0, 0, or >0 according to
1987 : * whether b1 is less than, equal to, or greater than b2.
1988 : *
1989 : * The boundaries can be any combination of upper and lower; so it's useful
1990 : * for a variety of operators.
1991 : *
1992 : * The simple case is when b1 and b2 are both finite and inclusive, in which
1993 : * case the result is just a comparison of the values held in b1 and b2.
1994 : *
1995 : * If a bound is exclusive, then we need to know whether it's a lower bound,
1996 : * in which case we treat the boundary point as "just greater than" the held
1997 : * value; or an upper bound, in which case we treat the boundary point as
1998 : * "just less than" the held value.
1999 : *
2000 : * If a bound is infinite, it represents minus infinity (less than every other
2001 : * point) if it's a lower bound; or plus infinity (greater than every other
2002 : * point) if it's an upper bound.
2003 : *
2004 : * There is only one case where two boundaries compare equal but are not
2005 : * identical: when both bounds are inclusive and hold the same finite value,
2006 : * but one is an upper bound and the other a lower bound.
2007 : */
2008 : int
1256 peter 2009 GIC 6066546 : range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
2010 : {
2011 : int32 result;
2012 :
2013 : /*
2014 : * First, handle cases involving infinity, which don't require invoking
4161 tgl 2015 ECB : * the comparison proc.
2016 : */
4175 heikki.linnakangas 2017 GIC 6066546 : if (b1->infinite && b2->infinite)
2018 : {
2019 : /*
4161 tgl 2020 ECB : * Both are infinity, so they are equal unless one is lower and the
2021 : * other not.
2022 : */
4175 heikki.linnakangas 2023 CBC 8101 : if (b1->lower == b2->lower)
4175 heikki.linnakangas 2024 GIC 8059 : return 0;
2025 : else
4161 tgl 2026 42 : return b1->lower ? -1 : 1;
2027 : }
2028 6058445 : else if (b1->infinite)
2029 47572 : return b1->lower ? -1 : 1;
4161 tgl 2030 CBC 6010873 : else if (b2->infinite)
4161 tgl 2031 GIC 14006 : return b2->lower ? 1 : -1;
2032 :
2033 : /*
2034 : * Both boundaries are finite, so compare the held values.
4161 tgl 2035 ECB : */
4163 tgl 2036 GIC 5996867 : result = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
4163 tgl 2037 ECB : typcache->rng_collation,
4175 heikki.linnakangas 2038 CBC 5996867 : b1->val, b2->val));
2039 :
2040 : /*
4161 tgl 2041 ECB : * If the comparison is anything other than equal, we're done. If they
2042 : * compare equal though, we still have to consider whether the boundaries
2043 : * are inclusive or exclusive.
2044 : */
4175 heikki.linnakangas 2045 CBC 5996867 : if (result == 0)
2046 : {
4161 tgl 2047 GIC 346864 : if (!b1->inclusive && !b2->inclusive)
4161 tgl 2048 ECB : {
2049 : /* both are exclusive */
4161 tgl 2050 GIC 153823 : if (b1->lower == b2->lower)
4161 tgl 2051 CBC 153820 : return 0;
4161 tgl 2052 ECB : else
4161 tgl 2053 GIC 3 : return b1->lower ? 1 : -1;
4161 tgl 2054 ECB : }
4161 tgl 2055 GIC 193041 : else if (!b1->inclusive)
4161 tgl 2056 CBC 315 : return b1->lower ? 1 : -1;
2057 192726 : else if (!b2->inclusive)
4161 tgl 2058 GIC 413 : return b2->lower ? -1 : 1;
2059 : else
4161 tgl 2060 ECB : {
4161 tgl 2061 EUB : /*
2062 : * Both are inclusive and the values held are equal, so they are
2063 : * equal regardless of whether they are upper or lower boundaries,
4161 tgl 2064 ECB : * or a mix.
2065 : */
4161 tgl 2066 GIC 192313 : return 0;
4161 tgl 2067 ECB : }
2068 : }
2069 :
4175 heikki.linnakangas 2070 GIC 5650003 : return result;
2071 : }
2072 :
2073 : /*
2074 : * Compare two range boundary point values, returning <0, 0, or >0 according
2075 : * to whether b1 is less than, equal to, or greater than b2.
2076 : *
2077 : * This is similar to but simpler than range_cmp_bounds(). We just compare
2078 : * the values held in b1 and b2, ignoring inclusive/exclusive flags. The
2079 : * lower/upper flags only matter for infinities, where they tell us if the
2080 : * infinity is plus or minus.
2081 : */
2082 : int
1256 peter 2083 704332 : range_cmp_bound_values(TypeCacheEntry *typcache, const RangeBound *b1,
2084 : const RangeBound *b2)
2085 : {
2086 : /*
2087 : * First, handle cases involving infinity, which don't require invoking
2088 : * the comparison proc.
2089 : */
4156 tgl 2090 704332 : if (b1->infinite && b2->infinite)
2091 : {
2092 : /*
2093 : * Both are infinity, so they are equal unless one is lower and the
4156 tgl 2094 ECB : * other not.
2095 : */
4156 tgl 2096 GIC 137 : if (b1->lower == b2->lower)
4156 tgl 2097 UIC 0 : return 0;
2098 : else
4156 tgl 2099 GIC 137 : return b1->lower ? -1 : 1;
2100 : }
2101 704195 : else if (b1->infinite)
4156 tgl 2102 CBC 8166 : return b1->lower ? -1 : 1;
4156 tgl 2103 GIC 696029 : else if (b2->infinite)
2104 6910 : return b2->lower ? 1 : -1;
2105 :
2106 : /*
2107 : * Both boundaries are finite, so compare the held values.
4156 tgl 2108 ECB : */
4156 tgl 2109 CBC 689119 : return DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
2110 : typcache->rng_collation,
2111 689119 : b1->val, b2->val));
2112 : }
4156 tgl 2113 ECB :
840 akorotkov 2114 : /*
2115 : * qsort callback for sorting ranges.
2116 : *
2117 : * Two empty ranges compare equal; an empty range sorts to the left of any
2118 : * non-empty range. Two non-empty ranges are sorted by lower bound first
2119 : * and by upper bound next.
2120 : */
2121 : int
840 akorotkov 2122 GIC 13359 : range_compare(const void *key1, const void *key2, void *arg)
840 akorotkov 2123 ECB : {
840 akorotkov 2124 GIC 13359 : RangeType *r1 = *(RangeType **) key1;
2125 13359 : RangeType *r2 = *(RangeType **) key2;
2126 13359 : TypeCacheEntry *typcache = (TypeCacheEntry *) arg;
2127 : RangeBound lower1;
2128 : RangeBound upper1;
2129 : RangeBound lower2;
840 akorotkov 2130 ECB : RangeBound upper2;
2131 : bool empty1;
2132 : bool empty2;
2133 : int cmp;
2134 :
840 akorotkov 2135 CBC 13359 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
2136 13359 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
2137 :
2138 13359 : if (empty1 && empty2)
840 akorotkov 2139 GIC 24 : cmp = 0;
840 akorotkov 2140 CBC 13335 : else if (empty1)
2141 21 : cmp = -1;
2142 13314 : else if (empty2)
2143 6 : cmp = 1;
2144 : else
2145 : {
840 akorotkov 2146 GIC 13308 : cmp = range_cmp_bounds(typcache, &lower1, &lower2);
2147 13308 : if (cmp == 0)
2148 24 : cmp = range_cmp_bounds(typcache, &upper1, &upper2);
2149 : }
2150 :
840 akorotkov 2151 CBC 13359 : return cmp;
2152 : }
2153 :
2154 : /*
4156 tgl 2155 ECB : * Build an empty range value of the type indicated by the typcache entry.
2156 : */
2157 : RangeType *
4163 tgl 2158 GIC 1560 : make_empty_range(TypeCacheEntry *typcache)
2159 : {
2160 : RangeBound lower;
2161 : RangeBound upper;
2162 :
2163 1560 : lower.val = (Datum) 0;
2164 1560 : lower.infinite = false;
2165 1560 : lower.inclusive = false;
4175 heikki.linnakangas 2166 1560 : lower.lower = true;
2167 :
4163 tgl 2168 CBC 1560 : upper.val = (Datum) 0;
4163 tgl 2169 GIC 1560 : upper.infinite = false;
2170 1560 : upper.inclusive = false;
4175 heikki.linnakangas 2171 1560 : upper.lower = false;
2172 :
115 tgl 2173 GNC 1560 : return make_range(typcache, &lower, &upper, true, NULL);
2174 : }
4175 heikki.linnakangas 2175 ECB :
2176 :
2177 : /*
2178 : *----------------------------------------------------------
2179 : * STATIC FUNCTIONS
2180 : *----------------------------------------------------------
4164 tgl 2181 : */
4164 tgl 2182 EUB :
2183 : /*
4175 heikki.linnakangas 2184 ECB : * Given a string representing the flags for the range type, return the flags
2185 : * represented as a char.
2186 : */
4164 tgl 2187 : static char
4164 tgl 2188 CBC 2559 : range_parse_flags(const char *flags_str)
4175 heikki.linnakangas 2189 ECB : {
4164 bruce 2190 GIC 2559 : char flags = 0;
2191 :
4175 heikki.linnakangas 2192 2559 : if (flags_str[0] == '\0' ||
2193 2559 : flags_str[1] == '\0' ||
4175 heikki.linnakangas 2194 CBC 2559 : flags_str[2] != '\0')
4175 heikki.linnakangas 2195 UIC 0 : ereport(ERROR,
4175 heikki.linnakangas 2196 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
2197 : errmsg("invalid range bound flags"),
2198 : errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
2199 :
4175 heikki.linnakangas 2200 GIC 2559 : switch (flags_str[0])
2201 : {
2202 105 : case '[':
2203 105 : flags |= RANGE_LB_INC;
2204 105 : break;
2205 2454 : case '(':
2206 2454 : break;
4175 heikki.linnakangas 2207 LBC 0 : default:
4175 heikki.linnakangas 2208 UIC 0 : ereport(ERROR,
4175 heikki.linnakangas 2209 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
2210 : errmsg("invalid range bound flags"),
2118 tgl 2211 : errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
2212 : }
2213 :
4175 heikki.linnakangas 2214 GIC 2559 : switch (flags_str[1])
2215 : {
2216 2517 : case ']':
2217 2517 : flags |= RANGE_UB_INC;
2218 2517 : break;
2219 42 : case ')':
4175 heikki.linnakangas 2220 CBC 42 : break;
4175 heikki.linnakangas 2221 LBC 0 : default:
4175 heikki.linnakangas 2222 UIC 0 : ereport(ERROR,
4175 heikki.linnakangas 2223 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
2224 : errmsg("invalid range bound flags"),
2118 tgl 2225 : errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
4175 heikki.linnakangas 2226 : }
2227 :
4175 heikki.linnakangas 2228 CBC 2559 : return flags;
2229 : }
2230 :
4175 heikki.linnakangas 2231 ECB : /*
4156 tgl 2232 : * Parse range input.
4175 heikki.linnakangas 2233 : *
2234 : * Input parameters:
2235 : * string: input string to be parsed
4156 tgl 2236 : * Output parameters:
2237 : * *flags: receives flags bitmask
2238 : * *lbound_str: receives palloc'd lower bound string, or NULL if none
2239 : * *ubound_str: receives palloc'd upper bound string, or NULL if none
2240 : *
2241 : * This is modeled somewhat after record_in in rowtypes.c.
2242 : * The input syntax is:
4164 bruce 2243 : * <range> := EMPTY
2244 : * | <lb-inc> <string>, <string> <ub-inc>
2245 : * <lb-inc> := '[' | '('
2246 : * <ub-inc> := ']' | ')'
2247 : *
4156 tgl 2248 : * Whitespace before or after <range> is ignored. Whitespace within a <string>
2249 : * is taken literally and becomes part of the input string for that bound.
4175 heikki.linnakangas 2250 : *
4156 tgl 2251 : * A <string> of length zero is taken as "infinite" (i.e. no bound), unless it
2252 : * is surrounded by double-quotes, in which case it is the literal empty
4175 heikki.linnakangas 2253 : * string.
2254 : *
2255 : * Within a <string>, special characters (such as comma, parenthesis, or
2256 : * brackets) can be enclosed in double-quotes or escaped with backslash. Within
2257 : * double-quotes, a double-quote can be escaped with double-quote or backslash.
2258 : *
2259 : * Returns true on success, false on failure (but failures will return only if
2260 : * escontext is an ErrorSaveContext).
2261 : */
2262 : static bool
4156 tgl 2263 GIC 1471 : range_parse(const char *string, char *flags, char **lbound_str,
2264 : char **ubound_str, Node *escontext)
2265 : {
2266 1471 : const char *ptr = string;
2267 : bool infinite;
2268 :
4175 heikki.linnakangas 2269 1471 : *flags = 0;
2270 :
2271 : /* consume whitespace */
4163 tgl 2272 1483 : while (*ptr != '\0' && isspace((unsigned char) *ptr))
4175 heikki.linnakangas 2273 12 : ptr++;
2274 :
2275 : /* check for empty range */
4175 heikki.linnakangas 2276 CBC 1471 : if (pg_strncasecmp(ptr, RANGE_EMPTY_LITERAL,
2277 : strlen(RANGE_EMPTY_LITERAL)) == 0)
4175 heikki.linnakangas 2278 ECB : {
4175 heikki.linnakangas 2279 GIC 270 : *flags = RANGE_EMPTY;
4156 tgl 2280 CBC 270 : *lbound_str = NULL;
2281 270 : *ubound_str = NULL;
4175 heikki.linnakangas 2282 ECB :
4175 heikki.linnakangas 2283 GBC 270 : ptr += strlen(RANGE_EMPTY_LITERAL);
2284 :
2285 : /* the rest should be whitespace */
4163 tgl 2286 GIC 276 : while (*ptr != '\0' && isspace((unsigned char) *ptr))
4175 heikki.linnakangas 2287 6 : ptr++;
4175 heikki.linnakangas 2288 ECB :
2289 : /* should have consumed everything */
4175 heikki.linnakangas 2290 CBC 270 : if (*ptr != '\0')
115 tgl 2291 UNC 0 : ereturn(escontext, false,
4175 heikki.linnakangas 2292 ECB : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2293 : errmsg("malformed range literal: \"%s\"",
2294 : string),
3738 peter_e 2295 EUB : errdetail("Junk after \"empty\" key word.")));
4175 heikki.linnakangas 2296 :
115 tgl 2297 GNC 270 : return true;
2298 : }
2299 :
4156 tgl 2300 GIC 1201 : if (*ptr == '[')
2301 : {
4156 tgl 2302 CBC 864 : *flags |= RANGE_LB_INC;
4175 heikki.linnakangas 2303 GIC 864 : ptr++;
4175 heikki.linnakangas 2304 ECB : }
4156 tgl 2305 CBC 337 : else if (*ptr == '(')
2306 331 : ptr++;
4175 heikki.linnakangas 2307 ECB : else
115 tgl 2308 GNC 6 : ereturn(escontext, false,
4175 heikki.linnakangas 2309 EUB : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2310 : errmsg("malformed range literal: \"%s\"",
2311 : string),
2312 : errdetail("Missing left parenthesis or bracket.")));
2313 :
115 tgl 2314 GNC 1195 : ptr = range_parse_bound(string, ptr, lbound_str, &infinite, escontext);
2315 1192 : if (ptr == NULL)
115 tgl 2316 UNC 0 : return false;
4175 heikki.linnakangas 2317 GIC 1192 : if (infinite)
4175 heikki.linnakangas 2318 CBC 81 : *flags |= RANGE_LB_INF;
2319 :
4156 tgl 2320 GIC 1192 : if (*ptr == ',')
2321 1180 : ptr++;
2322 : else
115 tgl 2323 GNC 12 : ereturn(escontext, false,
2324 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2325 : errmsg("malformed range literal: \"%s\"",
2326 : string),
2327 : errdetail("Missing comma after lower bound.")));
2328 :
2329 1180 : ptr = range_parse_bound(string, ptr, ubound_str, &infinite, escontext);
2330 1180 : if (ptr == NULL)
2331 6 : return false;
4156 tgl 2332 GIC 1174 : if (infinite)
2333 123 : *flags |= RANGE_UB_INF;
2334 :
2335 1174 : if (*ptr == ']')
2336 : {
2337 313 : *flags |= RANGE_UB_INC;
2338 313 : ptr++;
2339 : }
2340 861 : else if (*ptr == ')')
2341 855 : ptr++;
2342 : else /* must be a comma */
115 tgl 2343 GNC 6 : ereturn(escontext, false,
2344 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2345 : errmsg("malformed range literal: \"%s\"",
2346 : string),
2347 : errdetail("Too many commas.")));
2348 :
2349 : /* consume whitespace */
4163 tgl 2350 GIC 1183 : while (*ptr != '\0' && isspace((unsigned char) *ptr))
4175 heikki.linnakangas 2351 15 : ptr++;
2352 :
2353 1168 : if (*ptr != '\0')
115 tgl 2354 GNC 9 : ereturn(escontext, false,
4175 heikki.linnakangas 2355 ECB : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2356 : errmsg("malformed range literal: \"%s\"",
2357 : string),
2358 : errdetail("Junk after right parenthesis or bracket.")));
2359 :
115 tgl 2360 GNC 1159 : return true;
2361 : }
2362 :
4156 tgl 2363 ECB : /*
2364 : * Helper for range_parse: parse and de-quote one bound string.
2365 : *
2366 : * We scan until finding comma, right parenthesis, or right bracket.
2367 : *
2368 : * Input parameters:
2369 : * string: entire input string (used only for error reports)
2370 : * ptr: where to start parsing bound
2371 : * Output parameters:
2372 : * *bound_str: receives palloc'd bound string, or NULL if none
2373 : * *infinite: set true if no bound, else false
2374 : *
2375 : * The return value is the scan ptr, advanced past the bound string.
2376 : * However, if escontext is an ErrorSaveContext, we return NULL on failure.
2377 : */
2378 : static const char *
4156 tgl 2379 GIC 2375 : range_parse_bound(const char *string, const char *ptr,
2380 : char **bound_str, bool *infinite, Node *escontext)
4175 heikki.linnakangas 2381 ECB : {
4164 bruce 2382 : StringInfoData buf;
2383 :
2384 : /* Check for null: completely empty input means null */
4175 heikki.linnakangas 2385 CBC 2375 : if (*ptr == ',' || *ptr == ')' || *ptr == ']')
4175 heikki.linnakangas 2386 EUB : {
4175 heikki.linnakangas 2387 GIC 204 : *bound_str = NULL;
4164 bruce 2388 204 : *infinite = true;
2389 : }
2390 : else
2391 : {
4156 tgl 2392 ECB : /* Extract string for this bound */
4175 heikki.linnakangas 2393 GIC 2171 : bool inquote = false;
2394 :
4175 heikki.linnakangas 2395 CBC 2171 : initStringInfo(&buf);
4175 heikki.linnakangas 2396 GIC 7868 : while (inquote || !(*ptr == ',' || *ptr == ')' || *ptr == ']'))
4175 heikki.linnakangas 2397 ECB : {
4175 heikki.linnakangas 2398 CBC 5706 : char ch = *ptr++;
2399 :
2400 5706 : if (ch == '\0')
115 tgl 2401 GNC 9 : ereturn(escontext, NULL,
2402 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
4175 heikki.linnakangas 2403 ECB : errmsg("malformed range literal: \"%s\"",
2404 : string),
2405 : errdetail("Unexpected end of input.")));
4175 heikki.linnakangas 2406 GIC 5697 : if (ch == '\\')
2407 : {
2408 21 : if (*ptr == '\0')
115 tgl 2409 UNC 0 : ereturn(escontext, NULL,
4175 heikki.linnakangas 2410 ECB : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
4175 heikki.linnakangas 2411 EUB : errmsg("malformed range literal: \"%s\"",
4175 heikki.linnakangas 2412 ECB : string),
2413 : errdetail("Unexpected end of input.")));
4175 heikki.linnakangas 2414 GIC 21 : appendStringInfoChar(&buf, *ptr++);
4175 heikki.linnakangas 2415 ECB : }
2665 peter_e 2416 CBC 5676 : else if (ch == '"')
2417 : {
4175 heikki.linnakangas 2418 200 : if (!inquote)
4175 heikki.linnakangas 2419 GIC 100 : inquote = true;
2665 peter_e 2420 100 : else if (*ptr == '"')
2421 : {
2422 : /* doubled quote within quote sequence */
4175 heikki.linnakangas 2423 3 : appendStringInfoChar(&buf, *ptr++);
4175 heikki.linnakangas 2424 ECB : }
2425 : else
4175 heikki.linnakangas 2426 CBC 97 : inquote = false;
4175 heikki.linnakangas 2427 ECB : }
2428 : else
4175 heikki.linnakangas 2429 GIC 5476 : appendStringInfoChar(&buf, ch);
4175 heikki.linnakangas 2430 ECB : }
2431 :
4175 heikki.linnakangas 2432 CBC 2162 : *bound_str = buf.data;
4164 bruce 2433 2162 : *infinite = false;
2434 : }
4175 heikki.linnakangas 2435 ECB :
4175 heikki.linnakangas 2436 CBC 2366 : return ptr;
2437 : }
4175 heikki.linnakangas 2438 ECB :
2439 : /*
2440 : * Convert a deserialized range value to text form
2441 : *
2442 : * Inputs are the flags byte, and the two bound values already converted to
2443 : * text (but not yet quoted). If no bound value, pass NULL.
2444 : *
4163 tgl 2445 : * Result is a palloc'd string
2446 : */
2447 : static char *
4156 tgl 2448 CBC 52061 : range_deparse(char flags, const char *lbound_str, const char *ubound_str)
4175 heikki.linnakangas 2449 ECB : {
2450 : StringInfoData buf;
2451 :
4175 heikki.linnakangas 2452 GIC 52061 : if (flags & RANGE_EMPTY)
2453 8452 : return pstrdup(RANGE_EMPTY_LITERAL);
2454 :
4163 tgl 2455 CBC 43609 : initStringInfo(&buf);
2456 :
4156 tgl 2457 GIC 43609 : appendStringInfoChar(&buf, (flags & RANGE_LB_INC) ? '[' : '(');
2458 :
4175 heikki.linnakangas 2459 43609 : if (RANGE_HAS_LBOUND(flags))
2460 42382 : appendStringInfoString(&buf, range_bound_escape(lbound_str));
2461 :
4156 tgl 2462 43609 : appendStringInfoChar(&buf, ',');
2463 :
4175 heikki.linnakangas 2464 43609 : if (RANGE_HAS_UBOUND(flags))
2465 42349 : appendStringInfoString(&buf, range_bound_escape(ubound_str));
2466 :
4156 tgl 2467 43609 : appendStringInfoChar(&buf, (flags & RANGE_UB_INC) ? ']' : ')');
2468 :
4175 heikki.linnakangas 2469 43609 : return buf.data;
2470 : }
2471 :
2472 : /*
2473 : * Helper for range_deparse: quote a bound value as needed
4163 tgl 2474 ECB : *
2475 : * Result is a palloc'd string
2476 : */
2477 : static char *
4156 tgl 2478 GIC 84731 : range_bound_escape(const char *value)
2479 : {
4164 bruce 2480 ECB : bool nq;
2481 : const char *ptr;
2482 : StringInfoData buf;
4175 heikki.linnakangas 2483 :
4175 heikki.linnakangas 2484 GIC 84731 : initStringInfo(&buf);
2485 :
2486 : /* Detect whether we need double quotes for this value */
2487 84731 : nq = (value[0] == '\0'); /* force quotes for empty string */
4156 tgl 2488 CBC 383970 : for (ptr = value; *ptr; ptr++)
2489 : {
2490 299488 : char ch = *ptr;
4175 heikki.linnakangas 2491 ECB :
4175 heikki.linnakangas 2492 GIC 299488 : if (ch == '"' || ch == '\\' ||
4175 heikki.linnakangas 2493 CBC 299419 : ch == '(' || ch == ')' ||
4175 heikki.linnakangas 2494 GIC 299407 : ch == '[' || ch == ']' ||
4175 heikki.linnakangas 2495 CBC 299383 : ch == ',' ||
2496 299383 : isspace((unsigned char) ch))
2497 : {
4175 heikki.linnakangas 2498 GIC 249 : nq = true;
2499 249 : break;
2500 : }
4175 heikki.linnakangas 2501 ECB : }
2502 :
2503 : /* And emit the string */
4175 heikki.linnakangas 2504 GBC 84731 : if (nq)
4175 heikki.linnakangas 2505 GIC 261 : appendStringInfoChar(&buf, '"');
4156 tgl 2506 385917 : for (ptr = value; *ptr; ptr++)
2507 : {
2508 301186 : char ch = *ptr;
4175 heikki.linnakangas 2509 ECB :
4175 heikki.linnakangas 2510 GIC 301186 : if (ch == '"' || ch == '\\')
4175 heikki.linnakangas 2511 CBC 60 : appendStringInfoChar(&buf, ch);
4175 heikki.linnakangas 2512 GIC 301186 : appendStringInfoChar(&buf, ch);
4175 heikki.linnakangas 2513 ECB : }
4175 heikki.linnakangas 2514 CBC 84731 : if (nq)
2515 261 : appendStringInfoChar(&buf, '"');
2516 :
4175 heikki.linnakangas 2517 GIC 84731 : return buf.data;
4175 heikki.linnakangas 2518 ECB : }
2519 :
2520 : /*
4156 tgl 2521 : * Test whether range r1 contains range r2.
2522 : *
2523 : * Caller has already checked that they are the same range type, and looked up
2524 : * the necessary typcache entry.
2525 : */
2526 : bool
1256 peter 2527 CBC 243953 : range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
4175 heikki.linnakangas 2528 ECB : {
2529 : RangeBound lower1;
2530 : RangeBound upper1;
2531 : bool empty1;
2532 : RangeBound lower2;
2533 : RangeBound upper2;
2534 : bool empty2;
2535 :
2536 : /* Different types should be prevented by ANYRANGE matching rules */
3917 heikki.linnakangas 2537 GIC 243953 : if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
3917 heikki.linnakangas 2538 UIC 0 : elog(ERROR, "range types do not match");
2539 :
4163 tgl 2540 GIC 243953 : range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
2541 243953 : range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
2542 :
4156 tgl 2543 ECB : /* If either range is empty, the answer is easy */
4175 heikki.linnakangas 2544 GIC 243953 : if (empty2)
2545 157373 : return true;
2546 86580 : else if (empty1)
4175 heikki.linnakangas 2547 CBC 6783 : return false;
4175 heikki.linnakangas 2548 ECB :
2549 : /* Else we must have lower1 <= lower2 and upper1 >= upper2 */
4163 tgl 2550 CBC 79797 : if (range_cmp_bounds(typcache, &lower1, &lower2) > 0)
4175 heikki.linnakangas 2551 GIC 38018 : return false;
4163 tgl 2552 CBC 41779 : if (range_cmp_bounds(typcache, &upper1, &upper2) < 0)
4175 heikki.linnakangas 2553 GIC 37646 : return false;
4175 heikki.linnakangas 2554 ECB :
4156 tgl 2555 CBC 4133 : return true;
2556 : }
4156 tgl 2557 ECB :
2558 : bool
1256 peter 2559 CBC 62345 : range_contained_by_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
3917 heikki.linnakangas 2560 ECB : {
3917 heikki.linnakangas 2561 GIC 62345 : return range_contains_internal(typcache, r2, r1);
3917 heikki.linnakangas 2562 ECB : }
2563 :
4156 tgl 2564 : /*
2565 : * Test whether range r contains a specific element value.
2566 : */
2567 : bool
1256 peter 2568 GIC 45578 : range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val)
2569 : {
2570 : RangeBound lower;
2571 : RangeBound upper;
2572 : bool empty;
4156 tgl 2573 ECB : int32 cmp;
2574 :
4156 tgl 2575 GIC 45578 : range_deserialize(typcache, r, &lower, &upper, &empty);
2576 :
2577 45578 : if (empty)
2578 6432 : return false;
4156 tgl 2579 ECB :
4156 tgl 2580 GIC 39146 : if (!lower.infinite)
2581 : {
4156 tgl 2582 CBC 37019 : cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
4156 tgl 2583 ECB : typcache->rng_collation,
2584 : lower.val, val));
4156 tgl 2585 CBC 37019 : if (cmp > 0)
4156 tgl 2586 GIC 35691 : return false;
4156 tgl 2587 CBC 1328 : if (cmp == 0 && !lower.inclusive)
4156 tgl 2588 LBC 0 : return false;
4156 tgl 2589 ECB : }
2590 :
4156 tgl 2591 CBC 3455 : if (!upper.infinite)
2592 : {
2593 3437 : cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
4156 tgl 2594 ECB : typcache->rng_collation,
2595 : upper.val, val));
4156 tgl 2596 GIC 3437 : if (cmp < 0)
2597 357 : return false;
2598 3080 : if (cmp == 0 && !upper.inclusive)
4156 tgl 2599 CBC 3 : return false;
4156 tgl 2600 ECB : }
2601 :
4175 heikki.linnakangas 2602 GIC 3095 : return true;
4175 heikki.linnakangas 2603 ECB : }
2604 :
4164 tgl 2605 :
4175 heikki.linnakangas 2606 : /*
4164 tgl 2607 : * datum_compute_size() and datum_write() are used to insert the bound
2608 : * values into a range object. They are modeled after heaptuple.c's
2609 : * heap_compute_data_size() and heap_fill_tuple(), but we need not handle
2610 : * null values here. TYPE_IS_PACKABLE must test the same conditions as
2611 : * heaptuple.c's ATT_IS_PACKABLE macro.
4175 heikki.linnakangas 2612 : */
2613 :
2614 : /* Does datatype allow packing into the 1-byte-header varlena format? */
2615 : #define TYPE_IS_PACKABLE(typlen, typstorage) \
2616 : ((typlen) == -1 && (typstorage) != TYPSTORAGE_PLAIN)
2617 :
2618 : /*
2619 : * Increment data_length by the space needed by the datum, including any
2620 : * preceding alignment padding.
2621 : */
2622 : static Size
4175 heikki.linnakangas 2623 GIC 927320 : datum_compute_size(Size data_length, Datum val, bool typbyval, char typalign,
2624 : int16 typlen, char typstorage)
2625 : {
2626 927320 : if (TYPE_IS_PACKABLE(typlen, typstorage) &&
2627 4704 : VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
2628 : {
2629 : /*
2630 : * we're anticipating converting to a short varlena header, so adjust
2631 : * length and don't count any alignment
4175 heikki.linnakangas 2632 ECB : */
4175 heikki.linnakangas 2633 GBC 4245 : data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
2634 : }
4175 heikki.linnakangas 2635 ECB : else
2636 : {
4175 heikki.linnakangas 2637 GIC 923075 : data_length = att_align_datum(data_length, typalign, typlen, val);
2638 923075 : data_length = att_addlength_datum(data_length, typlen, val);
4175 heikki.linnakangas 2639 ECB : }
2640 :
4175 heikki.linnakangas 2641 CBC 927320 : return data_length;
4175 heikki.linnakangas 2642 ECB : }
2643 :
2644 : /*
4164 tgl 2645 : * Write the given datum beginning at ptr (after advancing to correct
2646 : * alignment, if needed). Return the pointer incremented by space used.
4175 heikki.linnakangas 2647 : */
2648 : static Pointer
4175 heikki.linnakangas 2649 GIC 927320 : datum_write(Pointer ptr, Datum datum, bool typbyval, char typalign,
4175 heikki.linnakangas 2650 ECB : int16 typlen, char typstorage)
2651 : {
2652 : Size data_length;
2653 :
4175 heikki.linnakangas 2654 CBC 927320 : if (typbyval)
2655 : {
4175 heikki.linnakangas 2656 ECB : /* pass-by-value */
4175 heikki.linnakangas 2657 GIC 922616 : ptr = (char *) att_align_nominal(ptr, typalign);
2658 922616 : store_att_byval(ptr, datum, typlen);
2659 922616 : data_length = typlen;
2660 : }
2661 4704 : else if (typlen == -1)
2662 : {
4175 heikki.linnakangas 2663 ECB : /* varlena */
4175 heikki.linnakangas 2664 GIC 4704 : Pointer val = DatumGetPointer(datum);
2665 :
2666 4704 : if (VARATT_IS_EXTERNAL(val))
2667 : {
2668 : /*
2669 : * Throw error, because we must never put a toast pointer inside a
4164 tgl 2670 ECB : * range object. Caller should have detoasted it.
2671 : */
4164 tgl 2672 LBC 0 : elog(ERROR, "cannot store a toast pointer inside a range");
4164 tgl 2673 ECB : data_length = 0; /* keep compiler quiet */
2674 : }
4175 heikki.linnakangas 2675 CBC 4704 : else if (VARATT_IS_SHORT(val))
2676 : {
4175 heikki.linnakangas 2677 ECB : /* no alignment for short varlenas */
4175 heikki.linnakangas 2678 GIC 441 : data_length = VARSIZE_SHORT(val);
2679 441 : memcpy(ptr, val, data_length);
4175 heikki.linnakangas 2680 ECB : }
4175 heikki.linnakangas 2681 CBC 4263 : else if (TYPE_IS_PACKABLE(typlen, typstorage) &&
2682 4263 : VARATT_CAN_MAKE_SHORT(val))
4175 heikki.linnakangas 2683 EUB : {
2684 : /* convert to short varlena -- no alignment */
4175 heikki.linnakangas 2685 GIC 4245 : data_length = VARATT_CONVERTED_SHORT_SIZE(val);
4175 heikki.linnakangas 2686 CBC 4245 : SET_VARSIZE_SHORT(ptr, data_length);
4175 heikki.linnakangas 2687 GIC 4245 : memcpy(ptr + 1, VARDATA(val), data_length - 1);
4175 heikki.linnakangas 2688 ECB : }
2689 : else
2690 : {
2691 : /* full 4-byte header varlena */
4175 heikki.linnakangas 2692 CBC 18 : ptr = (char *) att_align_nominal(ptr, typalign);
2693 18 : data_length = VARSIZE(val);
2694 18 : memcpy(ptr, val, data_length);
2695 : }
2696 : }
4175 heikki.linnakangas 2697 LBC 0 : else if (typlen == -2)
2698 : {
2699 : /* cstring ... never needs alignment */
1131 tgl 2700 UIC 0 : Assert(typalign == TYPALIGN_CHAR);
4175 heikki.linnakangas 2701 0 : data_length = strlen(DatumGetCString(datum)) + 1;
2702 0 : memcpy(ptr, DatumGetPointer(datum), data_length);
2703 : }
2704 : else
2705 : {
2706 : /* fixed-length pass-by-reference */
2707 0 : ptr = (char *) att_align_nominal(ptr, typalign);
2708 0 : Assert(typlen > 0);
2709 0 : data_length = typlen;
2710 0 : memcpy(ptr, DatumGetPointer(datum), data_length);
2711 : }
2712 :
4175 heikki.linnakangas 2713 GIC 927320 : ptr += data_length;
2714 :
2715 927320 : return ptr;
2716 : }
|