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
00032
00033
00034
00035
00036
00037 #include "postgres.h"
00038
00039 #include "access/spgist.h"
00040 #include "access/skey.h"
00041 #include "catalog/pg_type.h"
00042 #include "utils/builtins.h"
00043 #include "utils/datum.h"
00044 #include "utils/rangetypes.h"
00045
00046
00047 Datum spg_range_quad_config(PG_FUNCTION_ARGS);
00048 Datum spg_range_quad_choose(PG_FUNCTION_ARGS);
00049 Datum spg_range_quad_picksplit(PG_FUNCTION_ARGS);
00050 Datum spg_range_quad_inner_consistent(PG_FUNCTION_ARGS);
00051 Datum spg_range_quad_leaf_consistent(PG_FUNCTION_ARGS);
00052
00053 static int16 getQuadrant(TypeCacheEntry *typcache, RangeType *centroid,
00054 RangeType *tst);
00055 static int bound_cmp(const void *a, const void *b, void *arg);
00056
00057
00058
00059
00060 Datum
00061 spg_range_quad_config(PG_FUNCTION_ARGS)
00062 {
00063
00064 spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
00065
00066 cfg->prefixType = ANYRANGEOID;
00067 cfg->labelType = VOIDOID;
00068 cfg->canReturnData = true;
00069 cfg->longValuesOK = false;
00070 PG_RETURN_VOID();
00071 }
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 static int16
00096 getQuadrant(TypeCacheEntry *typcache, RangeType *centroid, RangeType *tst)
00097 {
00098 RangeBound centroidLower,
00099 centroidUpper;
00100 bool centroidEmpty;
00101 RangeBound lower,
00102 upper;
00103 bool empty;
00104
00105 range_deserialize(typcache, centroid, ¢roidLower, ¢roidUpper,
00106 ¢roidEmpty);
00107 range_deserialize(typcache, tst, &lower, &upper, &empty);
00108
00109 if (empty)
00110 return 5;
00111
00112 if (range_cmp_bounds(typcache, &lower, ¢roidLower) >= 0)
00113 {
00114 if (range_cmp_bounds(typcache, &upper, ¢roidUpper) >= 0)
00115 return 1;
00116 else
00117 return 2;
00118 }
00119 else
00120 {
00121 if (range_cmp_bounds(typcache, &upper, ¢roidUpper) >= 0)
00122 return 4;
00123 else
00124 return 3;
00125 }
00126 }
00127
00128
00129
00130
00131 Datum
00132 spg_range_quad_choose(PG_FUNCTION_ARGS)
00133 {
00134 spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
00135 spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
00136 RangeType *inRange = DatumGetRangeType(in->datum),
00137 *centroid;
00138 int16 quadrant;
00139 TypeCacheEntry *typcache;
00140
00141 if (in->allTheSame)
00142 {
00143 out->resultType = spgMatchNode;
00144
00145 out->result.matchNode.levelAdd = 0;
00146 out->result.matchNode.restDatum = RangeTypeGetDatum(inRange);
00147 PG_RETURN_VOID();
00148 }
00149
00150 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(inRange));
00151
00152
00153
00154
00155
00156
00157 if (!in->hasPrefix)
00158 {
00159 out->resultType = spgMatchNode;
00160 if (RangeIsEmpty(inRange))
00161 out->result.matchNode.nodeN = 0;
00162 else
00163 out->result.matchNode.nodeN = 1;
00164 out->result.matchNode.levelAdd = 1;
00165 out->result.matchNode.restDatum = RangeTypeGetDatum(inRange);
00166 PG_RETURN_VOID();
00167 }
00168
00169 centroid = DatumGetRangeType(in->prefixDatum);
00170 quadrant = getQuadrant(typcache, centroid, inRange);
00171
00172 Assert(quadrant <= in->nNodes);
00173
00174
00175 out->resultType = spgMatchNode;
00176 out->result.matchNode.nodeN = quadrant - 1;
00177 out->result.matchNode.levelAdd = 1;
00178 out->result.matchNode.restDatum = RangeTypeGetDatum(inRange);
00179
00180 PG_RETURN_VOID();
00181 }
00182
00183
00184
00185
00186 static int
00187 bound_cmp(const void *a, const void *b, void *arg)
00188 {
00189 RangeBound *ba = (RangeBound *) a;
00190 RangeBound *bb = (RangeBound *) b;
00191 TypeCacheEntry *typcache = (TypeCacheEntry *) arg;
00192
00193 return range_cmp_bounds(typcache, ba, bb);
00194 }
00195
00196
00197
00198
00199
00200 Datum
00201 spg_range_quad_picksplit(PG_FUNCTION_ARGS)
00202 {
00203 spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
00204 spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
00205 int i;
00206 int j;
00207 int nonEmptyCount;
00208 RangeType *centroid;
00209 bool empty;
00210 TypeCacheEntry *typcache;
00211
00212
00213 RangeBound *lowerBounds,
00214 *upperBounds;
00215
00216 typcache = range_get_typcache(fcinfo,
00217 RangeTypeGetOid(DatumGetRangeType(in->datums[0])));
00218
00219
00220 lowerBounds = palloc(sizeof(RangeBound) * in->nTuples);
00221 upperBounds = palloc(sizeof(RangeBound) * in->nTuples);
00222 j = 0;
00223
00224
00225 for (i = 0; i < in->nTuples; i++)
00226 {
00227 range_deserialize(typcache, DatumGetRangeType(in->datums[i]),
00228 &lowerBounds[j], &upperBounds[j], &empty);
00229 if (!empty)
00230 j++;
00231 }
00232 nonEmptyCount = j;
00233
00234
00235
00236
00237
00238
00239 if (nonEmptyCount == 0)
00240 {
00241 out->nNodes = 2;
00242 out->hasPrefix = false;
00243
00244 out->prefixDatum = PointerGetDatum(NULL);
00245 out->nodeLabels = NULL;
00246
00247 out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
00248 out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
00249
00250
00251 for (i = 0; i < in->nTuples; i++)
00252 {
00253 RangeType *range = DatumGetRangeType(in->datums[i]);
00254
00255 out->leafTupleDatums[i] = RangeTypeGetDatum(range);
00256 out->mapTuplesToNodes[i] = 0;
00257 }
00258 PG_RETURN_VOID();
00259 }
00260
00261
00262 qsort_arg(lowerBounds, nonEmptyCount, sizeof(RangeBound),
00263 bound_cmp, typcache);
00264 qsort_arg(upperBounds, nonEmptyCount, sizeof(RangeBound),
00265 bound_cmp, typcache);
00266
00267
00268 centroid = range_serialize(typcache, &lowerBounds[nonEmptyCount / 2],
00269 &upperBounds[nonEmptyCount / 2], false);
00270 out->hasPrefix = true;
00271 out->prefixDatum = RangeTypeGetDatum(centroid);
00272
00273
00274 out->nNodes = (in->level == 0) ? 5 : 4;
00275 out->nodeLabels = NULL;
00276
00277 out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
00278 out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
00279
00280
00281
00282
00283
00284 for (i = 0; i < in->nTuples; i++)
00285 {
00286 RangeType *range = DatumGetRangeType(in->datums[i]);
00287 int16 quadrant = getQuadrant(typcache, centroid, range);
00288
00289 out->leafTupleDatums[i] = RangeTypeGetDatum(range);
00290 out->mapTuplesToNodes[i] = quadrant - 1;
00291 }
00292
00293 PG_RETURN_VOID();
00294 }
00295
00296
00297
00298
00299
00300 Datum
00301 spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
00302 {
00303 spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
00304 spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
00305 int which;
00306 int i;
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 bool needPrevious = false;
00317
00318 if (in->allTheSame)
00319 {
00320
00321 out->nNodes = in->nNodes;
00322 out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
00323 for (i = 0; i < in->nNodes; i++)
00324 out->nodeNumbers[i] = i;
00325 PG_RETURN_VOID();
00326 }
00327
00328 if (!in->hasPrefix)
00329 {
00330
00331
00332
00333
00334 Assert(in->nNodes == 2);
00335
00336
00337
00338
00339
00340
00341 which = (1 << 1) | (1 << 2);
00342 for (i = 0; i < in->nkeys; i++)
00343 {
00344 StrategyNumber strategy = in->scankeys[i].sk_strategy;
00345 bool empty;
00346
00347
00348
00349
00350
00351 if (strategy != RANGESTRAT_CONTAINS_ELEM)
00352 empty = RangeIsEmpty(
00353 DatumGetRangeType(in->scankeys[i].sk_argument));
00354 else
00355 empty = false;
00356
00357 switch (strategy)
00358 {
00359 case RANGESTRAT_BEFORE:
00360 case RANGESTRAT_OVERLEFT:
00361 case RANGESTRAT_OVERLAPS:
00362 case RANGESTRAT_OVERRIGHT:
00363 case RANGESTRAT_AFTER:
00364 case RANGESTRAT_ADJACENT:
00365
00366 if (empty)
00367 which = 0;
00368 else
00369 which &= (1 << 2);
00370 break;
00371
00372 case RANGESTRAT_CONTAINS:
00373
00374
00375
00376
00377 if (!empty)
00378 which &= (1 << 2);
00379 break;
00380
00381 case RANGESTRAT_CONTAINED_BY:
00382
00383
00384
00385
00386
00387 if (empty)
00388 which &= (1 << 1);
00389 break;
00390
00391 case RANGESTRAT_CONTAINS_ELEM:
00392 which &= (1 << 2);
00393 break;
00394
00395 case RANGESTRAT_EQ:
00396 if (empty)
00397 which &= (1 << 1);
00398 else
00399 which &= (1 << 2);
00400 break;
00401
00402 default:
00403 elog(ERROR, "unrecognized range strategy: %d", strategy);
00404 break;
00405 }
00406 if (which == 0)
00407 break;
00408 }
00409 }
00410 else
00411 {
00412 RangeBound centroidLower,
00413 centroidUpper;
00414 bool centroidEmpty;
00415 TypeCacheEntry *typcache;
00416 RangeType *centroid;
00417
00418
00419 centroid = DatumGetRangeType(in->prefixDatum);
00420 typcache = range_get_typcache(fcinfo,
00421 RangeTypeGetOid(DatumGetRangeType(centroid)));
00422 range_deserialize(typcache, centroid, ¢roidLower, ¢roidUpper,
00423 ¢roidEmpty);
00424
00425 Assert(in->nNodes == 4 || in->nNodes == 5);
00426
00427
00428
00429
00430
00431
00432 which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
00433
00434 for (i = 0; i < in->nkeys; i++)
00435 {
00436 StrategyNumber strategy;
00437 RangeBound lower,
00438 upper;
00439 bool empty;
00440 RangeType *range = NULL;
00441
00442 RangeBound *minLower = NULL,
00443 *maxLower = NULL,
00444 *minUpper = NULL,
00445 *maxUpper = NULL;
00446
00447 bool inclusive = true;
00448 bool strictEmpty = true;
00449 int cmp,
00450 which1,
00451 which2;
00452
00453 strategy = in->scankeys[i].sk_strategy;
00454
00455
00456
00457
00458
00459
00460
00461 if (strategy == RANGESTRAT_CONTAINS_ELEM)
00462 {
00463 lower.inclusive = true;
00464 lower.infinite = false;
00465 lower.lower = true;
00466 lower.val = in->scankeys[i].sk_argument;
00467
00468 upper.inclusive = true;
00469 upper.infinite = false;
00470 upper.lower = false;
00471 upper.val = in->scankeys[i].sk_argument;
00472
00473 empty = false;
00474
00475 strategy = RANGESTRAT_CONTAINS;
00476 }
00477 else
00478 {
00479 range = DatumGetRangeType(in->scankeys[i].sk_argument);
00480 range_deserialize(typcache, range, &lower, &upper, &empty);
00481 }
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 switch (strategy)
00495 {
00496 case RANGESTRAT_BEFORE:
00497
00498
00499
00500
00501 maxUpper = &lower;
00502 inclusive = false;
00503 break;
00504
00505 case RANGESTRAT_OVERLEFT:
00506
00507
00508
00509
00510 maxUpper = &upper;
00511 break;
00512
00513 case RANGESTRAT_OVERLAPS:
00514
00515
00516
00517
00518 maxLower = &upper;
00519 minUpper = &lower;
00520 break;
00521
00522 case RANGESTRAT_OVERRIGHT:
00523
00524
00525
00526
00527 minLower = &lower;
00528 break;
00529
00530 case RANGESTRAT_AFTER:
00531
00532
00533
00534
00535 minLower = &upper;
00536 inclusive = false;
00537 break;
00538
00539 case RANGESTRAT_ADJACENT:
00540 if (empty)
00541 break;
00542
00543
00544
00545
00546
00547
00548 which1 = which2 = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
00549
00550
00551
00552
00553
00554
00555 if (in->reconstructedValue != (Datum) 0)
00556 {
00557 RangeType *prevCentroid;
00558 RangeBound prevLower,
00559 prevUpper;
00560 bool prevEmpty;
00561 int cmp1,
00562 cmp2;
00563
00564 prevCentroid = DatumGetRangeType(in->reconstructedValue);
00565 range_deserialize(typcache, prevCentroid,
00566 &prevLower, &prevUpper, &prevEmpty);
00567
00568
00569
00570
00571
00572 cmp1 = range_cmp_bounds(typcache, &lower, &prevUpper);
00573 cmp2 = range_cmp_bounds(typcache, ¢roidUpper,
00574 &prevUpper);
00575 if ((cmp2 < 0 && cmp1 > 0) || (cmp2 > 0 && cmp1 < 0))
00576 which1 = 0;
00577
00578
00579
00580
00581
00582 cmp1 = range_cmp_bounds(typcache, &upper, &prevLower);
00583 cmp2 = range_cmp_bounds(typcache, ¢roidLower,
00584 &prevLower);
00585 if ((cmp2 < 0 && cmp1 > 0) || (cmp2 > 0 && cmp1 < 0))
00586 which2 = 0;
00587 }
00588
00589 if (which1)
00590 {
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 cmp = range_cmp_bounds(typcache, &lower,
00613 ¢roidUpper);
00614 if (cmp < 0)
00615 which1 &= (1 << 2) | (1 << 3);
00616 else if (cmp > 0)
00617 which1 &= (1 << 1) | (1 << 4);
00618 }
00619
00620 if (which2)
00621 {
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 cmp = range_cmp_bounds(typcache, &lower,
00638 ¢roidUpper);
00639 if (cmp < 0 &&
00640 !bounds_adjacent(typcache, upper, centroidLower))
00641 which1 &= (1 << 3) | (1 << 4);
00642 else if (cmp > 0)
00643 which1 &= (1 << 1) | (1 << 2);
00644 }
00645
00646 which &= which1 | which2;
00647
00648 needPrevious = true;
00649 break;
00650
00651 case RANGESTRAT_CONTAINS:
00652
00653
00654
00655
00656
00657
00658
00659
00660 strictEmpty = false;
00661 if (!empty)
00662 {
00663 which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
00664 maxLower = &lower;
00665 minUpper = &upper;
00666 }
00667 break;
00668
00669 case RANGESTRAT_CONTAINED_BY:
00670
00671 strictEmpty = false;
00672 if (empty)
00673 {
00674
00675 which &= (1 << 5);
00676 }
00677 else
00678 {
00679 minLower = &lower;
00680 maxUpper = &upper;
00681 }
00682 break;
00683
00684 case RANGESTRAT_EQ:
00685
00686
00687
00688
00689 strictEmpty = false;
00690 which &= (1 << getQuadrant(typcache, centroid, range));
00691 break;
00692
00693 default:
00694 elog(ERROR, "unrecognized range strategy: %d", strategy);
00695 break;
00696 }
00697
00698 if (strictEmpty)
00699 {
00700 if (empty)
00701 {
00702
00703 which = 0;
00704 break;
00705 }
00706 else
00707 {
00708
00709 which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
00710 }
00711 }
00712
00713
00714
00715
00716
00717 if (minLower)
00718 {
00719
00720
00721
00722
00723
00724
00725 if (range_cmp_bounds(typcache, ¢roidLower, minLower) <= 0)
00726 which &= (1 << 1) | (1 << 2) | (1 << 5);
00727 }
00728 if (maxLower)
00729 {
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739 int cmp;
00740
00741 cmp = range_cmp_bounds(typcache, ¢roidLower, maxLower);
00742 if (cmp > 0 || (!inclusive && cmp == 0))
00743 which &= (1 << 3) | (1 << 4) | (1 << 5);
00744 }
00745 if (minUpper)
00746 {
00747
00748
00749
00750
00751
00752
00753 if (range_cmp_bounds(typcache, ¢roidUpper, minUpper) <= 0)
00754 which &= (1 << 1) | (1 << 4) | (1 << 5);
00755 }
00756 if (maxUpper)
00757 {
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 int cmp;
00768
00769 cmp = range_cmp_bounds(typcache, ¢roidUpper, maxUpper);
00770 if (cmp > 0 || (!inclusive && cmp == 0))
00771 which &= (1 << 2) | (1 << 3) | (1 << 5);
00772 }
00773
00774 if (which == 0)
00775 break;
00776 }
00777 }
00778
00779
00780 out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
00781 if (needPrevious)
00782 out->reconstructedValues = (Datum *) palloc(sizeof(Datum) * in->nNodes);
00783 out->nNodes = 0;
00784 for (i = 1; i <= in->nNodes; i++)
00785 {
00786 if (which & (1 << i))
00787 {
00788
00789 if (needPrevious)
00790 out->reconstructedValues[out->nNodes] = in->prefixDatum;
00791 out->nodeNumbers[out->nNodes++] = i - 1;
00792 }
00793 }
00794
00795 PG_RETURN_VOID();
00796 }
00797
00798
00799
00800
00801
00802 Datum
00803 spg_range_quad_leaf_consistent(PG_FUNCTION_ARGS)
00804 {
00805 spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
00806 spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
00807 RangeType *leafRange = DatumGetRangeType(in->leafDatum);
00808 TypeCacheEntry *typcache;
00809 bool res;
00810 int i;
00811
00812
00813 out->recheck = false;
00814
00815
00816 out->leafValue = in->leafDatum;
00817
00818 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(leafRange));
00819
00820
00821 res = true;
00822 for (i = 0; i < in->nkeys; i++)
00823 {
00824 Datum keyDatum = in->scankeys[i].sk_argument;
00825
00826
00827 switch (in->scankeys[i].sk_strategy)
00828 {
00829 case RANGESTRAT_BEFORE:
00830 res = range_before_internal(typcache, leafRange,
00831 DatumGetRangeType(keyDatum));
00832 break;
00833 case RANGESTRAT_OVERLEFT:
00834 res = range_overleft_internal(typcache, leafRange,
00835 DatumGetRangeType(keyDatum));
00836 break;
00837 case RANGESTRAT_OVERLAPS:
00838 res = range_overlaps_internal(typcache, leafRange,
00839 DatumGetRangeType(keyDatum));
00840 break;
00841 case RANGESTRAT_OVERRIGHT:
00842 res = range_overright_internal(typcache, leafRange,
00843 DatumGetRangeType(keyDatum));
00844 break;
00845 case RANGESTRAT_AFTER:
00846 res = range_after_internal(typcache, leafRange,
00847 DatumGetRangeType(keyDatum));
00848 break;
00849 case RANGESTRAT_ADJACENT:
00850 res = range_adjacent_internal(typcache, leafRange,
00851 DatumGetRangeType(keyDatum));
00852 break;
00853 case RANGESTRAT_CONTAINS:
00854 res = range_contains_internal(typcache, leafRange,
00855 DatumGetRangeType(keyDatum));
00856 break;
00857 case RANGESTRAT_CONTAINED_BY:
00858 res = range_contained_by_internal(typcache, leafRange,
00859 DatumGetRangeType(keyDatum));
00860 break;
00861 case RANGESTRAT_CONTAINS_ELEM:
00862 res = range_contains_elem_internal(typcache, leafRange,
00863 keyDatum);
00864 break;
00865 case RANGESTRAT_EQ:
00866 res = range_eq_internal(typcache, leafRange,
00867 DatumGetRangeType(keyDatum));
00868 break;
00869 default:
00870 elog(ERROR, "unrecognized range strategy: %d",
00871 in->scankeys[i].sk_strategy);
00872 break;
00873 }
00874
00875
00876
00877
00878
00879 if (!res)
00880 break;
00881 }
00882
00883 PG_RETURN_BOOL(res);
00884 }