LCOV - code coverage report
Current view: top level - src/backend/utils/adt - geo_spgist.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 247 249 99.2 %
Date: 2017-09-29 13:40:31 Functions: 28 28 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * geo_spgist.c
       4             :  *    SP-GiST implementation of 4-dimensional quad tree over boxes
       5             :  *
       6             :  * This module provides SP-GiST implementation for boxes using quad tree
       7             :  * analogy in 4-dimensional space.  SP-GiST doesn't allow indexing of
       8             :  * overlapping objects.  We are making 2D objects never-overlapping in
       9             :  * 4D space.  This technique has some benefits compared to traditional
      10             :  * R-Tree which is implemented as GiST.  The performance tests reveal
      11             :  * that this technique especially beneficial with too much overlapping
      12             :  * objects, so called "spaghetti data".
      13             :  *
      14             :  * Unlike the original quad tree, we are splitting the tree into 16
      15             :  * quadrants in 4D space.  It is easier to imagine it as splitting space
      16             :  * two times into 4:
      17             :  *
      18             :  *              |      |
      19             :  *              |      |
      20             :  *              | -----+-----
      21             :  *              |      |
      22             :  *              |      |
      23             :  * -------------+-------------
      24             :  *              |
      25             :  *              |
      26             :  *              |
      27             :  *              |
      28             :  *              |
      29             :  *
      30             :  * We are using box datatype as the prefix, but we are treating them
      31             :  * as points in 4-dimensional space, because 2D boxes are not enough
      32             :  * to represent the quadrant boundaries in 4D space.  They however are
      33             :  * sufficient to point out the additional boundaries of the next
      34             :  * quadrant.
      35             :  *
      36             :  * We are using traversal values provided by SP-GiST to calculate and
      37             :  * to store the bounds of the quadrants, while traversing into the tree.
      38             :  * Traversal value has all the boundaries in the 4D space, and is is
      39             :  * capable of transferring the required boundaries to the following
      40             :  * traversal values.  In conclusion, three things are necessary
      41             :  * to calculate the next traversal value:
      42             :  *
      43             :  *  (1) the traversal value of the parent
      44             :  *  (2) the quadrant of the current node
      45             :  *  (3) the prefix of the current node
      46             :  *
      47             :  * If we visualize them on our simplified drawing (see the drawing above);
      48             :  * transferred boundaries of (1) would be the outer axis, relevant part
      49             :  * of (2) would be the up right part of the other axis, and (3) would be
      50             :  * the inner axis.
      51             :  *
      52             :  * For example, consider the case of overlapping.  When recursion
      53             :  * descends deeper and deeper down the tree, all quadrants in
      54             :  * the current node will be checked for overlapping.  The boundaries
      55             :  * will be re-calculated for all quadrants.  Overlap check answers
      56             :  * the question: can any box from this quadrant overlap with the given
      57             :  * box?  If yes, then this quadrant will be walked.  If no, then this
      58             :  * quadrant will be skipped.
      59             :  *
      60             :  * This method provides restrictions for minimum and maximum values of
      61             :  * every dimension of every corner of the box on every level of the tree
      62             :  * except the root.  For the root node, we are setting the boundaries
      63             :  * that we don't yet have as infinity.
      64             :  *
      65             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      66             :  * Portions Copyright (c) 1994, Regents of the University of California
      67             :  *
      68             :  * IDENTIFICATION
      69             :  *          src/backend/utils/adt/geo_spgist.c
      70             :  *
      71             :  *-------------------------------------------------------------------------
      72             :  */
      73             : 
      74             : #include "postgres.h"
      75             : 
      76             : #include "access/spgist.h"
      77             : #include "access/stratnum.h"
      78             : #include "catalog/pg_type.h"
      79             : #include "utils/builtins.h"
      80             : #include "utils/geo_decls.h"
      81             : 
      82             : /*
      83             :  * Comparator for qsort
      84             :  *
      85             :  * We don't need to use the floating point macros in here, because this
      86             :  * is going only going to be used in a place to effect the performance
      87             :  * of the index, not the correctness.
      88             :  */
      89             : static int
      90      128167 : compareDoubles(const void *a, const void *b)
      91             : {
      92      128167 :     double      x = *(double *) a;
      93      128167 :     double      y = *(double *) b;
      94             : 
      95      128167 :     if (x == y)
      96       43510 :         return 0;
      97       84657 :     return (x > y) ? 1 : -1;
      98             : }
      99             : 
     100             : typedef struct
     101             : {
     102             :     double      low;
     103             :     double      high;
     104             : } Range;
     105             : 
     106             : typedef struct
     107             : {
     108             :     Range       left;
     109             :     Range       right;
     110             : } RangeBox;
     111             : 
     112             : typedef struct
     113             : {
     114             :     RangeBox    range_box_x;
     115             :     RangeBox    range_box_y;
     116             : } RectBox;
     117             : 
     118             : /*
     119             :  * Calculate the quadrant
     120             :  *
     121             :  * The quadrant is 8 bit unsigned integer with 4 least bits in use.
     122             :  * This function accepts BOXes as input.  They are not casted to
     123             :  * RangeBoxes, yet.  All 4 bits are set by comparing a corner of the box.
     124             :  * This makes 16 quadrants in total.
     125             :  */
     126             : static uint8
     127       66985 : getQuadrant(BOX *centroid, BOX *inBox)
     128             : {
     129       66985 :     uint8       quadrant = 0;
     130             : 
     131       66985 :     if (inBox->low.x > centroid->low.x)
     132       58948 :         quadrant |= 0x8;
     133             : 
     134       66985 :     if (inBox->high.x > centroid->high.x)
     135       58950 :         quadrant |= 0x4;
     136             : 
     137       66985 :     if (inBox->low.y > centroid->low.y)
     138       32602 :         quadrant |= 0x2;
     139             : 
     140       66985 :     if (inBox->high.y > centroid->high.y)
     141       32605 :         quadrant |= 0x1;
     142             : 
     143       66985 :     return quadrant;
     144             : }
     145             : 
     146             : /*
     147             :  * Get RangeBox using BOX
     148             :  *
     149             :  * We are turning the BOX to our structures to emphasize their function
     150             :  * of representing points in 4D space.  It also is more convenient to
     151             :  * access the values with this structure.
     152             :  */
     153             : static RangeBox *
     154        1268 : getRangeBox(BOX *box)
     155             : {
     156        1268 :     RangeBox   *range_box = (RangeBox *) palloc(sizeof(RangeBox));
     157             : 
     158        1268 :     range_box->left.low = box->low.x;
     159        1268 :     range_box->left.high = box->high.x;
     160             : 
     161        1268 :     range_box->right.low = box->low.y;
     162        1268 :     range_box->right.high = box->high.y;
     163             : 
     164        1268 :     return range_box;
     165             : }
     166             : 
     167             : /*
     168             :  * Initialize the traversal value
     169             :  *
     170             :  * In the beginning, we don't have any restrictions.  We have to
     171             :  * initialize the struct to cover the whole 4D space.
     172             :  */
     173             : static RectBox *
     174          13 : initRectBox(void)
     175             : {
     176          13 :     RectBox    *rect_box = (RectBox *) palloc(sizeof(RectBox));
     177          13 :     double      infinity = get_float8_infinity();
     178             : 
     179          13 :     rect_box->range_box_x.left.low = -infinity;
     180          13 :     rect_box->range_box_x.left.high = infinity;
     181             : 
     182          13 :     rect_box->range_box_x.right.low = -infinity;
     183          13 :     rect_box->range_box_x.right.high = infinity;
     184             : 
     185          13 :     rect_box->range_box_y.left.low = -infinity;
     186          13 :     rect_box->range_box_y.left.high = infinity;
     187             : 
     188          13 :     rect_box->range_box_y.right.low = -infinity;
     189          13 :     rect_box->range_box_y.right.high = infinity;
     190             : 
     191          13 :     return rect_box;
     192             : }
     193             : 
     194             : /*
     195             :  * Calculate the next traversal value
     196             :  *
     197             :  * All centroids are bounded by RectBox, but SP-GiST only keeps
     198             :  * boxes.  When we are traversing the tree, we must calculate RectBox,
     199             :  * using centroid and quadrant.
     200             :  */
     201             : static RectBox *
     202       10144 : nextRectBox(RectBox *rect_box, RangeBox *centroid, uint8 quadrant)
     203             : {
     204       10144 :     RectBox    *next_rect_box = (RectBox *) palloc(sizeof(RectBox));
     205             : 
     206       10144 :     memcpy(next_rect_box, rect_box, sizeof(RectBox));
     207             : 
     208       10144 :     if (quadrant & 0x8)
     209        5072 :         next_rect_box->range_box_x.left.low = centroid->left.low;
     210             :     else
     211        5072 :         next_rect_box->range_box_x.left.high = centroid->left.low;
     212             : 
     213       10144 :     if (quadrant & 0x4)
     214        5072 :         next_rect_box->range_box_x.right.low = centroid->left.high;
     215             :     else
     216        5072 :         next_rect_box->range_box_x.right.high = centroid->left.high;
     217             : 
     218       10144 :     if (quadrant & 0x2)
     219        5072 :         next_rect_box->range_box_y.left.low = centroid->right.low;
     220             :     else
     221        5072 :         next_rect_box->range_box_y.left.high = centroid->right.low;
     222             : 
     223       10144 :     if (quadrant & 0x1)
     224        5072 :         next_rect_box->range_box_y.right.low = centroid->right.high;
     225             :     else
     226        5072 :         next_rect_box->range_box_y.right.high = centroid->right.high;
     227             : 
     228       10144 :     return next_rect_box;
     229             : }
     230             : 
     231             : /* Can any range from range_box overlap with this argument? */
     232             : static bool
     233         808 : overlap2D(RangeBox *range_box, Range *query)
     234             : {
     235        1560 :     return FPge(range_box->right.high, query->low) &&
     236         752 :         FPle(range_box->left.low, query->high);
     237             : }
     238             : 
     239             : /* Can any rectangle from rect_box overlap with this argument? */
     240             : static bool
     241         480 : overlap4D(RectBox *rect_box, RangeBox *query)
     242             : {
     243         808 :     return overlap2D(&rect_box->range_box_x, &query->left) &&
     244         328 :         overlap2D(&rect_box->range_box_y, &query->right);
     245             : }
     246             : 
     247             : /* Can any range from range_box contain this argument? */
     248             : static bool
     249         152 : contain2D(RangeBox *range_box, Range *query)
     250             : {
     251         260 :     return FPge(range_box->right.high, query->high) &&
     252         108 :         FPle(range_box->left.low, query->low);
     253             : }
     254             : 
     255             : /* Can any rectangle from rect_box contain this argument? */
     256             : static bool
     257          96 : contain4D(RectBox *rect_box, RangeBox *query)
     258             : {
     259         152 :     return contain2D(&rect_box->range_box_x, &query->left) &&
     260          56 :         contain2D(&rect_box->range_box_y, &query->right);
     261             : }
     262             : 
     263             : /* Can any range from range_box be contained by this argument? */
     264             : static bool
     265         756 : contained2D(RangeBox *range_box, Range *query)
     266             : {
     267        2172 :     return FPle(range_box->left.low, query->high) &&
     268        1232 :         FPge(range_box->left.high, query->low) &&
     269        1824 :         FPle(range_box->right.low, query->high) &&
     270         496 :         FPge(range_box->right.high, query->low);
     271             : }
     272             : 
     273             : /* Can any rectangle from rect_box be contained by this argument? */
     274             : static bool
     275         512 : contained4D(RectBox *rect_box, RangeBox *query)
     276             : {
     277         756 :     return contained2D(&rect_box->range_box_x, &query->left) &&
     278         244 :         contained2D(&rect_box->range_box_y, &query->right);
     279             : }
     280             : 
     281             : /* Can any range from range_box to be lower than this argument? */
     282             : static bool
     283         704 : lower2D(RangeBox *range_box, Range *query)
     284             : {
     285        1280 :     return FPlt(range_box->left.low, query->low) &&
     286         576 :         FPlt(range_box->right.low, query->low);
     287             : }
     288             : 
     289             : /* Can any range from range_box not extend to the right side of the query? */
     290             : static bool
     291        1888 : overLower2D(RangeBox *range_box, Range *query)
     292             : {
     293        3496 :     return FPle(range_box->left.low, query->high) &&
     294        1608 :         FPle(range_box->right.low, query->high);
     295             : }
     296             : 
     297             : /* Can any range from range_box to be higher than this argument? */
     298             : static bool
     299        3744 : higher2D(RangeBox *range_box, Range *query)
     300             : {
     301        6880 :     return FPgt(range_box->left.high, query->high) &&
     302        3136 :         FPgt(range_box->right.high, query->high);
     303             : }
     304             : 
     305             : /* Can any range from range_box not extend to the left side of the query? */
     306             : static bool
     307        2720 : overHigher2D(RangeBox *range_box, Range *query)
     308             : {
     309        5344 :     return FPge(range_box->left.high, query->low) &&
     310        2624 :         FPge(range_box->right.high, query->low);
     311             : }
     312             : 
     313             : /* Can any rectangle from rect_box be left of this argument? */
     314             : static bool
     315         336 : left4D(RectBox *rect_box, RangeBox *query)
     316             : {
     317         336 :     return lower2D(&rect_box->range_box_x, &query->left);
     318             : }
     319             : 
     320             : /* Can any rectangle from rect_box does not extend the right of this argument? */
     321             : static bool
     322        1136 : overLeft4D(RectBox *rect_box, RangeBox *query)
     323             : {
     324        1136 :     return overLower2D(&rect_box->range_box_x, &query->left);
     325             : }
     326             : 
     327             : /* Can any rectangle from rect_box be right of this argument? */
     328             : static bool
     329        2944 : right4D(RectBox *rect_box, RangeBox *query)
     330             : {
     331        2944 :     return higher2D(&rect_box->range_box_x, &query->left);
     332             : }
     333             : 
     334             : /* Can any rectangle from rect_box does not extend the left of this argument? */
     335             : static bool
     336        1488 : overRight4D(RectBox *rect_box, RangeBox *query)
     337             : {
     338        1488 :     return overHigher2D(&rect_box->range_box_x, &query->left);
     339             : }
     340             : 
     341             : /* Can any rectangle from rect_box be below of this argument? */
     342             : static bool
     343         368 : below4D(RectBox *rect_box, RangeBox *query)
     344             : {
     345         368 :     return lower2D(&rect_box->range_box_y, &query->right);
     346             : }
     347             : 
     348             : /* Can any rectangle from rect_box does not extend above this argument? */
     349             : static bool
     350         752 : overBelow4D(RectBox *rect_box, RangeBox *query)
     351             : {
     352         752 :     return overLower2D(&rect_box->range_box_y, &query->right);
     353             : }
     354             : 
     355             : /* Can any rectangle from rect_box be above of this argument? */
     356             : static bool
     357         800 : above4D(RectBox *rect_box, RangeBox *query)
     358             : {
     359         800 :     return higher2D(&rect_box->range_box_y, &query->right);
     360             : }
     361             : 
     362             : /* Can any rectangle from rect_box does not extend below of this argument? */
     363             : static bool
     364        1232 : overAbove4D(RectBox *rect_box, RangeBox *query)
     365             : {
     366        1232 :     return overHigher2D(&rect_box->range_box_y, &query->right);
     367             : }
     368             : 
     369             : /*
     370             :  * SP-GiST config function
     371             :  */
     372             : Datum
     373           5 : spg_box_quad_config(PG_FUNCTION_ARGS)
     374             : {
     375           5 :     spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
     376             : 
     377           5 :     cfg->prefixType = BOXOID;
     378           5 :     cfg->labelType = VOIDOID;    /* We don't need node labels. */
     379           5 :     cfg->canReturnData = true;
     380           5 :     cfg->longValuesOK = false;
     381             : 
     382           5 :     PG_RETURN_VOID();
     383             : }
     384             : 
     385             : /*
     386             :  * SP-GiST choose function
     387             :  */
     388             : Datum
     389       57345 : spg_box_quad_choose(PG_FUNCTION_ARGS)
     390             : {
     391       57345 :     spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
     392       57345 :     spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
     393       57345 :     BOX        *centroid = DatumGetBoxP(in->prefixDatum),
     394       57345 :                *box = DatumGetBoxP(in->datum);
     395             : 
     396       57345 :     out->resultType = spgMatchNode;
     397       57345 :     out->result.matchNode.restDatum = BoxPGetDatum(box);
     398             : 
     399             :     /* nodeN will be set by core, when allTheSame. */
     400       57345 :     if (!in->allTheSame)
     401       56309 :         out->result.matchNode.nodeN = getQuadrant(centroid, box);
     402             : 
     403       57345 :     PG_RETURN_VOID();
     404             : }
     405             : 
     406             : /*
     407             :  * SP-GiST pick-split function
     408             :  *
     409             :  * It splits a list of boxes into quadrants by choosing a central 4D
     410             :  * point as the median of the coordinates of the boxes.
     411             :  */
     412             : Datum
     413         101 : spg_box_quad_picksplit(PG_FUNCTION_ARGS)
     414             : {
     415         101 :     spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
     416         101 :     spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
     417             :     BOX        *centroid;
     418             :     int         median,
     419             :                 i;
     420         101 :     double     *lowXs = palloc(sizeof(double) * in->nTuples);
     421         101 :     double     *highXs = palloc(sizeof(double) * in->nTuples);
     422         101 :     double     *lowYs = palloc(sizeof(double) * in->nTuples);
     423         101 :     double     *highYs = palloc(sizeof(double) * in->nTuples);
     424             : 
     425             :     /* Calculate median of all 4D coordinates */
     426       10777 :     for (i = 0; i < in->nTuples; i++)
     427             :     {
     428       10676 :         BOX        *box = DatumGetBoxP(in->datums[i]);
     429             : 
     430       10676 :         lowXs[i] = box->low.x;
     431       10676 :         highXs[i] = box->high.x;
     432       10676 :         lowYs[i] = box->low.y;
     433       10676 :         highYs[i] = box->high.y;
     434             :     }
     435             : 
     436         101 :     qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
     437         101 :     qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
     438         101 :     qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
     439         101 :     qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
     440             : 
     441         101 :     median = in->nTuples / 2;
     442             : 
     443         101 :     centroid = palloc(sizeof(BOX));
     444             : 
     445         101 :     centroid->low.x = lowXs[median];
     446         101 :     centroid->high.x = highXs[median];
     447         101 :     centroid->low.y = lowYs[median];
     448         101 :     centroid->high.y = highYs[median];
     449             : 
     450             :     /* Fill the output */
     451         101 :     out->hasPrefix = true;
     452         101 :     out->prefixDatum = BoxPGetDatum(centroid);
     453             : 
     454         101 :     out->nNodes = 16;
     455         101 :     out->nodeLabels = NULL;      /* We don't need node labels. */
     456             : 
     457         101 :     out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
     458         101 :     out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
     459             : 
     460             :     /*
     461             :      * Assign ranges to corresponding nodes according to quadrants relative to
     462             :      * the "centroid" range
     463             :      */
     464       10777 :     for (i = 0; i < in->nTuples; i++)
     465             :     {
     466       10676 :         BOX        *box = DatumGetBoxP(in->datums[i]);
     467       10676 :         uint8       quadrant = getQuadrant(centroid, box);
     468             : 
     469       10676 :         out->leafTupleDatums[i] = BoxPGetDatum(box);
     470       10676 :         out->mapTuplesToNodes[i] = quadrant;
     471             :     }
     472             : 
     473         101 :     PG_RETURN_VOID();
     474             : }
     475             : 
     476             : /*
     477             :  * SP-GiST inner consistent function
     478             :  */
     479             : Datum
     480         698 : spg_box_quad_inner_consistent(PG_FUNCTION_ARGS)
     481             : {
     482         698 :     spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
     483         698 :     spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
     484             :     int         i;
     485             :     MemoryContext old_ctx;
     486             :     RectBox    *rect_box;
     487             :     uint8       quadrant;
     488             :     RangeBox   *centroid,
     489             :               **queries;
     490             : 
     491         698 :     if (in->allTheSame)
     492             :     {
     493             :         /* Report that all nodes should be visited */
     494          64 :         out->nNodes = in->nNodes;
     495          64 :         out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
     496         576 :         for (i = 0; i < in->nNodes; i++)
     497         512 :             out->nodeNumbers[i] = i;
     498             : 
     499          64 :         PG_RETURN_VOID();
     500             :     }
     501             : 
     502             :     /*
     503             :      * We are saving the traversal value or initialize it an unbounded one, if
     504             :      * we have just begun to walk the tree.
     505             :      */
     506         634 :     if (in->traversalValue)
     507         621 :         rect_box = in->traversalValue;
     508             :     else
     509          13 :         rect_box = initRectBox();
     510             : 
     511             :     /*
     512             :      * We are casting the prefix and queries to RangeBoxes for ease of the
     513             :      * following operations.
     514             :      */
     515         634 :     centroid = getRangeBox(DatumGetBoxP(in->prefixDatum));
     516         634 :     queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *));
     517        1268 :     for (i = 0; i < in->nkeys; i++)
     518         634 :         queries[i] = getRangeBox(DatumGetBoxP(in->scankeys[i].sk_argument));
     519             : 
     520             :     /* Allocate enough memory for nodes */
     521         634 :     out->nNodes = 0;
     522         634 :     out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
     523         634 :     out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes);
     524             : 
     525             :     /*
     526             :      * We switch memory context, because we want to allocate memory for new
     527             :      * traversal values (next_rect_box) and pass these pieces of memory to
     528             :      * further call of this function.
     529             :      */
     530         634 :     old_ctx = MemoryContextSwitchTo(in->traversalMemoryContext);
     531             : 
     532       10778 :     for (quadrant = 0; quadrant < in->nNodes; quadrant++)
     533             :     {
     534       10144 :         RectBox    *next_rect_box = nextRectBox(rect_box, centroid, quadrant);
     535       10144 :         bool        flag = true;
     536             : 
     537       18072 :         for (i = 0; i < in->nkeys; i++)
     538             :         {
     539       10144 :             StrategyNumber strategy = in->scankeys[i].sk_strategy;
     540             : 
     541       10144 :             switch (strategy)
     542             :             {
     543             :                 case RTOverlapStrategyNumber:
     544         480 :                     flag = overlap4D(next_rect_box, queries[i]);
     545         480 :                     break;
     546             : 
     547             :                 case RTContainsStrategyNumber:
     548          96 :                     flag = contain4D(next_rect_box, queries[i]);
     549          96 :                     break;
     550             : 
     551             :                 case RTSameStrategyNumber:
     552             :                 case RTContainedByStrategyNumber:
     553         512 :                     flag = contained4D(next_rect_box, queries[i]);
     554         512 :                     break;
     555             : 
     556             :                 case RTLeftStrategyNumber:
     557         336 :                     flag = left4D(next_rect_box, queries[i]);
     558         336 :                     break;
     559             : 
     560             :                 case RTOverLeftStrategyNumber:
     561        1136 :                     flag = overLeft4D(next_rect_box, queries[i]);
     562        1136 :                     break;
     563             : 
     564             :                 case RTRightStrategyNumber:
     565        2944 :                     flag = right4D(next_rect_box, queries[i]);
     566        2944 :                     break;
     567             : 
     568             :                 case RTOverRightStrategyNumber:
     569        1488 :                     flag = overRight4D(next_rect_box, queries[i]);
     570        1488 :                     break;
     571             : 
     572             :                 case RTAboveStrategyNumber:
     573         800 :                     flag = above4D(next_rect_box, queries[i]);
     574         800 :                     break;
     575             : 
     576             :                 case RTOverAboveStrategyNumber:
     577        1232 :                     flag = overAbove4D(next_rect_box, queries[i]);
     578        1232 :                     break;
     579             : 
     580             :                 case RTBelowStrategyNumber:
     581         368 :                     flag = below4D(next_rect_box, queries[i]);
     582         368 :                     break;
     583             : 
     584             :                 case RTOverBelowStrategyNumber:
     585         752 :                     flag = overBelow4D(next_rect_box, queries[i]);
     586         752 :                     break;
     587             : 
     588             :                 default:
     589           0 :                     elog(ERROR, "unrecognized strategy: %d", strategy);
     590             :             }
     591             : 
     592             :             /* If any check is failed, we have found our answer. */
     593       10144 :             if (!flag)
     594        2216 :                 break;
     595             :         }
     596             : 
     597       10144 :         if (flag)
     598             :         {
     599        7928 :             out->traversalValues[out->nNodes] = next_rect_box;
     600        7928 :             out->nodeNumbers[out->nNodes] = quadrant;
     601        7928 :             out->nNodes++;
     602             :         }
     603             :         else
     604             :         {
     605             :             /*
     606             :              * If this node is not selected, we don't need to keep the next
     607             :              * traversal value in the memory context.
     608             :              */
     609        2216 :             pfree(next_rect_box);
     610             :         }
     611             :     }
     612             : 
     613             :     /* Switch back */
     614         634 :     MemoryContextSwitchTo(old_ctx);
     615             : 
     616         634 :     PG_RETURN_VOID();
     617             : }
     618             : 
     619             : /*
     620             :  * SP-GiST inner consistent function
     621             :  */
     622             : Datum
     623       61893 : spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS)
     624             : {
     625       61893 :     spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
     626       61893 :     spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
     627       61893 :     Datum       leaf = in->leafDatum;
     628       61893 :     bool        flag = true;
     629             :     int         i;
     630             : 
     631             :     /* All tests are exact. */
     632       61893 :     out->recheck = false;
     633             : 
     634             :     /* leafDatum is what it is... */
     635       61893 :     out->leafValue = in->leafDatum;
     636             : 
     637             :     /* Perform the required comparison(s) */
     638      117031 :     for (i = 0; i < in->nkeys; i++)
     639             :     {
     640       61893 :         StrategyNumber strategy = in->scankeys[i].sk_strategy;
     641       61893 :         Datum       query = in->scankeys[i].sk_argument;
     642             : 
     643       61893 :         switch (strategy)
     644             :         {
     645             :             case RTOverlapStrategyNumber:
     646        2332 :                 flag = DatumGetBool(DirectFunctionCall2(box_overlap, leaf,
     647             :                                                         query));
     648        2332 :                 break;
     649             : 
     650             :             case RTContainsStrategyNumber:
     651        1090 :                 flag = DatumGetBool(DirectFunctionCall2(box_contain, leaf,
     652             :                                                         query));
     653        1090 :                 break;
     654             : 
     655             :             case RTContainedByStrategyNumber:
     656        2155 :                 flag = DatumGetBool(DirectFunctionCall2(box_contained, leaf,
     657             :                                                         query));
     658        2155 :                 break;
     659             : 
     660             :             case RTSameStrategyNumber:
     661        1075 :                 flag = DatumGetBool(DirectFunctionCall2(box_same, leaf,
     662             :                                                         query));
     663        1075 :                 break;
     664             : 
     665             :             case RTLeftStrategyNumber:
     666        1446 :                 flag = DatumGetBool(DirectFunctionCall2(box_left, leaf,
     667             :                                                         query));
     668        1446 :                 break;
     669             : 
     670             :             case RTOverLeftStrategyNumber:
     671        5242 :                 flag = DatumGetBool(DirectFunctionCall2(box_overleft, leaf,
     672             :                                                         query));
     673        5242 :                 break;
     674             : 
     675             :             case RTRightStrategyNumber:
     676       15545 :                 flag = DatumGetBool(DirectFunctionCall2(box_right, leaf,
     677             :                                                         query));
     678       15545 :                 break;
     679             : 
     680             :             case RTOverRightStrategyNumber:
     681       10389 :                 flag = DatumGetBool(DirectFunctionCall2(box_overright, leaf,
     682             :                                                         query));
     683       10389 :                 break;
     684             : 
     685             :             case RTAboveStrategyNumber:
     686        5090 :                 flag = DatumGetBool(DirectFunctionCall2(box_above, leaf,
     687             :                                                         query));
     688        5090 :                 break;
     689             : 
     690             :             case RTOverAboveStrategyNumber:
     691        9206 :                 flag = DatumGetBool(DirectFunctionCall2(box_overabove, leaf,
     692             :                                                         query));
     693        9206 :                 break;
     694             : 
     695             :             case RTBelowStrategyNumber:
     696        2167 :                 flag = DatumGetBool(DirectFunctionCall2(box_below, leaf,
     697             :                                                         query));
     698        2167 :                 break;
     699             : 
     700             :             case RTOverBelowStrategyNumber:
     701        6156 :                 flag = DatumGetBool(DirectFunctionCall2(box_overbelow, leaf,
     702             :                                                         query));
     703        6156 :                 break;
     704             : 
     705             :             default:
     706           0 :                 elog(ERROR, "unrecognized strategy: %d", strategy);
     707             :         }
     708             : 
     709             :         /* If any check is failed, we have found our answer. */
     710       61893 :         if (!flag)
     711        6755 :             break;
     712             :     }
     713             : 
     714       61893 :     PG_RETURN_BOOL(flag);
     715             : }

Generated by: LCOV version 1.11