00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "postgres.h"
00032
00033 #include "access/hash.h"
00034 #include "lib/stringinfo.h"
00035 #include "libpq/pqformat.h"
00036 #include "utils/builtins.h"
00037 #include "utils/date.h"
00038 #include "utils/int8.h"
00039 #include "utils/lsyscache.h"
00040 #include "utils/rangetypes.h"
00041 #include "utils/timestamp.h"
00042
00043
00044 #define RANGE_EMPTY_LITERAL "empty"
00045
00046
00047 typedef struct RangeIOData
00048 {
00049 TypeCacheEntry *typcache;
00050 Oid typiofunc;
00051 Oid typioparam;
00052 FmgrInfo proc;
00053 } RangeIOData;
00054
00055
00056 static RangeIOData *get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid,
00057 IOFuncSelector func);
00058 static char range_parse_flags(const char *flags_str);
00059 static void range_parse(const char *input_str, char *flags, char **lbound_str,
00060 char **ubound_str);
00061 static const char *range_parse_bound(const char *string, const char *ptr,
00062 char **bound_str, bool *infinite);
00063 static char *range_deparse(char flags, const char *lbound_str,
00064 const char *ubound_str);
00065 static char *range_bound_escape(const char *value);
00066 static Size datum_compute_size(Size sz, Datum datum, bool typbyval,
00067 char typalign, int16 typlen, char typstorage);
00068 static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval,
00069 char typalign, int16 typlen, char typstorage);
00070
00071
00072
00073
00074
00075
00076
00077
00078 Datum
00079 range_in(PG_FUNCTION_ARGS)
00080 {
00081 char *input_str = PG_GETARG_CSTRING(0);
00082 Oid rngtypoid = PG_GETARG_OID(1);
00083 Oid typmod = PG_GETARG_INT32(2);
00084 RangeType *range;
00085 RangeIOData *cache;
00086 char flags;
00087 char *lbound_str;
00088 char *ubound_str;
00089 RangeBound lower;
00090 RangeBound upper;
00091
00092 cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_input);
00093
00094
00095 range_parse(input_str, &flags, &lbound_str, &ubound_str);
00096
00097
00098 if (RANGE_HAS_LBOUND(flags))
00099 lower.val = InputFunctionCall(&cache->proc, lbound_str,
00100 cache->typioparam, typmod);
00101 if (RANGE_HAS_UBOUND(flags))
00102 upper.val = InputFunctionCall(&cache->proc, ubound_str,
00103 cache->typioparam, typmod);
00104
00105 lower.infinite = (flags & RANGE_LB_INF) != 0;
00106 lower.inclusive = (flags & RANGE_LB_INC) != 0;
00107 lower.lower = true;
00108 upper.infinite = (flags & RANGE_UB_INF) != 0;
00109 upper.inclusive = (flags & RANGE_UB_INC) != 0;
00110 upper.lower = false;
00111
00112
00113 range = make_range(cache->typcache, &lower, &upper, flags & RANGE_EMPTY);
00114
00115 PG_RETURN_RANGE(range);
00116 }
00117
00118 Datum
00119 range_out(PG_FUNCTION_ARGS)
00120 {
00121 RangeType *range = PG_GETARG_RANGE(0);
00122 char *output_str;
00123 RangeIOData *cache;
00124 char flags;
00125 char *lbound_str = NULL;
00126 char *ubound_str = NULL;
00127 RangeBound lower;
00128 RangeBound upper;
00129 bool empty;
00130
00131 cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_output);
00132
00133
00134 range_deserialize(cache->typcache, range, &lower, &upper, &empty);
00135 flags = range_get_flags(range);
00136
00137
00138 if (RANGE_HAS_LBOUND(flags))
00139 lbound_str = OutputFunctionCall(&cache->proc, lower.val);
00140 if (RANGE_HAS_UBOUND(flags))
00141 ubound_str = OutputFunctionCall(&cache->proc, upper.val);
00142
00143
00144 output_str = range_deparse(flags, lbound_str, ubound_str);
00145
00146 PG_RETURN_CSTRING(output_str);
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156 Datum
00157 range_recv(PG_FUNCTION_ARGS)
00158 {
00159 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
00160 Oid rngtypoid = PG_GETARG_OID(1);
00161 int32 typmod = PG_GETARG_INT32(2);
00162 RangeType *range;
00163 RangeIOData *cache;
00164 char flags;
00165 RangeBound lower;
00166 RangeBound upper;
00167
00168 cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_receive);
00169
00170
00171 flags = (unsigned char) pq_getmsgbyte(buf);
00172
00173
00174
00175
00176
00177
00178 flags &= (RANGE_EMPTY |
00179 RANGE_LB_INC |
00180 RANGE_LB_INF |
00181 RANGE_UB_INC |
00182 RANGE_UB_INF);
00183
00184
00185 if (RANGE_HAS_LBOUND(flags))
00186 {
00187 uint32 bound_len = pq_getmsgint(buf, 4);
00188 const char *bound_data = pq_getmsgbytes(buf, bound_len);
00189 StringInfoData bound_buf;
00190
00191 initStringInfo(&bound_buf);
00192 appendBinaryStringInfo(&bound_buf, bound_data, bound_len);
00193
00194 lower.val = ReceiveFunctionCall(&cache->proc,
00195 &bound_buf,
00196 cache->typioparam,
00197 typmod);
00198 pfree(bound_buf.data);
00199 }
00200 else
00201 lower.val = (Datum) 0;
00202
00203 if (RANGE_HAS_UBOUND(flags))
00204 {
00205 uint32 bound_len = pq_getmsgint(buf, 4);
00206 const char *bound_data = pq_getmsgbytes(buf, bound_len);
00207 StringInfoData bound_buf;
00208
00209 initStringInfo(&bound_buf);
00210 appendBinaryStringInfo(&bound_buf, bound_data, bound_len);
00211
00212 upper.val = ReceiveFunctionCall(&cache->proc,
00213 &bound_buf,
00214 cache->typioparam,
00215 typmod);
00216 pfree(bound_buf.data);
00217 }
00218 else
00219 upper.val = (Datum) 0;
00220
00221 pq_getmsgend(buf);
00222
00223
00224 lower.infinite = (flags & RANGE_LB_INF) != 0;
00225 lower.inclusive = (flags & RANGE_LB_INC) != 0;
00226 lower.lower = true;
00227 upper.infinite = (flags & RANGE_UB_INF) != 0;
00228 upper.inclusive = (flags & RANGE_UB_INC) != 0;
00229 upper.lower = false;
00230
00231
00232 range = make_range(cache->typcache, &lower, &upper, flags & RANGE_EMPTY);
00233
00234 PG_RETURN_RANGE(range);
00235 }
00236
00237 Datum
00238 range_send(PG_FUNCTION_ARGS)
00239 {
00240 RangeType *range = PG_GETARG_RANGE(0);
00241 StringInfo buf = makeStringInfo();
00242 RangeIOData *cache;
00243 char flags;
00244 RangeBound lower;
00245 RangeBound upper;
00246 bool empty;
00247
00248 cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_send);
00249
00250
00251 range_deserialize(cache->typcache, range, &lower, &upper, &empty);
00252 flags = range_get_flags(range);
00253
00254
00255 pq_begintypsend(buf);
00256
00257 pq_sendbyte(buf, flags);
00258
00259 if (RANGE_HAS_LBOUND(flags))
00260 {
00261 Datum bound = PointerGetDatum(SendFunctionCall(&cache->proc,
00262 lower.val));
00263 uint32 bound_len = VARSIZE(bound) - VARHDRSZ;
00264 char *bound_data = VARDATA(bound);
00265
00266 pq_sendint(buf, bound_len, 4);
00267 pq_sendbytes(buf, bound_data, bound_len);
00268 }
00269
00270 if (RANGE_HAS_UBOUND(flags))
00271 {
00272 Datum bound = PointerGetDatum(SendFunctionCall(&cache->proc,
00273 upper.val));
00274 uint32 bound_len = VARSIZE(bound) - VARHDRSZ;
00275 char *bound_data = VARDATA(bound);
00276
00277 pq_sendint(buf, bound_len, 4);
00278 pq_sendbytes(buf, bound_data, bound_len);
00279 }
00280
00281 PG_RETURN_BYTEA_P(pq_endtypsend(buf));
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291 static RangeIOData *
00292 get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func)
00293 {
00294 RangeIOData *cache = (RangeIOData *) fcinfo->flinfo->fn_extra;
00295
00296 if (cache == NULL || cache->typcache->type_id != rngtypid)
00297 {
00298 int16 typlen;
00299 bool typbyval;
00300 char typalign;
00301 char typdelim;
00302
00303 cache = (RangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00304 sizeof(RangeIOData));
00305 cache->typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
00306 if (cache->typcache->rngelemtype == NULL)
00307 elog(ERROR, "type %u is not a range type", rngtypid);
00308
00309
00310 get_type_io_data(cache->typcache->rngelemtype->type_id,
00311 func,
00312 &typlen,
00313 &typbyval,
00314 &typalign,
00315 &typdelim,
00316 &cache->typioparam,
00317 &cache->typiofunc);
00318
00319 if (!OidIsValid(cache->typiofunc))
00320 {
00321
00322 if (func == IOFunc_receive)
00323 ereport(ERROR,
00324 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00325 errmsg("no binary input function available for type %s",
00326 format_type_be(cache->typcache->rngelemtype->type_id))));
00327 else
00328 ereport(ERROR,
00329 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00330 errmsg("no binary output function available for type %s",
00331 format_type_be(cache->typcache->rngelemtype->type_id))));
00332 }
00333 fmgr_info_cxt(cache->typiofunc, &cache->proc,
00334 fcinfo->flinfo->fn_mcxt);
00335
00336 fcinfo->flinfo->fn_extra = (void *) cache;
00337 }
00338
00339 return cache;
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 Datum
00351 range_constructor2(PG_FUNCTION_ARGS)
00352 {
00353 Datum arg1 = PG_GETARG_DATUM(0);
00354 Datum arg2 = PG_GETARG_DATUM(1);
00355 Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
00356 RangeType *range;
00357 TypeCacheEntry *typcache;
00358 RangeBound lower;
00359 RangeBound upper;
00360
00361 typcache = range_get_typcache(fcinfo, rngtypid);
00362
00363 lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
00364 lower.infinite = PG_ARGISNULL(0);
00365 lower.inclusive = true;
00366 lower.lower = true;
00367
00368 upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
00369 upper.infinite = PG_ARGISNULL(1);
00370 upper.inclusive = false;
00371 upper.lower = false;
00372
00373 range = make_range(typcache, &lower, &upper, false);
00374
00375 PG_RETURN_RANGE(range);
00376 }
00377
00378
00379 Datum
00380 range_constructor3(PG_FUNCTION_ARGS)
00381 {
00382 Datum arg1 = PG_GETARG_DATUM(0);
00383 Datum arg2 = PG_GETARG_DATUM(1);
00384 Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
00385 RangeType *range;
00386 TypeCacheEntry *typcache;
00387 RangeBound lower;
00388 RangeBound upper;
00389 char flags;
00390
00391 typcache = range_get_typcache(fcinfo, rngtypid);
00392
00393 if (PG_ARGISNULL(2))
00394 ereport(ERROR,
00395 (errcode(ERRCODE_DATA_EXCEPTION),
00396 errmsg("range constructor flags argument must not be null")));
00397
00398 flags = range_parse_flags(text_to_cstring(PG_GETARG_TEXT_P(2)));
00399
00400 lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
00401 lower.infinite = PG_ARGISNULL(0);
00402 lower.inclusive = (flags & RANGE_LB_INC) != 0;
00403 lower.lower = true;
00404
00405 upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
00406 upper.infinite = PG_ARGISNULL(1);
00407 upper.inclusive = (flags & RANGE_UB_INC) != 0;
00408 upper.lower = false;
00409
00410 range = make_range(typcache, &lower, &upper, false);
00411
00412 PG_RETURN_RANGE(range);
00413 }
00414
00415
00416
00417
00418
00419 Datum
00420 range_lower(PG_FUNCTION_ARGS)
00421 {
00422 RangeType *r1 = PG_GETARG_RANGE(0);
00423 TypeCacheEntry *typcache;
00424 RangeBound lower;
00425 RangeBound upper;
00426 bool empty;
00427
00428 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00429
00430 range_deserialize(typcache, r1, &lower, &upper, &empty);
00431
00432
00433 if (empty || lower.infinite)
00434 PG_RETURN_NULL();
00435
00436 PG_RETURN_DATUM(lower.val);
00437 }
00438
00439
00440 Datum
00441 range_upper(PG_FUNCTION_ARGS)
00442 {
00443 RangeType *r1 = PG_GETARG_RANGE(0);
00444 TypeCacheEntry *typcache;
00445 RangeBound lower;
00446 RangeBound upper;
00447 bool empty;
00448
00449 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00450
00451 range_deserialize(typcache, r1, &lower, &upper, &empty);
00452
00453
00454 if (empty || upper.infinite)
00455 PG_RETURN_NULL();
00456
00457 PG_RETURN_DATUM(upper.val);
00458 }
00459
00460
00461
00462
00463
00464 Datum
00465 range_empty(PG_FUNCTION_ARGS)
00466 {
00467 RangeType *r1 = PG_GETARG_RANGE(0);
00468 char flags = range_get_flags(r1);
00469
00470 PG_RETURN_BOOL(flags & RANGE_EMPTY);
00471 }
00472
00473
00474 Datum
00475 range_lower_inc(PG_FUNCTION_ARGS)
00476 {
00477 RangeType *r1 = PG_GETARG_RANGE(0);
00478 char flags = range_get_flags(r1);
00479
00480 PG_RETURN_BOOL(flags & RANGE_LB_INC);
00481 }
00482
00483
00484 Datum
00485 range_upper_inc(PG_FUNCTION_ARGS)
00486 {
00487 RangeType *r1 = PG_GETARG_RANGE(0);
00488 char flags = range_get_flags(r1);
00489
00490 PG_RETURN_BOOL(flags & RANGE_UB_INC);
00491 }
00492
00493
00494 Datum
00495 range_lower_inf(PG_FUNCTION_ARGS)
00496 {
00497 RangeType *r1 = PG_GETARG_RANGE(0);
00498 char flags = range_get_flags(r1);
00499
00500 PG_RETURN_BOOL(flags & RANGE_LB_INF);
00501 }
00502
00503
00504 Datum
00505 range_upper_inf(PG_FUNCTION_ARGS)
00506 {
00507 RangeType *r1 = PG_GETARG_RANGE(0);
00508 char flags = range_get_flags(r1);
00509
00510 PG_RETURN_BOOL(flags & RANGE_UB_INF);
00511 }
00512
00513
00514
00515
00516
00517 Datum
00518 range_contains_elem(PG_FUNCTION_ARGS)
00519 {
00520 RangeType *r = PG_GETARG_RANGE(0);
00521 Datum val = PG_GETARG_DATUM(1);
00522 TypeCacheEntry *typcache;
00523
00524 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
00525
00526 PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
00527 }
00528
00529
00530 Datum
00531 elem_contained_by_range(PG_FUNCTION_ARGS)
00532 {
00533 Datum val = PG_GETARG_DATUM(0);
00534 RangeType *r = PG_GETARG_RANGE(1);
00535 TypeCacheEntry *typcache;
00536
00537 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
00538
00539 PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
00540 }
00541
00542
00543
00544
00545
00546 bool
00547 range_eq_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00548 {
00549 RangeBound lower1,
00550 lower2;
00551 RangeBound upper1,
00552 upper2;
00553 bool empty1,
00554 empty2;
00555
00556
00557 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00558 elog(ERROR, "range types do not match");
00559
00560 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00561 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00562
00563 if (empty1 && empty2)
00564 return true;
00565 if (empty1 != empty2)
00566 return false;
00567
00568 if (range_cmp_bounds(typcache, &lower1, &lower2) != 0)
00569 return false;
00570
00571 if (range_cmp_bounds(typcache, &upper1, &upper2) != 0)
00572 return false;
00573
00574 return true;
00575 }
00576
00577
00578 Datum
00579 range_eq(PG_FUNCTION_ARGS)
00580 {
00581 RangeType *r1 = PG_GETARG_RANGE(0);
00582 RangeType *r2 = PG_GETARG_RANGE(1);
00583 TypeCacheEntry *typcache;
00584
00585 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00586
00587 PG_RETURN_BOOL(range_eq_internal(typcache, r1, r2));
00588 }
00589
00590
00591 bool
00592 range_ne_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00593 {
00594 return (!range_eq_internal(typcache, r1, r2));
00595 }
00596
00597
00598 Datum
00599 range_ne(PG_FUNCTION_ARGS)
00600 {
00601 RangeType *r1 = PG_GETARG_RANGE(0);
00602 RangeType *r2 = PG_GETARG_RANGE(1);
00603 TypeCacheEntry *typcache;
00604
00605 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00606
00607 PG_RETURN_BOOL(range_ne_internal(typcache, r1, r2));
00608 }
00609
00610
00611 Datum
00612 range_contains(PG_FUNCTION_ARGS)
00613 {
00614 RangeType *r1 = PG_GETARG_RANGE(0);
00615 RangeType *r2 = PG_GETARG_RANGE(1);
00616 TypeCacheEntry *typcache;
00617
00618 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00619
00620 PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
00621 }
00622
00623
00624 Datum
00625 range_contained_by(PG_FUNCTION_ARGS)
00626 {
00627 RangeType *r1 = PG_GETARG_RANGE(0);
00628 RangeType *r2 = PG_GETARG_RANGE(1);
00629 TypeCacheEntry *typcache;
00630
00631 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00632
00633 PG_RETURN_BOOL(range_contained_by_internal(typcache, r1, r2));
00634 }
00635
00636
00637 bool
00638 range_before_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00639 {
00640 RangeBound lower1,
00641 lower2;
00642 RangeBound upper1,
00643 upper2;
00644 bool empty1,
00645 empty2;
00646
00647
00648 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00649 elog(ERROR, "range types do not match");
00650
00651 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00652 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00653
00654
00655 if (empty1 || empty2)
00656 return false;
00657
00658 return (range_cmp_bounds(typcache, &upper1, &lower2) < 0);
00659 }
00660
00661
00662 Datum
00663 range_before(PG_FUNCTION_ARGS)
00664 {
00665 RangeType *r1 = PG_GETARG_RANGE(0);
00666 RangeType *r2 = PG_GETARG_RANGE(1);
00667 TypeCacheEntry *typcache;
00668
00669 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00670
00671 PG_RETURN_BOOL(range_before_internal(typcache, r1, r2));
00672 }
00673
00674
00675 bool
00676 range_after_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00677 {
00678 RangeBound lower1,
00679 lower2;
00680 RangeBound upper1,
00681 upper2;
00682 bool empty1,
00683 empty2;
00684
00685
00686 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00687 elog(ERROR, "range types do not match");
00688
00689 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00690 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00691
00692
00693 if (empty1 || empty2)
00694 return false;
00695
00696 return (range_cmp_bounds(typcache, &lower1, &upper2) > 0);
00697 }
00698
00699
00700 Datum
00701 range_after(PG_FUNCTION_ARGS)
00702 {
00703 RangeType *r1 = PG_GETARG_RANGE(0);
00704 RangeType *r2 = PG_GETARG_RANGE(1);
00705 TypeCacheEntry *typcache;
00706
00707 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00708
00709 PG_RETURN_BOOL(range_after_internal(typcache, r1, r2));
00710 }
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 bool
00731 bounds_adjacent(TypeCacheEntry *typcache, RangeBound boundA, RangeBound boundB)
00732 {
00733 int cmp;
00734
00735 Assert(!boundA.lower && boundB.lower);
00736
00737 cmp = range_cmp_bound_values(typcache, &boundA, &boundB);
00738 if (cmp < 0)
00739 {
00740 RangeType *r;
00741
00742
00743
00744
00745
00746
00747 if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
00748 return false;
00749
00750
00751
00752
00753
00754
00755
00756 boundA.inclusive = !boundA.inclusive;
00757 boundB.inclusive = !boundB.inclusive;
00758
00759 boundA.lower = true;
00760 boundB.lower = false;
00761 r = make_range(typcache, &boundA, &boundB, false);
00762 return RangeIsEmpty(r);
00763 }
00764 else if (cmp == 0)
00765 return boundA.inclusive != boundB.inclusive;
00766 else
00767 return false;
00768 }
00769
00770
00771 bool
00772 range_adjacent_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00773 {
00774 RangeBound lower1,
00775 lower2;
00776 RangeBound upper1,
00777 upper2;
00778 bool empty1,
00779 empty2;
00780
00781
00782 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00783 elog(ERROR, "range types do not match");
00784
00785 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00786 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00787
00788
00789 if (empty1 || empty2)
00790 return false;
00791
00792
00793
00794
00795
00796 return (bounds_adjacent(typcache, upper1, lower2) ||
00797 bounds_adjacent(typcache, upper2, lower1));
00798 }
00799
00800
00801 Datum
00802 range_adjacent(PG_FUNCTION_ARGS)
00803 {
00804 RangeType *r1 = PG_GETARG_RANGE(0);
00805 RangeType *r2 = PG_GETARG_RANGE(1);
00806 TypeCacheEntry *typcache;
00807
00808 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00809
00810 PG_RETURN_BOOL(range_adjacent_internal(typcache, r1, r2));
00811 }
00812
00813
00814 bool
00815 range_overlaps_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00816 {
00817 RangeBound lower1,
00818 lower2;
00819 RangeBound upper1,
00820 upper2;
00821 bool empty1,
00822 empty2;
00823
00824
00825 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00826 elog(ERROR, "range types do not match");
00827
00828 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00829 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00830
00831
00832 if (empty1 || empty2)
00833 return false;
00834
00835 if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 &&
00836 range_cmp_bounds(typcache, &lower1, &upper2) <= 0)
00837 return true;
00838
00839 if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 &&
00840 range_cmp_bounds(typcache, &lower2, &upper1) <= 0)
00841 return true;
00842
00843 return false;
00844 }
00845
00846
00847 Datum
00848 range_overlaps(PG_FUNCTION_ARGS)
00849 {
00850 RangeType *r1 = PG_GETARG_RANGE(0);
00851 RangeType *r2 = PG_GETARG_RANGE(1);
00852 TypeCacheEntry *typcache;
00853
00854 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00855
00856 PG_RETURN_BOOL(range_overlaps_internal(typcache, r1, r2));
00857 }
00858
00859
00860 bool
00861 range_overleft_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00862 {
00863 RangeBound lower1,
00864 lower2;
00865 RangeBound upper1,
00866 upper2;
00867 bool empty1,
00868 empty2;
00869
00870
00871 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00872 elog(ERROR, "range types do not match");
00873
00874 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00875 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00876
00877
00878 if (empty1 || empty2)
00879 return false;
00880
00881 if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
00882 return true;
00883
00884 return false;
00885 }
00886
00887
00888 Datum
00889 range_overleft(PG_FUNCTION_ARGS)
00890 {
00891 RangeType *r1 = PG_GETARG_RANGE(0);
00892 RangeType *r2 = PG_GETARG_RANGE(1);
00893 TypeCacheEntry *typcache;
00894
00895 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00896
00897 PG_RETURN_BOOL(range_overleft_internal(typcache, r1, r2));
00898 }
00899
00900
00901 bool
00902 range_overright_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
00903 {
00904 RangeBound lower1,
00905 lower2;
00906 RangeBound upper1,
00907 upper2;
00908 bool empty1,
00909 empty2;
00910
00911
00912 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00913 elog(ERROR, "range types do not match");
00914
00915 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00916 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00917
00918
00919 if (empty1 || empty2)
00920 PG_RETURN_BOOL(false);
00921
00922 if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
00923 PG_RETURN_BOOL(true);
00924
00925 PG_RETURN_BOOL(false);
00926 }
00927
00928
00929 Datum
00930 range_overright(PG_FUNCTION_ARGS)
00931 {
00932 RangeType *r1 = PG_GETARG_RANGE(0);
00933 RangeType *r2 = PG_GETARG_RANGE(1);
00934 TypeCacheEntry *typcache;
00935
00936 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00937
00938 PG_RETURN_BOOL(range_overright_internal(typcache, r1, r2));
00939 }
00940
00941
00942
00943
00944
00945 Datum
00946 range_minus(PG_FUNCTION_ARGS)
00947 {
00948 RangeType *r1 = PG_GETARG_RANGE(0);
00949 RangeType *r2 = PG_GETARG_RANGE(1);
00950 TypeCacheEntry *typcache;
00951 RangeBound lower1,
00952 lower2;
00953 RangeBound upper1,
00954 upper2;
00955 bool empty1,
00956 empty2;
00957 int cmp_l1l2,
00958 cmp_l1u2,
00959 cmp_u1l2,
00960 cmp_u1u2;
00961
00962
00963 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
00964 elog(ERROR, "range types do not match");
00965
00966 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
00967
00968 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
00969 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
00970
00971
00972 if (empty1 || empty2)
00973 PG_RETURN_RANGE(r1);
00974
00975 cmp_l1l2 = range_cmp_bounds(typcache, &lower1, &lower2);
00976 cmp_l1u2 = range_cmp_bounds(typcache, &lower1, &upper2);
00977 cmp_u1l2 = range_cmp_bounds(typcache, &upper1, &lower2);
00978 cmp_u1u2 = range_cmp_bounds(typcache, &upper1, &upper2);
00979
00980 if (cmp_l1l2 < 0 && cmp_u1u2 > 0)
00981 ereport(ERROR,
00982 (errcode(ERRCODE_DATA_EXCEPTION),
00983 errmsg("result of range difference would not be contiguous")));
00984
00985 if (cmp_l1u2 > 0 || cmp_u1l2 < 0)
00986 PG_RETURN_RANGE(r1);
00987
00988 if (cmp_l1l2 >= 0 && cmp_u1u2 <= 0)
00989 PG_RETURN_RANGE(make_empty_range(typcache));
00990
00991 if (cmp_l1l2 <= 0 && cmp_u1l2 >= 0 && cmp_u1u2 <= 0)
00992 {
00993 lower2.inclusive = !lower2.inclusive;
00994 lower2.lower = false;
00995 PG_RETURN_RANGE(make_range(typcache, &lower1, &lower2, false));
00996 }
00997
00998 if (cmp_l1l2 >= 0 && cmp_u1u2 >= 0 && cmp_l1u2 <= 0)
00999 {
01000 upper2.inclusive = !upper2.inclusive;
01001 upper2.lower = true;
01002 PG_RETURN_RANGE(make_range(typcache, &upper2, &upper1, false));
01003 }
01004
01005 elog(ERROR, "unexpected case in range_minus");
01006 PG_RETURN_NULL();
01007 }
01008
01009
01010 Datum
01011 range_union(PG_FUNCTION_ARGS)
01012 {
01013 RangeType *r1 = PG_GETARG_RANGE(0);
01014 RangeType *r2 = PG_GETARG_RANGE(1);
01015 TypeCacheEntry *typcache;
01016 RangeBound lower1,
01017 lower2;
01018 RangeBound upper1,
01019 upper2;
01020 bool empty1,
01021 empty2;
01022 RangeBound *result_lower;
01023 RangeBound *result_upper;
01024
01025
01026 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
01027 elog(ERROR, "range types do not match");
01028
01029 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
01030
01031 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
01032 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
01033
01034
01035 if (empty1)
01036 PG_RETURN_RANGE(r2);
01037 if (empty2)
01038 PG_RETURN_RANGE(r1);
01039
01040 if (!DatumGetBool(range_overlaps(fcinfo)) &&
01041 !DatumGetBool(range_adjacent(fcinfo)))
01042 ereport(ERROR,
01043 (errcode(ERRCODE_DATA_EXCEPTION),
01044 errmsg("result of range union would not be contiguous")));
01045
01046 if (range_cmp_bounds(typcache, &lower1, &lower2) < 0)
01047 result_lower = &lower1;
01048 else
01049 result_lower = &lower2;
01050
01051 if (range_cmp_bounds(typcache, &upper1, &upper2) > 0)
01052 result_upper = &upper1;
01053 else
01054 result_upper = &upper2;
01055
01056 PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
01057 }
01058
01059
01060 Datum
01061 range_intersect(PG_FUNCTION_ARGS)
01062 {
01063 RangeType *r1 = PG_GETARG_RANGE(0);
01064 RangeType *r2 = PG_GETARG_RANGE(1);
01065 TypeCacheEntry *typcache;
01066 RangeBound lower1,
01067 lower2;
01068 RangeBound upper1,
01069 upper2;
01070 bool empty1,
01071 empty2;
01072 RangeBound *result_lower;
01073 RangeBound *result_upper;
01074
01075
01076 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
01077 elog(ERROR, "range types do not match");
01078
01079 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
01080
01081 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
01082 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
01083
01084 if (empty1 || empty2 || !DatumGetBool(range_overlaps(fcinfo)))
01085 PG_RETURN_RANGE(make_empty_range(typcache));
01086
01087 if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
01088 result_lower = &lower1;
01089 else
01090 result_lower = &lower2;
01091
01092 if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
01093 result_upper = &upper1;
01094 else
01095 result_upper = &upper2;
01096
01097 PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
01098 }
01099
01100
01101
01102
01103 Datum
01104 range_cmp(PG_FUNCTION_ARGS)
01105 {
01106 RangeType *r1 = PG_GETARG_RANGE(0);
01107 RangeType *r2 = PG_GETARG_RANGE(1);
01108 TypeCacheEntry *typcache;
01109 RangeBound lower1,
01110 lower2;
01111 RangeBound upper1,
01112 upper2;
01113 bool empty1,
01114 empty2;
01115 int cmp;
01116
01117
01118 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
01119 elog(ERROR, "range types do not match");
01120
01121 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
01122
01123 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
01124 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
01125
01126
01127 if (empty1 && empty2)
01128 PG_RETURN_INT32(0);
01129 else if (empty1)
01130 PG_RETURN_INT32(-1);
01131 else if (empty2)
01132 PG_RETURN_INT32(1);
01133
01134 if ((cmp = range_cmp_bounds(typcache, &lower1, &lower2)) != 0)
01135 PG_RETURN_INT32(cmp);
01136
01137 PG_RETURN_INT32(range_cmp_bounds(typcache, &upper1, &upper2));
01138 }
01139
01140
01141 Datum
01142 range_lt(PG_FUNCTION_ARGS)
01143 {
01144 int cmp = range_cmp(fcinfo);
01145
01146 PG_RETURN_BOOL(cmp < 0);
01147 }
01148
01149 Datum
01150 range_le(PG_FUNCTION_ARGS)
01151 {
01152 int cmp = range_cmp(fcinfo);
01153
01154 PG_RETURN_BOOL(cmp <= 0);
01155 }
01156
01157 Datum
01158 range_ge(PG_FUNCTION_ARGS)
01159 {
01160 int cmp = range_cmp(fcinfo);
01161
01162 PG_RETURN_BOOL(cmp >= 0);
01163 }
01164
01165 Datum
01166 range_gt(PG_FUNCTION_ARGS)
01167 {
01168 int cmp = range_cmp(fcinfo);
01169
01170 PG_RETURN_BOOL(cmp > 0);
01171 }
01172
01173
01174
01175
01176 Datum
01177 hash_range(PG_FUNCTION_ARGS)
01178 {
01179 RangeType *r = PG_GETARG_RANGE(0);
01180 uint32 result;
01181 TypeCacheEntry *typcache;
01182 TypeCacheEntry *scache;
01183 RangeBound lower;
01184 RangeBound upper;
01185 bool empty;
01186 char flags;
01187 uint32 lower_hash;
01188 uint32 upper_hash;
01189
01190 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
01191
01192
01193 range_deserialize(typcache, r, &lower, &upper, &empty);
01194 flags = range_get_flags(r);
01195
01196
01197
01198
01199 scache = typcache->rngelemtype;
01200 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
01201 {
01202 scache = lookup_type_cache(scache->type_id, TYPECACHE_HASH_PROC_FINFO);
01203 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
01204 ereport(ERROR,
01205 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01206 errmsg("could not identify a hash function for type %s",
01207 format_type_be(scache->type_id))));
01208 }
01209
01210
01211
01212
01213 if (RANGE_HAS_LBOUND(flags))
01214 lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
01215 typcache->rng_collation,
01216 lower.val));
01217 else
01218 lower_hash = 0;
01219
01220 if (RANGE_HAS_UBOUND(flags))
01221 upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
01222 typcache->rng_collation,
01223 upper.val));
01224 else
01225 upper_hash = 0;
01226
01227
01228 result = hash_uint32((uint32) flags);
01229 result ^= lower_hash;
01230 result = (result << 1) | (result >> 31);
01231 result ^= upper_hash;
01232
01233 PG_RETURN_INT32(result);
01234 }
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244 Datum
01245 int4range_canonical(PG_FUNCTION_ARGS)
01246 {
01247 RangeType *r = PG_GETARG_RANGE(0);
01248 TypeCacheEntry *typcache;
01249 RangeBound lower;
01250 RangeBound upper;
01251 bool empty;
01252
01253 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
01254
01255 range_deserialize(typcache, r, &lower, &upper, &empty);
01256
01257 if (empty)
01258 PG_RETURN_RANGE(r);
01259
01260 if (!lower.infinite && !lower.inclusive)
01261 {
01262 lower.val = DirectFunctionCall2(int4pl, lower.val, Int32GetDatum(1));
01263 lower.inclusive = true;
01264 }
01265
01266 if (!upper.infinite && upper.inclusive)
01267 {
01268 upper.val = DirectFunctionCall2(int4pl, upper.val, Int32GetDatum(1));
01269 upper.inclusive = false;
01270 }
01271
01272 PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
01273 }
01274
01275 Datum
01276 int8range_canonical(PG_FUNCTION_ARGS)
01277 {
01278 RangeType *r = PG_GETARG_RANGE(0);
01279 TypeCacheEntry *typcache;
01280 RangeBound lower;
01281 RangeBound upper;
01282 bool empty;
01283
01284 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
01285
01286 range_deserialize(typcache, r, &lower, &upper, &empty);
01287
01288 if (empty)
01289 PG_RETURN_RANGE(r);
01290
01291 if (!lower.infinite && !lower.inclusive)
01292 {
01293 lower.val = DirectFunctionCall2(int8pl, lower.val, Int64GetDatum(1));
01294 lower.inclusive = true;
01295 }
01296
01297 if (!upper.infinite && upper.inclusive)
01298 {
01299 upper.val = DirectFunctionCall2(int8pl, upper.val, Int64GetDatum(1));
01300 upper.inclusive = false;
01301 }
01302
01303 PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
01304 }
01305
01306 Datum
01307 daterange_canonical(PG_FUNCTION_ARGS)
01308 {
01309 RangeType *r = PG_GETARG_RANGE(0);
01310 TypeCacheEntry *typcache;
01311 RangeBound lower;
01312 RangeBound upper;
01313 bool empty;
01314
01315 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
01316
01317 range_deserialize(typcache, r, &lower, &upper, &empty);
01318
01319 if (empty)
01320 PG_RETURN_RANGE(r);
01321
01322 if (!lower.infinite && !lower.inclusive)
01323 {
01324 lower.val = DirectFunctionCall2(date_pli, lower.val, Int32GetDatum(1));
01325 lower.inclusive = true;
01326 }
01327
01328 if (!upper.infinite && upper.inclusive)
01329 {
01330 upper.val = DirectFunctionCall2(date_pli, upper.val, Int32GetDatum(1));
01331 upper.inclusive = false;
01332 }
01333
01334 PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
01335 }
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 Datum
01350 int4range_subdiff(PG_FUNCTION_ARGS)
01351 {
01352 int32 v1 = PG_GETARG_INT32(0);
01353 int32 v2 = PG_GETARG_INT32(1);
01354
01355 PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
01356 }
01357
01358 Datum
01359 int8range_subdiff(PG_FUNCTION_ARGS)
01360 {
01361 int64 v1 = PG_GETARG_INT64(0);
01362 int64 v2 = PG_GETARG_INT64(1);
01363
01364 PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
01365 }
01366
01367 Datum
01368 numrange_subdiff(PG_FUNCTION_ARGS)
01369 {
01370 Datum v1 = PG_GETARG_DATUM(0);
01371 Datum v2 = PG_GETARG_DATUM(1);
01372 Datum numresult;
01373 float8 floatresult;
01374
01375 numresult = DirectFunctionCall2(numeric_sub, v1, v2);
01376
01377 floatresult = DatumGetFloat8(DirectFunctionCall1(numeric_float8,
01378 numresult));
01379
01380 PG_RETURN_FLOAT8(floatresult);
01381 }
01382
01383 Datum
01384 daterange_subdiff(PG_FUNCTION_ARGS)
01385 {
01386 int32 v1 = PG_GETARG_INT32(0);
01387 int32 v2 = PG_GETARG_INT32(1);
01388
01389 PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
01390 }
01391
01392 Datum
01393 tsrange_subdiff(PG_FUNCTION_ARGS)
01394 {
01395 Timestamp v1 = PG_GETARG_TIMESTAMP(0);
01396 Timestamp v2 = PG_GETARG_TIMESTAMP(1);
01397 float8 result;
01398
01399 #ifdef HAVE_INT64_TIMESTAMP
01400 result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
01401 #else
01402 result = v1 - v2;
01403 #endif
01404
01405 PG_RETURN_FLOAT8(result);
01406 }
01407
01408 Datum
01409 tstzrange_subdiff(PG_FUNCTION_ARGS)
01410 {
01411 Timestamp v1 = PG_GETARG_TIMESTAMP(0);
01412 Timestamp v2 = PG_GETARG_TIMESTAMP(1);
01413 float8 result;
01414
01415 #ifdef HAVE_INT64_TIMESTAMP
01416 result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
01417 #else
01418 result = v1 - v2;
01419 #endif
01420
01421 PG_RETURN_FLOAT8(result);
01422 }
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441 TypeCacheEntry *
01442 range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
01443 {
01444 TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
01445
01446 if (typcache == NULL ||
01447 typcache->type_id != rngtypid)
01448 {
01449 typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
01450 if (typcache->rngelemtype == NULL)
01451 elog(ERROR, "type %u is not a range type", rngtypid);
01452 fcinfo->flinfo->fn_extra = (void *) typcache;
01453 }
01454
01455 return typcache;
01456 }
01457
01458
01459
01460
01461
01462
01463
01464
01465 RangeType *
01466 range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
01467 bool empty)
01468 {
01469 RangeType *range;
01470 int cmp;
01471 Size msize;
01472 Pointer ptr;
01473 int16 typlen;
01474 bool typbyval;
01475 char typalign;
01476 char typstorage;
01477 char flags = 0;
01478
01479
01480
01481
01482
01483 Assert(lower->lower);
01484 Assert(!upper->lower);
01485
01486 if (empty)
01487 flags |= RANGE_EMPTY;
01488 else
01489 {
01490 cmp = range_cmp_bound_values(typcache, lower, upper);
01491
01492
01493 if (cmp > 0)
01494 ereport(ERROR,
01495 (errcode(ERRCODE_DATA_EXCEPTION),
01496 errmsg("range lower bound must be less than or equal to range upper bound")));
01497
01498
01499 if (cmp == 0 && !(lower->inclusive && upper->inclusive))
01500 flags |= RANGE_EMPTY;
01501 else
01502 {
01503
01504 if (lower->infinite)
01505 flags |= RANGE_LB_INF;
01506 else if (lower->inclusive)
01507 flags |= RANGE_LB_INC;
01508 if (upper->infinite)
01509 flags |= RANGE_UB_INF;
01510 else if (upper->inclusive)
01511 flags |= RANGE_UB_INC;
01512 }
01513 }
01514
01515
01516 typlen = typcache->rngelemtype->typlen;
01517 typbyval = typcache->rngelemtype->typbyval;
01518 typalign = typcache->rngelemtype->typalign;
01519 typstorage = typcache->rngelemtype->typstorage;
01520
01521
01522 msize = sizeof(RangeType);
01523 Assert(msize == MAXALIGN(msize));
01524
01525
01526 if (RANGE_HAS_LBOUND(flags))
01527 {
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537 if (typlen == -1)
01538 lower->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(lower->val));
01539
01540 msize = datum_compute_size(msize, lower->val, typbyval, typalign,
01541 typlen, typstorage);
01542 }
01543
01544 if (RANGE_HAS_UBOUND(flags))
01545 {
01546
01547 if (typlen == -1)
01548 upper->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(upper->val));
01549
01550 msize = datum_compute_size(msize, upper->val, typbyval, typalign,
01551 typlen, typstorage);
01552 }
01553
01554
01555 msize += sizeof(char);
01556
01557
01558 range = (RangeType *) palloc0(msize);
01559 SET_VARSIZE(range, msize);
01560
01561
01562 range->rangetypid = typcache->type_id;
01563
01564 ptr = (char *) (range + 1);
01565
01566 if (RANGE_HAS_LBOUND(flags))
01567 {
01568 Assert(lower->lower);
01569 ptr = datum_write(ptr, lower->val, typbyval, typalign, typlen,
01570 typstorage);
01571 }
01572
01573 if (RANGE_HAS_UBOUND(flags))
01574 {
01575 Assert(!upper->lower);
01576 ptr = datum_write(ptr, upper->val, typbyval, typalign, typlen,
01577 typstorage);
01578 }
01579
01580 *((char *) ptr) = flags;
01581
01582 return range;
01583 }
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594 void
01595 range_deserialize(TypeCacheEntry *typcache, RangeType *range,
01596 RangeBound *lower, RangeBound *upper, bool *empty)
01597 {
01598 char flags;
01599 int16 typlen;
01600 bool typbyval;
01601 char typalign;
01602 Pointer ptr;
01603 Datum lbound;
01604 Datum ubound;
01605
01606
01607 Assert(RangeTypeGetOid(range) == typcache->type_id);
01608
01609
01610 flags = *((char *) range + VARSIZE(range) - 1);
01611
01612
01613 typlen = typcache->rngelemtype->typlen;
01614 typbyval = typcache->rngelemtype->typbyval;
01615 typalign = typcache->rngelemtype->typalign;
01616
01617
01618 ptr = (Pointer) (range + 1);
01619
01620
01621 if (RANGE_HAS_LBOUND(flags))
01622 {
01623
01624 lbound = fetch_att(ptr, typbyval, typlen);
01625 ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
01626 }
01627 else
01628 lbound = (Datum) 0;
01629
01630
01631 if (RANGE_HAS_UBOUND(flags))
01632 {
01633 ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
01634 ubound = fetch_att(ptr, typbyval, typlen);
01635
01636 }
01637 else
01638 ubound = (Datum) 0;
01639
01640
01641
01642 *empty = (flags & RANGE_EMPTY) != 0;
01643
01644 lower->val = lbound;
01645 lower->infinite = (flags & RANGE_LB_INF) != 0;
01646 lower->inclusive = (flags & RANGE_LB_INC) != 0;
01647 lower->lower = true;
01648
01649 upper->val = ubound;
01650 upper->infinite = (flags & RANGE_UB_INF) != 0;
01651 upper->inclusive = (flags & RANGE_UB_INC) != 0;
01652 upper->lower = false;
01653 }
01654
01655
01656
01657
01658
01659
01660
01661 char
01662 range_get_flags(RangeType *range)
01663 {
01664
01665 return *((char *) range + VARSIZE(range) - 1);
01666 }
01667
01668
01669
01670
01671
01672
01673
01674
01675 void
01676 range_set_contain_empty(RangeType *range)
01677 {
01678 char *flagsp;
01679
01680
01681 flagsp = (char *) range + VARSIZE(range) - 1;
01682
01683 *flagsp |= RANGE_CONTAIN_EMPTY;
01684 }
01685
01686
01687
01688
01689
01690 RangeType *
01691 make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
01692 bool empty)
01693 {
01694 RangeType *range;
01695
01696 range = range_serialize(typcache, lower, upper, empty);
01697
01698
01699 if (OidIsValid(typcache->rng_canonical_finfo.fn_oid) &&
01700 !RangeIsEmpty(range))
01701 range = DatumGetRangeType(FunctionCall1(&typcache->rng_canonical_finfo,
01702 RangeTypeGetDatum(range)));
01703
01704 return range;
01705 }
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730 int
01731 range_cmp_bounds(TypeCacheEntry *typcache, RangeBound *b1, RangeBound *b2)
01732 {
01733 int32 result;
01734
01735
01736
01737
01738
01739 if (b1->infinite && b2->infinite)
01740 {
01741
01742
01743
01744
01745 if (b1->lower == b2->lower)
01746 return 0;
01747 else
01748 return b1->lower ? -1 : 1;
01749 }
01750 else if (b1->infinite)
01751 return b1->lower ? -1 : 1;
01752 else if (b2->infinite)
01753 return b2->lower ? 1 : -1;
01754
01755
01756
01757
01758 result = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
01759 typcache->rng_collation,
01760 b1->val, b2->val));
01761
01762
01763
01764
01765
01766
01767 if (result == 0)
01768 {
01769 if (!b1->inclusive && !b2->inclusive)
01770 {
01771
01772 if (b1->lower == b2->lower)
01773 return 0;
01774 else
01775 return b1->lower ? 1 : -1;
01776 }
01777 else if (!b1->inclusive)
01778 return b1->lower ? 1 : -1;
01779 else if (!b2->inclusive)
01780 return b2->lower ? -1 : 1;
01781 else
01782 {
01783
01784
01785
01786
01787
01788 return 0;
01789 }
01790 }
01791
01792 return result;
01793 }
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804 int
01805 range_cmp_bound_values(TypeCacheEntry *typcache, RangeBound *b1,
01806 RangeBound *b2)
01807 {
01808
01809
01810
01811
01812 if (b1->infinite && b2->infinite)
01813 {
01814
01815
01816
01817
01818 if (b1->lower == b2->lower)
01819 return 0;
01820 else
01821 return b1->lower ? -1 : 1;
01822 }
01823 else if (b1->infinite)
01824 return b1->lower ? -1 : 1;
01825 else if (b2->infinite)
01826 return b2->lower ? 1 : -1;
01827
01828
01829
01830
01831 return DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
01832 typcache->rng_collation,
01833 b1->val, b2->val));
01834 }
01835
01836
01837
01838
01839 RangeType *
01840 make_empty_range(TypeCacheEntry *typcache)
01841 {
01842 RangeBound lower;
01843 RangeBound upper;
01844
01845 lower.val = (Datum) 0;
01846 lower.infinite = false;
01847 lower.inclusive = false;
01848 lower.lower = true;
01849
01850 upper.val = (Datum) 0;
01851 upper.infinite = false;
01852 upper.inclusive = false;
01853 upper.lower = false;
01854
01855 return make_range(typcache, &lower, &upper, true);
01856 }
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869 static char
01870 range_parse_flags(const char *flags_str)
01871 {
01872 char flags = 0;
01873
01874 if (flags_str[0] == '\0' ||
01875 flags_str[1] == '\0' ||
01876 flags_str[2] != '\0')
01877 ereport(ERROR,
01878 (errcode(ERRCODE_SYNTAX_ERROR),
01879 errmsg("invalid range bound flags"),
01880 errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
01881
01882 switch (flags_str[0])
01883 {
01884 case '[':
01885 flags |= RANGE_LB_INC;
01886 break;
01887 case '(':
01888 break;
01889 default:
01890 ereport(ERROR,
01891 (errcode(ERRCODE_SYNTAX_ERROR),
01892 errmsg("invalid range bound flags"),
01893 errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
01894 }
01895
01896 switch (flags_str[1])
01897 {
01898 case ']':
01899 flags |= RANGE_UB_INC;
01900 break;
01901 case ')':
01902 break;
01903 default:
01904 ereport(ERROR,
01905 (errcode(ERRCODE_SYNTAX_ERROR),
01906 errmsg("invalid range bound flags"),
01907 errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
01908 }
01909
01910 return flags;
01911 }
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941 static void
01942 range_parse(const char *string, char *flags, char **lbound_str,
01943 char **ubound_str)
01944 {
01945 const char *ptr = string;
01946 bool infinite;
01947
01948 *flags = 0;
01949
01950
01951 while (*ptr != '\0' && isspace((unsigned char) *ptr))
01952 ptr++;
01953
01954
01955 if (pg_strncasecmp(ptr, RANGE_EMPTY_LITERAL,
01956 strlen(RANGE_EMPTY_LITERAL)) == 0)
01957 {
01958 *flags = RANGE_EMPTY;
01959 *lbound_str = NULL;
01960 *ubound_str = NULL;
01961
01962 ptr += strlen(RANGE_EMPTY_LITERAL);
01963
01964
01965 while (*ptr != '\0' && isspace((unsigned char) *ptr))
01966 ptr++;
01967
01968
01969 if (*ptr != '\0')
01970 ereport(ERROR,
01971 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01972 errmsg("malformed range literal: \"%s\"",
01973 string),
01974 errdetail("Junk after \"empty\" key word.")));
01975
01976 return;
01977 }
01978
01979 if (*ptr == '[')
01980 {
01981 *flags |= RANGE_LB_INC;
01982 ptr++;
01983 }
01984 else if (*ptr == '(')
01985 ptr++;
01986 else
01987 ereport(ERROR,
01988 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01989 errmsg("malformed range literal: \"%s\"",
01990 string),
01991 errdetail("Missing left parenthesis or bracket.")));
01992
01993 ptr = range_parse_bound(string, ptr, lbound_str, &infinite);
01994 if (infinite)
01995 *flags |= RANGE_LB_INF;
01996
01997 if (*ptr == ',')
01998 ptr++;
01999 else
02000 ereport(ERROR,
02001 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
02002 errmsg("malformed range literal: \"%s\"",
02003 string),
02004 errdetail("Missing comma after lower bound.")));
02005
02006 ptr = range_parse_bound(string, ptr, ubound_str, &infinite);
02007 if (infinite)
02008 *flags |= RANGE_UB_INF;
02009
02010 if (*ptr == ']')
02011 {
02012 *flags |= RANGE_UB_INC;
02013 ptr++;
02014 }
02015 else if (*ptr == ')')
02016 ptr++;
02017 else
02018 ereport(ERROR,
02019 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
02020 errmsg("malformed range literal: \"%s\"",
02021 string),
02022 errdetail("Too many commas.")));
02023
02024
02025 while (*ptr != '\0' && isspace((unsigned char) *ptr))
02026 ptr++;
02027
02028 if (*ptr != '\0')
02029 ereport(ERROR,
02030 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
02031 errmsg("malformed range literal: \"%s\"",
02032 string),
02033 errdetail("Junk after right parenthesis or bracket.")));
02034 }
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050 static const char *
02051 range_parse_bound(const char *string, const char *ptr,
02052 char **bound_str, bool *infinite)
02053 {
02054 StringInfoData buf;
02055
02056
02057 if (*ptr == ',' || *ptr == ')' || *ptr == ']')
02058 {
02059 *bound_str = NULL;
02060 *infinite = true;
02061 }
02062 else
02063 {
02064
02065 bool inquote = false;
02066
02067 initStringInfo(&buf);
02068 while (inquote || !(*ptr == ',' || *ptr == ')' || *ptr == ']'))
02069 {
02070 char ch = *ptr++;
02071
02072 if (ch == '\0')
02073 ereport(ERROR,
02074 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
02075 errmsg("malformed range literal: \"%s\"",
02076 string),
02077 errdetail("Unexpected end of input.")));
02078 if (ch == '\\')
02079 {
02080 if (*ptr == '\0')
02081 ereport(ERROR,
02082 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
02083 errmsg("malformed range literal: \"%s\"",
02084 string),
02085 errdetail("Unexpected end of input.")));
02086 appendStringInfoChar(&buf, *ptr++);
02087 }
02088 else if (ch == '\"')
02089 {
02090 if (!inquote)
02091 inquote = true;
02092 else if (*ptr == '\"')
02093 {
02094
02095 appendStringInfoChar(&buf, *ptr++);
02096 }
02097 else
02098 inquote = false;
02099 }
02100 else
02101 appendStringInfoChar(&buf, ch);
02102 }
02103
02104 *bound_str = buf.data;
02105 *infinite = false;
02106 }
02107
02108 return ptr;
02109 }
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119 static char *
02120 range_deparse(char flags, const char *lbound_str, const char *ubound_str)
02121 {
02122 StringInfoData buf;
02123
02124 if (flags & RANGE_EMPTY)
02125 return pstrdup(RANGE_EMPTY_LITERAL);
02126
02127 initStringInfo(&buf);
02128
02129 appendStringInfoChar(&buf, (flags & RANGE_LB_INC) ? '[' : '(');
02130
02131 if (RANGE_HAS_LBOUND(flags))
02132 appendStringInfoString(&buf, range_bound_escape(lbound_str));
02133
02134 appendStringInfoChar(&buf, ',');
02135
02136 if (RANGE_HAS_UBOUND(flags))
02137 appendStringInfoString(&buf, range_bound_escape(ubound_str));
02138
02139 appendStringInfoChar(&buf, (flags & RANGE_UB_INC) ? ']' : ')');
02140
02141 return buf.data;
02142 }
02143
02144
02145
02146
02147
02148
02149 static char *
02150 range_bound_escape(const char *value)
02151 {
02152 bool nq;
02153 const char *ptr;
02154 StringInfoData buf;
02155
02156 initStringInfo(&buf);
02157
02158
02159 nq = (value[0] == '\0');
02160 for (ptr = value; *ptr; ptr++)
02161 {
02162 char ch = *ptr;
02163
02164 if (ch == '"' || ch == '\\' ||
02165 ch == '(' || ch == ')' ||
02166 ch == '[' || ch == ']' ||
02167 ch == ',' ||
02168 isspace((unsigned char) ch))
02169 {
02170 nq = true;
02171 break;
02172 }
02173 }
02174
02175
02176 if (nq)
02177 appendStringInfoChar(&buf, '"');
02178 for (ptr = value; *ptr; ptr++)
02179 {
02180 char ch = *ptr;
02181
02182 if (ch == '"' || ch == '\\')
02183 appendStringInfoChar(&buf, ch);
02184 appendStringInfoChar(&buf, ch);
02185 }
02186 if (nq)
02187 appendStringInfoChar(&buf, '"');
02188
02189 return buf.data;
02190 }
02191
02192
02193
02194
02195
02196
02197
02198 bool
02199 range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
02200 {
02201 RangeBound lower1;
02202 RangeBound upper1;
02203 bool empty1;
02204 RangeBound lower2;
02205 RangeBound upper2;
02206 bool empty2;
02207
02208
02209 if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
02210 elog(ERROR, "range types do not match");
02211
02212 range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
02213 range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
02214
02215
02216 if (empty2)
02217 return true;
02218 else if (empty1)
02219 return false;
02220
02221
02222 if (range_cmp_bounds(typcache, &lower1, &lower2) > 0)
02223 return false;
02224 if (range_cmp_bounds(typcache, &upper1, &upper2) < 0)
02225 return false;
02226
02227 return true;
02228 }
02229
02230 bool
02231 range_contained_by_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
02232 {
02233 return range_contains_internal(typcache, r2, r1);
02234 }
02235
02236
02237
02238
02239 bool
02240 range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val)
02241 {
02242 RangeBound lower;
02243 RangeBound upper;
02244 bool empty;
02245 int32 cmp;
02246
02247 range_deserialize(typcache, r, &lower, &upper, &empty);
02248
02249 if (empty)
02250 return false;
02251
02252 if (!lower.infinite)
02253 {
02254 cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
02255 typcache->rng_collation,
02256 lower.val, val));
02257 if (cmp > 0)
02258 return false;
02259 if (cmp == 0 && !lower.inclusive)
02260 return false;
02261 }
02262
02263 if (!upper.infinite)
02264 {
02265 cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
02266 typcache->rng_collation,
02267 upper.val, val));
02268 if (cmp < 0)
02269 return false;
02270 if (cmp == 0 && !upper.inclusive)
02271 return false;
02272 }
02273
02274 return true;
02275 }
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287 #define TYPE_IS_PACKABLE(typlen, typstorage) \
02288 ((typlen) == -1 && (typstorage) != 'p')
02289
02290
02291
02292
02293
02294 static Size
02295 datum_compute_size(Size data_length, Datum val, bool typbyval, char typalign,
02296 int16 typlen, char typstorage)
02297 {
02298 if (TYPE_IS_PACKABLE(typlen, typstorage) &&
02299 VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
02300 {
02301
02302
02303
02304
02305 data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
02306 }
02307 else
02308 {
02309 data_length = att_align_datum(data_length, typalign, typlen, val);
02310 data_length = att_addlength_datum(data_length, typlen, val);
02311 }
02312
02313 return data_length;
02314 }
02315
02316
02317
02318
02319
02320 static Pointer
02321 datum_write(Pointer ptr, Datum datum, bool typbyval, char typalign,
02322 int16 typlen, char typstorage)
02323 {
02324 Size data_length;
02325
02326 if (typbyval)
02327 {
02328
02329 ptr = (char *) att_align_nominal(ptr, typalign);
02330 store_att_byval(ptr, datum, typlen);
02331 data_length = typlen;
02332 }
02333 else if (typlen == -1)
02334 {
02335
02336 Pointer val = DatumGetPointer(datum);
02337
02338 if (VARATT_IS_EXTERNAL(val))
02339 {
02340
02341
02342
02343
02344 elog(ERROR, "cannot store a toast pointer inside a range");
02345 data_length = 0;
02346 }
02347 else if (VARATT_IS_SHORT(val))
02348 {
02349
02350 data_length = VARSIZE_SHORT(val);
02351 memcpy(ptr, val, data_length);
02352 }
02353 else if (TYPE_IS_PACKABLE(typlen, typstorage) &&
02354 VARATT_CAN_MAKE_SHORT(val))
02355 {
02356
02357 data_length = VARATT_CONVERTED_SHORT_SIZE(val);
02358 SET_VARSIZE_SHORT(ptr, data_length);
02359 memcpy(ptr + 1, VARDATA(val), data_length - 1);
02360 }
02361 else
02362 {
02363
02364 ptr = (char *) att_align_nominal(ptr, typalign);
02365 data_length = VARSIZE(val);
02366 memcpy(ptr, val, data_length);
02367 }
02368 }
02369 else if (typlen == -2)
02370 {
02371
02372 Assert(typalign == 'c');
02373 data_length = strlen(DatumGetCString(datum)) + 1;
02374 memcpy(ptr, DatumGetPointer(datum), data_length);
02375 }
02376 else
02377 {
02378
02379 ptr = (char *) att_align_nominal(ptr, typalign);
02380 Assert(typlen > 0);
02381 data_length = typlen;
02382 memcpy(ptr, DatumGetPointer(datum), data_length);
02383 }
02384
02385 ptr += data_length;
02386
02387 return ptr;
02388 }